Header And Logo

PostgreSQL
| The world's most advanced open source database.

pg_shdepend.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pg_shdepend.c
00004  *    routines to support manipulation of the pg_shdepend relation
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/catalog/pg_shdepend.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include "access/genam.h"
00018 #include "access/heapam.h"
00019 #include "access/htup_details.h"
00020 #include "access/xact.h"
00021 #include "catalog/catalog.h"
00022 #include "catalog/dependency.h"
00023 #include "catalog/indexing.h"
00024 #include "catalog/pg_authid.h"
00025 #include "catalog/pg_collation.h"
00026 #include "catalog/pg_conversion.h"
00027 #include "catalog/pg_database.h"
00028 #include "catalog/pg_default_acl.h"
00029 #include "catalog/pg_event_trigger.h"
00030 #include "catalog/pg_extension.h"
00031 #include "catalog/pg_foreign_data_wrapper.h"
00032 #include "catalog/pg_foreign_server.h"
00033 #include "catalog/pg_language.h"
00034 #include "catalog/pg_largeobject.h"
00035 #include "catalog/pg_largeobject_metadata.h"
00036 #include "catalog/pg_namespace.h"
00037 #include "catalog/pg_operator.h"
00038 #include "catalog/pg_opclass.h"
00039 #include "catalog/pg_opfamily.h"
00040 #include "catalog/pg_proc.h"
00041 #include "catalog/pg_shdepend.h"
00042 #include "catalog/pg_tablespace.h"
00043 #include "catalog/pg_type.h"
00044 #include "commands/alter.h"
00045 #include "commands/dbcommands.h"
00046 #include "commands/collationcmds.h"
00047 #include "commands/conversioncmds.h"
00048 #include "commands/defrem.h"
00049 #include "commands/event_trigger.h"
00050 #include "commands/extension.h"
00051 #include "commands/proclang.h"
00052 #include "commands/schemacmds.h"
00053 #include "commands/tablecmds.h"
00054 #include "commands/typecmds.h"
00055 #include "storage/lmgr.h"
00056 #include "miscadmin.h"
00057 #include "utils/acl.h"
00058 #include "utils/fmgroids.h"
00059 #include "utils/syscache.h"
00060 #include "utils/tqual.h"
00061 
00062 
00063 typedef enum
00064 {
00065     LOCAL_OBJECT,
00066     SHARED_OBJECT,
00067     REMOTE_OBJECT
00068 } objectType;
00069 
00070 static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2);
00071 static Oid  classIdGetDbId(Oid classId);
00072 static void shdepChangeDep(Relation sdepRel,
00073                Oid classid, Oid objid, int32 objsubid,
00074                Oid refclassid, Oid refobjid,
00075                SharedDependencyType deptype);
00076 static void shdepAddDependency(Relation sdepRel,
00077                    Oid classId, Oid objectId, int32 objsubId,
00078                    Oid refclassId, Oid refobjId,
00079                    SharedDependencyType deptype);
00080 static void shdepDropDependency(Relation sdepRel,
00081                     Oid classId, Oid objectId, int32 objsubId,
00082                     bool drop_subobjects,
00083                     Oid refclassId, Oid refobjId,
00084                     SharedDependencyType deptype);
00085 static void storeObjectDescription(StringInfo descs, objectType type,
00086                        ObjectAddress *object,
00087                        SharedDependencyType deptype,
00088                        int count);
00089 static bool isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel);
00090 
00091 
00092 /*
00093  * recordSharedDependencyOn
00094  *
00095  * Record a dependency between 2 objects via their respective ObjectAddresses.
00096  * The first argument is the dependent object, the second the one it
00097  * references (which must be a shared object).
00098  *
00099  * This locks the referenced object and makes sure it still exists.
00100  * Then it creates an entry in pg_shdepend.  The lock is kept until
00101  * the end of the transaction.
00102  *
00103  * Dependencies on pinned objects are not recorded.
00104  */
00105 void
00106 recordSharedDependencyOn(ObjectAddress *depender,
00107                          ObjectAddress *referenced,
00108                          SharedDependencyType deptype)
00109 {
00110     Relation    sdepRel;
00111 
00112     /*
00113      * Objects in pg_shdepend can't have SubIds.
00114      */
00115     Assert(depender->objectSubId == 0);
00116     Assert(referenced->objectSubId == 0);
00117 
00118     /*
00119      * During bootstrap, do nothing since pg_shdepend may not exist yet.
00120      * initdb will fill in appropriate pg_shdepend entries after bootstrap.
00121      */
00122     if (IsBootstrapProcessingMode())
00123         return;
00124 
00125     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
00126 
00127     /* If the referenced object is pinned, do nothing. */
00128     if (!isSharedObjectPinned(referenced->classId, referenced->objectId,
00129                               sdepRel))
00130     {
00131         shdepAddDependency(sdepRel, depender->classId, depender->objectId,
00132                            depender->objectSubId,
00133                            referenced->classId, referenced->objectId,
00134                            deptype);
00135     }
00136 
00137     heap_close(sdepRel, RowExclusiveLock);
00138 }
00139 
00140 /*
00141  * recordDependencyOnOwner
00142  *
00143  * A convenient wrapper of recordSharedDependencyOn -- register the specified
00144  * user as owner of the given object.
00145  *
00146  * Note: it's the caller's responsibility to ensure that there isn't an owner
00147  * entry for the object already.
00148  */
00149 void
00150 recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
00151 {
00152     ObjectAddress myself,
00153                 referenced;
00154 
00155     myself.classId = classId;
00156     myself.objectId = objectId;
00157     myself.objectSubId = 0;
00158 
00159     referenced.classId = AuthIdRelationId;
00160     referenced.objectId = owner;
00161     referenced.objectSubId = 0;
00162 
00163     recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER);
00164 }
00165 
00166 /*
00167  * shdepChangeDep
00168  *
00169  * Update shared dependency records to account for an updated referenced
00170  * object.  This is an internal workhorse for operations such as changing
00171  * an object's owner.
00172  *
00173  * There must be no more than one existing entry for the given dependent
00174  * object and dependency type!  So in practice this can only be used for
00175  * updating SHARED_DEPENDENCY_OWNER entries, which should have that property.
00176  *
00177  * If there is no previous entry, we assume it was referencing a PINned
00178  * object, so we create a new entry.  If the new referenced object is
00179  * PINned, we don't create an entry (and drop the old one, if any).
00180  *
00181  * sdepRel must be the pg_shdepend relation, already opened and suitably
00182  * locked.
00183  */
00184 static void
00185 shdepChangeDep(Relation sdepRel,
00186                Oid classid, Oid objid, int32 objsubid,
00187                Oid refclassid, Oid refobjid,
00188                SharedDependencyType deptype)
00189 {
00190     Oid         dbid = classIdGetDbId(classid);
00191     HeapTuple   oldtup = NULL;
00192     HeapTuple   scantup;
00193     ScanKeyData key[4];
00194     SysScanDesc scan;
00195 
00196     /*
00197      * Make sure the new referenced object doesn't go away while we record the
00198      * dependency.
00199      */
00200     shdepLockAndCheckObject(refclassid, refobjid);
00201 
00202     /*
00203      * Look for a previous entry
00204      */
00205     ScanKeyInit(&key[0],
00206                 Anum_pg_shdepend_dbid,
00207                 BTEqualStrategyNumber, F_OIDEQ,
00208                 ObjectIdGetDatum(dbid));
00209     ScanKeyInit(&key[1],
00210                 Anum_pg_shdepend_classid,
00211                 BTEqualStrategyNumber, F_OIDEQ,
00212                 ObjectIdGetDatum(classid));
00213     ScanKeyInit(&key[2],
00214                 Anum_pg_shdepend_objid,
00215                 BTEqualStrategyNumber, F_OIDEQ,
00216                 ObjectIdGetDatum(objid));
00217     ScanKeyInit(&key[3],
00218                 Anum_pg_shdepend_objsubid,
00219                 BTEqualStrategyNumber, F_INT4EQ,
00220                 Int32GetDatum(objsubid));
00221 
00222     scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
00223                               SnapshotNow, 4, key);
00224 
00225     while ((scantup = systable_getnext(scan)) != NULL)
00226     {
00227         /* Ignore if not of the target dependency type */
00228         if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype)
00229             continue;
00230         /* Caller screwed up if multiple matches */
00231         if (oldtup)
00232             elog(ERROR,
00233                "multiple pg_shdepend entries for object %u/%u/%d deptype %c",
00234                  classid, objid, objsubid, deptype);
00235         oldtup = heap_copytuple(scantup);
00236     }
00237 
00238     systable_endscan(scan);
00239 
00240     if (isSharedObjectPinned(refclassid, refobjid, sdepRel))
00241     {
00242         /* No new entry needed, so just delete existing entry if any */
00243         if (oldtup)
00244             simple_heap_delete(sdepRel, &oldtup->t_self);
00245     }
00246     else if (oldtup)
00247     {
00248         /* Need to update existing entry */
00249         Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup);
00250 
00251         /* Since oldtup is a copy, we can just modify it in-memory */
00252         shForm->refclassid = refclassid;
00253         shForm->refobjid = refobjid;
00254 
00255         simple_heap_update(sdepRel, &oldtup->t_self, oldtup);
00256 
00257         /* keep indexes current */
00258         CatalogUpdateIndexes(sdepRel, oldtup);
00259     }
00260     else
00261     {
00262         /* Need to insert new entry */
00263         Datum       values[Natts_pg_shdepend];
00264         bool        nulls[Natts_pg_shdepend];
00265 
00266         memset(nulls, false, sizeof(nulls));
00267 
00268         values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid);
00269         values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid);
00270         values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid);
00271         values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubid);
00272 
00273         values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid);
00274         values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid);
00275         values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
00276 
00277         /*
00278          * we are reusing oldtup just to avoid declaring a new variable, but
00279          * it's certainly a new tuple
00280          */
00281         oldtup = heap_form_tuple(RelationGetDescr(sdepRel), values, nulls);
00282         simple_heap_insert(sdepRel, oldtup);
00283 
00284         /* keep indexes current */
00285         CatalogUpdateIndexes(sdepRel, oldtup);
00286     }
00287 
00288     if (oldtup)
00289         heap_freetuple(oldtup);
00290 }
00291 
00292 /*
00293  * changeDependencyOnOwner
00294  *
00295  * Update the shared dependencies to account for the new owner.
00296  *
00297  * Note: we don't need an objsubid argument because only whole objects
00298  * have owners.
00299  */
00300 void
00301 changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
00302 {
00303     Relation    sdepRel;
00304 
00305     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
00306 
00307     /* Adjust the SHARED_DEPENDENCY_OWNER entry */
00308     shdepChangeDep(sdepRel,
00309                    classId, objectId, 0,
00310                    AuthIdRelationId, newOwnerId,
00311                    SHARED_DEPENDENCY_OWNER);
00312 
00313     /*----------
00314      * There should never be a SHARED_DEPENDENCY_ACL entry for the owner,
00315      * so get rid of it if there is one.  This can happen if the new owner
00316      * was previously granted some rights to the object.
00317      *
00318      * This step is analogous to aclnewowner's removal of duplicate entries
00319      * in the ACL.  We have to do it to handle this scenario:
00320      *      A grants some rights on an object to B
00321      *      ALTER OWNER changes the object's owner to B
00322      *      ALTER OWNER changes the object's owner to C
00323      * The third step would remove all mention of B from the object's ACL,
00324      * but we'd still have a SHARED_DEPENDENCY_ACL for B if we did not do
00325      * things this way.
00326      *
00327      * The rule against having a SHARED_DEPENDENCY_ACL entry for the owner
00328      * allows us to fix things up in just this one place, without having
00329      * to make the various ALTER OWNER routines each know about it.
00330      *----------
00331      */
00332     shdepDropDependency(sdepRel, classId, objectId, 0, true,
00333                         AuthIdRelationId, newOwnerId,
00334                         SHARED_DEPENDENCY_ACL);
00335 
00336     heap_close(sdepRel, RowExclusiveLock);
00337 }
00338 
00339 /*
00340  * getOidListDiff
00341  *      Helper for updateAclDependencies.
00342  *
00343  * Takes two Oid arrays and removes elements that are common to both arrays,
00344  * leaving just those that are in one input but not the other.
00345  * We assume both arrays have been sorted and de-duped.
00346  */
00347 static void
00348 getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
00349 {
00350     int         in1,
00351                 in2,
00352                 out1,
00353                 out2;
00354 
00355     in1 = in2 = out1 = out2 = 0;
00356     while (in1 < *nlist1 && in2 < *nlist2)
00357     {
00358         if (list1[in1] == list2[in2])
00359         {
00360             /* skip over duplicates */
00361             in1++;
00362             in2++;
00363         }
00364         else if (list1[in1] < list2[in2])
00365         {
00366             /* list1[in1] is not in list2 */
00367             list1[out1++] = list1[in1++];
00368         }
00369         else
00370         {
00371             /* list2[in2] is not in list1 */
00372             list2[out2++] = list2[in2++];
00373         }
00374     }
00375 
00376     /* any remaining list1 entries are not in list2 */
00377     while (in1 < *nlist1)
00378     {
00379         list1[out1++] = list1[in1++];
00380     }
00381 
00382     /* any remaining list2 entries are not in list1 */
00383     while (in2 < *nlist2)
00384     {
00385         list2[out2++] = list2[in2++];
00386     }
00387 
00388     *nlist1 = out1;
00389     *nlist2 = out2;
00390 }
00391 
00392 /*
00393  * updateAclDependencies
00394  *      Update the pg_shdepend info for an object's ACL during GRANT/REVOKE.
00395  *
00396  * classId, objectId, objsubId: identify the object whose ACL this is
00397  * ownerId: role owning the object
00398  * noldmembers, oldmembers: array of roleids appearing in old ACL
00399  * nnewmembers, newmembers: array of roleids appearing in new ACL
00400  *
00401  * We calculate the differences between the new and old lists of roles,
00402  * and then insert or delete from pg_shdepend as appropriate.
00403  *
00404  * Note that we can't just insert all referenced roles blindly during GRANT,
00405  * because we would end up with duplicate registered dependencies.  We could
00406  * check for existence of the tuples before inserting, but that seems to be
00407  * more expensive than what we are doing here.  Likewise we can't just delete
00408  * blindly during REVOKE, because the user may still have other privileges.
00409  * It is also possible that REVOKE actually adds dependencies, due to
00410  * instantiation of a formerly implicit default ACL (although at present,
00411  * all such dependencies should be for the owning role, which we ignore here).
00412  *
00413  * NOTE: Both input arrays must be sorted and de-duped.  (Typically they
00414  * are extracted from an ACL array by aclmembers(), which takes care of
00415  * both requirements.)  The arrays are pfreed before return.
00416  */
00417 void
00418 updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
00419                       Oid ownerId,
00420                       int noldmembers, Oid *oldmembers,
00421                       int nnewmembers, Oid *newmembers)
00422 {
00423     Relation    sdepRel;
00424     int         i;
00425 
00426     /*
00427      * Remove entries that are common to both lists; those represent existing
00428      * dependencies we don't need to change.
00429      *
00430      * OK to overwrite the inputs since we'll pfree them anyway.
00431      */
00432     getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers);
00433 
00434     if (noldmembers > 0 || nnewmembers > 0)
00435     {
00436         sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
00437 
00438         /* Add new dependencies that weren't already present */
00439         for (i = 0; i < nnewmembers; i++)
00440         {
00441             Oid         roleid = newmembers[i];
00442 
00443             /*
00444              * Skip the owner: he has an OWNER shdep entry instead. (This is
00445              * not just a space optimization; it makes ALTER OWNER easier. See
00446              * notes in changeDependencyOnOwner.)
00447              */
00448             if (roleid == ownerId)
00449                 continue;
00450 
00451             /* Skip pinned roles; they don't need dependency entries */
00452             if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
00453                 continue;
00454 
00455             shdepAddDependency(sdepRel, classId, objectId, objsubId,
00456                                AuthIdRelationId, roleid,
00457                                SHARED_DEPENDENCY_ACL);
00458         }
00459 
00460         /* Drop no-longer-used old dependencies */
00461         for (i = 0; i < noldmembers; i++)
00462         {
00463             Oid         roleid = oldmembers[i];
00464 
00465             /* Skip the owner, same as above */
00466             if (roleid == ownerId)
00467                 continue;
00468 
00469             /* Skip pinned roles */
00470             if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
00471                 continue;
00472 
00473             shdepDropDependency(sdepRel, classId, objectId, objsubId,
00474                                 false,  /* exact match on objsubId */
00475                                 AuthIdRelationId, roleid,
00476                                 SHARED_DEPENDENCY_ACL);
00477         }
00478 
00479         heap_close(sdepRel, RowExclusiveLock);
00480     }
00481 
00482     if (oldmembers)
00483         pfree(oldmembers);
00484     if (newmembers)
00485         pfree(newmembers);
00486 }
00487 
00488 /*
00489  * A struct to keep track of dependencies found in other databases.
00490  */
00491 typedef struct
00492 {
00493     Oid         dbOid;
00494     int         count;
00495 } remoteDep;
00496 
00497 /*
00498  * checkSharedDependencies
00499  *
00500  * Check whether there are shared dependency entries for a given shared
00501  * object; return true if so.
00502  *
00503  * In addition, return a string containing a newline-separated list of object
00504  * descriptions that depend on the shared object, or NULL if none is found.
00505  * We actually return two such strings; the "detail" result is suitable for
00506  * returning to the client as an errdetail() string, and is limited in size.
00507  * The "detail_log" string is potentially much longer, and should be emitted
00508  * to the server log only.
00509  *
00510  * We can find three different kinds of dependencies: dependencies on objects
00511  * of the current database; dependencies on shared objects; and dependencies
00512  * on objects local to other databases.  We can (and do) provide descriptions
00513  * of the two former kinds of objects, but we can't do that for "remote"
00514  * objects, so we just provide a count of them.
00515  *
00516  * If we find a SHARED_DEPENDENCY_PIN entry, we can error out early.
00517  */
00518 bool
00519 checkSharedDependencies(Oid classId, Oid objectId,
00520                         char **detail_msg, char **detail_log_msg)
00521 {
00522     Relation    sdepRel;
00523     ScanKeyData key[2];
00524     SysScanDesc scan;
00525     HeapTuple   tup;
00526     int         numReportedDeps = 0;
00527     int         numNotReportedDeps = 0;
00528     int         numNotReportedDbs = 0;
00529     List       *remDeps = NIL;
00530     ListCell   *cell;
00531     ObjectAddress object;
00532     StringInfoData descs;
00533     StringInfoData alldescs;
00534 
00535     /*
00536      * We limit the number of dependencies reported to the client to
00537      * MAX_REPORTED_DEPS, since client software may not deal well with
00538      * enormous error strings.  The server log always gets a full report.
00539      */
00540 #define MAX_REPORTED_DEPS 100
00541 
00542     initStringInfo(&descs);
00543     initStringInfo(&alldescs);
00544 
00545     sdepRel = heap_open(SharedDependRelationId, AccessShareLock);
00546 
00547     ScanKeyInit(&key[0],
00548                 Anum_pg_shdepend_refclassid,
00549                 BTEqualStrategyNumber, F_OIDEQ,
00550                 ObjectIdGetDatum(classId));
00551     ScanKeyInit(&key[1],
00552                 Anum_pg_shdepend_refobjid,
00553                 BTEqualStrategyNumber, F_OIDEQ,
00554                 ObjectIdGetDatum(objectId));
00555 
00556     scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
00557                               SnapshotNow, 2, key);
00558 
00559     while (HeapTupleIsValid(tup = systable_getnext(scan)))
00560     {
00561         Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
00562 
00563         /* This case can be dispatched quickly */
00564         if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
00565         {
00566             object.classId = classId;
00567             object.objectId = objectId;
00568             object.objectSubId = 0;
00569             ereport(ERROR,
00570                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
00571                      errmsg("cannot drop %s because it is required by the database system",
00572                             getObjectDescription(&object))));
00573         }
00574 
00575         object.classId = sdepForm->classid;
00576         object.objectId = sdepForm->objid;
00577         object.objectSubId = sdepForm->objsubid;
00578 
00579         /*
00580          * If it's a dependency local to this database or it's a shared
00581          * object, describe it.
00582          *
00583          * If it's a remote dependency, keep track of it so we can report the
00584          * number of them later.
00585          */
00586         if (sdepForm->dbid == MyDatabaseId)
00587         {
00588             if (numReportedDeps < MAX_REPORTED_DEPS)
00589             {
00590                 numReportedDeps++;
00591                 storeObjectDescription(&descs, LOCAL_OBJECT, &object,
00592                                        sdepForm->deptype, 0);
00593             }
00594             else
00595                 numNotReportedDeps++;
00596             storeObjectDescription(&alldescs, LOCAL_OBJECT, &object,
00597                                    sdepForm->deptype, 0);
00598         }
00599         else if (sdepForm->dbid == InvalidOid)
00600         {
00601             if (numReportedDeps < MAX_REPORTED_DEPS)
00602             {
00603                 numReportedDeps++;
00604                 storeObjectDescription(&descs, SHARED_OBJECT, &object,
00605                                        sdepForm->deptype, 0);
00606             }
00607             else
00608                 numNotReportedDeps++;
00609             storeObjectDescription(&alldescs, SHARED_OBJECT, &object,
00610                                    sdepForm->deptype, 0);
00611         }
00612         else
00613         {
00614             /* It's not local nor shared, so it must be remote. */
00615             remoteDep  *dep;
00616             bool        stored = false;
00617 
00618             /*
00619              * XXX this info is kept on a simple List.  Maybe it's not good
00620              * for performance, but using a hash table seems needlessly
00621              * complex.  The expected number of databases is not high anyway,
00622              * I suppose.
00623              */
00624             foreach(cell, remDeps)
00625             {
00626                 dep = lfirst(cell);
00627                 if (dep->dbOid == sdepForm->dbid)
00628                 {
00629                     dep->count++;
00630                     stored = true;
00631                     break;
00632                 }
00633             }
00634             if (!stored)
00635             {
00636                 dep = (remoteDep *) palloc(sizeof(remoteDep));
00637                 dep->dbOid = sdepForm->dbid;
00638                 dep->count = 1;
00639                 remDeps = lappend(remDeps, dep);
00640             }
00641         }
00642     }
00643 
00644     systable_endscan(scan);
00645 
00646     heap_close(sdepRel, AccessShareLock);
00647 
00648     /*
00649      * Summarize dependencies in remote databases.
00650      */
00651     foreach(cell, remDeps)
00652     {
00653         remoteDep  *dep = lfirst(cell);
00654 
00655         object.classId = DatabaseRelationId;
00656         object.objectId = dep->dbOid;
00657         object.objectSubId = 0;
00658 
00659         if (numReportedDeps < MAX_REPORTED_DEPS)
00660         {
00661             numReportedDeps++;
00662             storeObjectDescription(&descs, REMOTE_OBJECT, &object,
00663                                    SHARED_DEPENDENCY_INVALID, dep->count);
00664         }
00665         else
00666             numNotReportedDbs++;
00667         storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
00668                                SHARED_DEPENDENCY_INVALID, dep->count);
00669     }
00670 
00671     list_free_deep(remDeps);
00672 
00673     if (descs.len == 0)
00674     {
00675         pfree(descs.data);
00676         pfree(alldescs.data);
00677         *detail_msg = *detail_log_msg = NULL;
00678         return false;
00679     }
00680 
00681     if (numNotReportedDeps > 0)
00682         appendStringInfo(&descs, ngettext("\nand %d other object "
00683                                           "(see server log for list)",
00684                                           "\nand %d other objects "
00685                                           "(see server log for list)",
00686                                           numNotReportedDeps),
00687                          numNotReportedDeps);
00688     if (numNotReportedDbs > 0)
00689         appendStringInfo(&descs, ngettext("\nand objects in %d other database "
00690                                           "(see server log for list)",
00691                                        "\nand objects in %d other databases "
00692                                           "(see server log for list)",
00693                                           numNotReportedDbs),
00694                          numNotReportedDbs);
00695 
00696     *detail_msg = descs.data;
00697     *detail_log_msg = alldescs.data;
00698     return true;
00699 }
00700 
00701 /*
00702  * copyTemplateDependencies
00703  *
00704  * Routine to create the initial shared dependencies of a new database.
00705  * We simply copy the dependencies from the template database.
00706  */
00707 void
00708 copyTemplateDependencies(Oid templateDbId, Oid newDbId)
00709 {
00710     Relation    sdepRel;
00711     TupleDesc   sdepDesc;
00712     ScanKeyData key[1];
00713     SysScanDesc scan;
00714     HeapTuple   tup;
00715     CatalogIndexState indstate;
00716     Datum       values[Natts_pg_shdepend];
00717     bool        nulls[Natts_pg_shdepend];
00718     bool        replace[Natts_pg_shdepend];
00719 
00720     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
00721     sdepDesc = RelationGetDescr(sdepRel);
00722 
00723     indstate = CatalogOpenIndexes(sdepRel);
00724 
00725     /* Scan all entries with dbid = templateDbId */
00726     ScanKeyInit(&key[0],
00727                 Anum_pg_shdepend_dbid,
00728                 BTEqualStrategyNumber, F_OIDEQ,
00729                 ObjectIdGetDatum(templateDbId));
00730 
00731     scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
00732                               SnapshotNow, 1, key);
00733 
00734     /* Set up to copy the tuples except for inserting newDbId */
00735     memset(values, 0, sizeof(values));
00736     memset(nulls, false, sizeof(nulls));
00737     memset(replace, false, sizeof(replace));
00738 
00739     replace[Anum_pg_shdepend_dbid - 1] = true;
00740     values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);
00741 
00742     /*
00743      * Copy the entries of the original database, changing the database Id to
00744      * that of the new database.  Note that because we are not copying rows
00745      * with dbId == 0 (ie, rows describing dependent shared objects) we won't
00746      * copy the ownership dependency of the template database itself; this is
00747      * what we want.
00748      */
00749     while (HeapTupleIsValid(tup = systable_getnext(scan)))
00750     {
00751         HeapTuple   newtup;
00752 
00753         newtup = heap_modify_tuple(tup, sdepDesc, values, nulls, replace);
00754         simple_heap_insert(sdepRel, newtup);
00755 
00756         /* Keep indexes current */
00757         CatalogIndexInsert(indstate, newtup);
00758 
00759         heap_freetuple(newtup);
00760     }
00761 
00762     systable_endscan(scan);
00763 
00764     CatalogCloseIndexes(indstate);
00765     heap_close(sdepRel, RowExclusiveLock);
00766 }
00767 
00768 /*
00769  * dropDatabaseDependencies
00770  *
00771  * Delete pg_shdepend entries corresponding to a database that's being
00772  * dropped.
00773  */
00774 void
00775 dropDatabaseDependencies(Oid databaseId)
00776 {
00777     Relation    sdepRel;
00778     ScanKeyData key[1];
00779     SysScanDesc scan;
00780     HeapTuple   tup;
00781 
00782     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
00783 
00784     /*
00785      * First, delete all the entries that have the database Oid in the dbid
00786      * field.
00787      */
00788     ScanKeyInit(&key[0],
00789                 Anum_pg_shdepend_dbid,
00790                 BTEqualStrategyNumber, F_OIDEQ,
00791                 ObjectIdGetDatum(databaseId));
00792     /* We leave the other index fields unspecified */
00793 
00794     scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
00795                               SnapshotNow, 1, key);
00796 
00797     while (HeapTupleIsValid(tup = systable_getnext(scan)))
00798     {
00799         simple_heap_delete(sdepRel, &tup->t_self);
00800     }
00801 
00802     systable_endscan(scan);
00803 
00804     /* Now delete all entries corresponding to the database itself */
00805     shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true,
00806                         InvalidOid, InvalidOid,
00807                         SHARED_DEPENDENCY_INVALID);
00808 
00809     heap_close(sdepRel, RowExclusiveLock);
00810 }
00811 
00812 /*
00813  * deleteSharedDependencyRecordsFor
00814  *
00815  * Delete all pg_shdepend entries corresponding to an object that's being
00816  * dropped or modified.  The object is assumed to be either a shared object
00817  * or local to the current database (the classId tells us which).
00818  *
00819  * If objectSubId is zero, we are deleting a whole object, so get rid of
00820  * pg_shdepend entries for subobjects as well.
00821  */
00822 void
00823 deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
00824 {
00825     Relation    sdepRel;
00826 
00827     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
00828 
00829     shdepDropDependency(sdepRel, classId, objectId, objectSubId,
00830                         (objectSubId == 0),
00831                         InvalidOid, InvalidOid,
00832                         SHARED_DEPENDENCY_INVALID);
00833 
00834     heap_close(sdepRel, RowExclusiveLock);
00835 }
00836 
00837 /*
00838  * shdepAddDependency
00839  *      Internal workhorse for inserting into pg_shdepend
00840  *
00841  * sdepRel must be the pg_shdepend relation, already opened and suitably
00842  * locked.
00843  */
00844 static void
00845 shdepAddDependency(Relation sdepRel,
00846                    Oid classId, Oid objectId, int32 objsubId,
00847                    Oid refclassId, Oid refobjId,
00848                    SharedDependencyType deptype)
00849 {
00850     HeapTuple   tup;
00851     Datum       values[Natts_pg_shdepend];
00852     bool        nulls[Natts_pg_shdepend];
00853 
00854     /*
00855      * Make sure the object doesn't go away while we record the dependency on
00856      * it.  DROP routines should lock the object exclusively before they check
00857      * shared dependencies.
00858      */
00859     shdepLockAndCheckObject(refclassId, refobjId);
00860 
00861     memset(nulls, false, sizeof(nulls));
00862 
00863     /*
00864      * Form the new tuple and record the dependency.
00865      */
00866     values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
00867     values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
00868     values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
00869     values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId);
00870 
00871     values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
00872     values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
00873     values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
00874 
00875     tup = heap_form_tuple(sdepRel->rd_att, values, nulls);
00876 
00877     simple_heap_insert(sdepRel, tup);
00878 
00879     /* keep indexes current */
00880     CatalogUpdateIndexes(sdepRel, tup);
00881 
00882     /* clean up */
00883     heap_freetuple(tup);
00884 }
00885 
00886 /*
00887  * shdepDropDependency
00888  *      Internal workhorse for deleting entries from pg_shdepend.
00889  *
00890  * We drop entries having the following properties:
00891  *  dependent object is the one identified by classId/objectId/objsubId
00892  *  if refclassId isn't InvalidOid, it must match the entry's refclassid
00893  *  if refobjId isn't InvalidOid, it must match the entry's refobjid
00894  *  if deptype isn't SHARED_DEPENDENCY_INVALID, it must match entry's deptype
00895  *
00896  * If drop_subobjects is true, we ignore objsubId and consider all entries
00897  * matching classId/objectId.
00898  *
00899  * sdepRel must be the pg_shdepend relation, already opened and suitably
00900  * locked.
00901  */
00902 static void
00903 shdepDropDependency(Relation sdepRel,
00904                     Oid classId, Oid objectId, int32 objsubId,
00905                     bool drop_subobjects,
00906                     Oid refclassId, Oid refobjId,
00907                     SharedDependencyType deptype)
00908 {
00909     ScanKeyData key[4];
00910     int         nkeys;
00911     SysScanDesc scan;
00912     HeapTuple   tup;
00913 
00914     /* Scan for entries matching the dependent object */
00915     ScanKeyInit(&key[0],
00916                 Anum_pg_shdepend_dbid,
00917                 BTEqualStrategyNumber, F_OIDEQ,
00918                 ObjectIdGetDatum(classIdGetDbId(classId)));
00919     ScanKeyInit(&key[1],
00920                 Anum_pg_shdepend_classid,
00921                 BTEqualStrategyNumber, F_OIDEQ,
00922                 ObjectIdGetDatum(classId));
00923     ScanKeyInit(&key[2],
00924                 Anum_pg_shdepend_objid,
00925                 BTEqualStrategyNumber, F_OIDEQ,
00926                 ObjectIdGetDatum(objectId));
00927     if (drop_subobjects)
00928         nkeys = 3;
00929     else
00930     {
00931         ScanKeyInit(&key[3],
00932                     Anum_pg_shdepend_objsubid,
00933                     BTEqualStrategyNumber, F_INT4EQ,
00934                     Int32GetDatum(objsubId));
00935         nkeys = 4;
00936     }
00937 
00938     scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
00939                               SnapshotNow, nkeys, key);
00940 
00941     while (HeapTupleIsValid(tup = systable_getnext(scan)))
00942     {
00943         Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
00944 
00945         /* Filter entries according to additional parameters */
00946         if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId)
00947             continue;
00948         if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId)
00949             continue;
00950         if (deptype != SHARED_DEPENDENCY_INVALID &&
00951             shdepForm->deptype != deptype)
00952             continue;
00953 
00954         /* OK, delete it */
00955         simple_heap_delete(sdepRel, &tup->t_self);
00956     }
00957 
00958     systable_endscan(scan);
00959 }
00960 
00961 /*
00962  * classIdGetDbId
00963  *
00964  * Get the database Id that should be used in pg_shdepend, given the OID
00965  * of the catalog containing the object.  For shared objects, it's 0
00966  * (InvalidOid); for all other objects, it's the current database Id.
00967  */
00968 static Oid
00969 classIdGetDbId(Oid classId)
00970 {
00971     Oid         dbId;
00972 
00973     if (IsSharedRelation(classId))
00974         dbId = InvalidOid;
00975     else
00976         dbId = MyDatabaseId;
00977 
00978     return dbId;
00979 }
00980 
00981 /*
00982  * shdepLockAndCheckObject
00983  *
00984  * Lock the object that we are about to record a dependency on.
00985  * After it's locked, verify that it hasn't been dropped while we
00986  * weren't looking.  If the object has been dropped, this function
00987  * does not return!
00988  */
00989 void
00990 shdepLockAndCheckObject(Oid classId, Oid objectId)
00991 {
00992     /* AccessShareLock should be OK, since we are not modifying the object */
00993     LockSharedObject(classId, objectId, 0, AccessShareLock);
00994 
00995     switch (classId)
00996     {
00997         case AuthIdRelationId:
00998             if (!SearchSysCacheExists1(AUTHOID, ObjectIdGetDatum(objectId)))
00999                 ereport(ERROR,
01000                         (errcode(ERRCODE_UNDEFINED_OBJECT),
01001                          errmsg("role %u was concurrently dropped",
01002                                 objectId)));
01003             break;
01004 
01005             /*
01006              * Currently, this routine need not support any other shared
01007              * object types besides roles.  If we wanted to record explicit
01008              * dependencies on databases or tablespaces, we'd need code along
01009              * these lines:
01010              */
01011 #ifdef NOT_USED
01012         case TableSpaceRelationId:
01013             {
01014                 /* For lack of a syscache on pg_tablespace, do this: */
01015                 char       *tablespace = get_tablespace_name(objectId);
01016 
01017                 if (tablespace == NULL)
01018                     ereport(ERROR,
01019                             (errcode(ERRCODE_UNDEFINED_OBJECT),
01020                              errmsg("tablespace %u was concurrently dropped",
01021                                     objectId)));
01022                 pfree(tablespace);
01023                 break;
01024             }
01025 #endif
01026 
01027         case DatabaseRelationId:
01028             {
01029                 /* For lack of a syscache on pg_database, do this: */
01030                 char       *database = get_database_name(objectId);
01031 
01032                 if (database == NULL)
01033                     ereport(ERROR,
01034                             (errcode(ERRCODE_UNDEFINED_OBJECT),
01035                              errmsg("database %u was concurrently dropped",
01036                                     objectId)));
01037                 pfree(database);
01038                 break;
01039             }
01040 
01041 
01042         default:
01043             elog(ERROR, "unrecognized shared classId: %u", classId);
01044     }
01045 }
01046 
01047 
01048 /*
01049  * storeObjectDescription
01050  *      Append the description of a dependent object to "descs"
01051  *
01052  * While searching for dependencies of a shared object, we stash the
01053  * descriptions of dependent objects we find in a single string, which we
01054  * later pass to ereport() in the DETAIL field when somebody attempts to
01055  * drop a referenced shared object.
01056  *
01057  * When type is LOCAL_OBJECT or SHARED_OBJECT, we expect object to be the
01058  * dependent object, deptype is the dependency type, and count is not used.
01059  * When type is REMOTE_OBJECT, we expect object to be the database object,
01060  * and count to be nonzero; deptype is not used in this case.
01061  */
01062 static void
01063 storeObjectDescription(StringInfo descs, objectType type,
01064                        ObjectAddress *object,
01065                        SharedDependencyType deptype,
01066                        int count)
01067 {
01068     char       *objdesc = getObjectDescription(object);
01069 
01070     /* separate entries with a newline */
01071     if (descs->len != 0)
01072         appendStringInfoChar(descs, '\n');
01073 
01074     switch (type)
01075     {
01076         case LOCAL_OBJECT:
01077         case SHARED_OBJECT:
01078             if (deptype == SHARED_DEPENDENCY_OWNER)
01079                 appendStringInfo(descs, _("owner of %s"), objdesc);
01080             else if (deptype == SHARED_DEPENDENCY_ACL)
01081                 appendStringInfo(descs, _("privileges for %s"), objdesc);
01082             else
01083                 elog(ERROR, "unrecognized dependency type: %d",
01084                      (int) deptype);
01085             break;
01086 
01087         case REMOTE_OBJECT:
01088             /* translator: %s will always be "database %s" */
01089             appendStringInfo(descs, ngettext("%d object in %s",
01090                                              "%d objects in %s",
01091                                              count),
01092                              count, objdesc);
01093             break;
01094 
01095         default:
01096             elog(ERROR, "unrecognized object type: %d", type);
01097     }
01098 
01099     pfree(objdesc);
01100 }
01101 
01102 
01103 /*
01104  * isSharedObjectPinned
01105  *      Return whether a given shared object has a SHARED_DEPENDENCY_PIN entry.
01106  *
01107  * sdepRel must be the pg_shdepend relation, already opened and suitably
01108  * locked.
01109  */
01110 static bool
01111 isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
01112 {
01113     bool        result = false;
01114     ScanKeyData key[2];
01115     SysScanDesc scan;
01116     HeapTuple   tup;
01117 
01118     ScanKeyInit(&key[0],
01119                 Anum_pg_shdepend_refclassid,
01120                 BTEqualStrategyNumber, F_OIDEQ,
01121                 ObjectIdGetDatum(classId));
01122     ScanKeyInit(&key[1],
01123                 Anum_pg_shdepend_refobjid,
01124                 BTEqualStrategyNumber, F_OIDEQ,
01125                 ObjectIdGetDatum(objectId));
01126 
01127     scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
01128                               SnapshotNow, 2, key);
01129 
01130     /*
01131      * Since we won't generate additional pg_shdepend entries for pinned
01132      * objects, there can be at most one entry referencing a pinned object.
01133      * Hence, it's sufficient to look at the first returned tuple; we don't
01134      * need to loop.
01135      */
01136     tup = systable_getnext(scan);
01137     if (HeapTupleIsValid(tup))
01138     {
01139         Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
01140 
01141         if (shdepForm->deptype == SHARED_DEPENDENCY_PIN)
01142             result = true;
01143     }
01144 
01145     systable_endscan(scan);
01146 
01147     return result;
01148 }
01149 
01150 /*
01151  * shdepDropOwned
01152  *
01153  * Drop the objects owned by any one of the given RoleIds.  If a role has
01154  * access to an object, the grant will be removed as well (but the object
01155  * will not, of course).
01156  *
01157  * We can revoke grants immediately while doing the scan, but drops are
01158  * saved up and done all at once with performMultipleDeletions.  This
01159  * is necessary so that we don't get failures from trying to delete
01160  * interdependent objects in the wrong order.
01161  */
01162 void
01163 shdepDropOwned(List *roleids, DropBehavior behavior)
01164 {
01165     Relation    sdepRel;
01166     ListCell   *cell;
01167     ObjectAddresses *deleteobjs;
01168 
01169     deleteobjs = new_object_addresses();
01170 
01171     /*
01172      * We don't need this strong a lock here, but we'll call routines that
01173      * acquire RowExclusiveLock.  Better get that right now to avoid potential
01174      * deadlock failures.
01175      */
01176     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
01177 
01178     /*
01179      * For each role, find the dependent objects and drop them using the
01180      * regular (non-shared) dependency management.
01181      */
01182     foreach(cell, roleids)
01183     {
01184         Oid         roleid = lfirst_oid(cell);
01185         ScanKeyData key[2];
01186         SysScanDesc scan;
01187         HeapTuple   tuple;
01188 
01189         /* Doesn't work for pinned objects */
01190         if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
01191         {
01192             ObjectAddress obj;
01193 
01194             obj.classId = AuthIdRelationId;
01195             obj.objectId = roleid;
01196             obj.objectSubId = 0;
01197 
01198             ereport(ERROR,
01199                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
01200                    errmsg("cannot drop objects owned by %s because they are "
01201                           "required by the database system",
01202                           getObjectDescription(&obj))));
01203         }
01204 
01205         ScanKeyInit(&key[0],
01206                     Anum_pg_shdepend_refclassid,
01207                     BTEqualStrategyNumber, F_OIDEQ,
01208                     ObjectIdGetDatum(AuthIdRelationId));
01209         ScanKeyInit(&key[1],
01210                     Anum_pg_shdepend_refobjid,
01211                     BTEqualStrategyNumber, F_OIDEQ,
01212                     ObjectIdGetDatum(roleid));
01213 
01214         scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
01215                                   SnapshotNow, 2, key);
01216 
01217         while ((tuple = systable_getnext(scan)) != NULL)
01218         {
01219             Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
01220             ObjectAddress obj;
01221 
01222             /*
01223              * We only operate on shared objects and objects in the current
01224              * database
01225              */
01226             if (sdepForm->dbid != MyDatabaseId &&
01227                 sdepForm->dbid != InvalidOid)
01228                 continue;
01229 
01230             switch (sdepForm->deptype)
01231             {
01232                     /* Shouldn't happen */
01233                 case SHARED_DEPENDENCY_PIN:
01234                 case SHARED_DEPENDENCY_INVALID:
01235                     elog(ERROR, "unexpected dependency type");
01236                     break;
01237                 case SHARED_DEPENDENCY_ACL:
01238                     RemoveRoleFromObjectACL(roleid,
01239                                             sdepForm->classid,
01240                                             sdepForm->objid);
01241                     break;
01242                 case SHARED_DEPENDENCY_OWNER:
01243                     /* If a local object, save it for deletion below */
01244                     if (sdepForm->dbid == MyDatabaseId)
01245                     {
01246                         obj.classId = sdepForm->classid;
01247                         obj.objectId = sdepForm->objid;
01248                         obj.objectSubId = sdepForm->objsubid;
01249                         add_exact_object_address(&obj, deleteobjs);
01250                     }
01251                     break;
01252             }
01253         }
01254 
01255         systable_endscan(scan);
01256     }
01257 
01258     /* the dependency mechanism does the actual work */
01259     performMultipleDeletions(deleteobjs, behavior, 0);
01260 
01261     heap_close(sdepRel, RowExclusiveLock);
01262 
01263     free_object_addresses(deleteobjs);
01264 }
01265 
01266 /*
01267  * shdepReassignOwned
01268  *
01269  * Change the owner of objects owned by any of the roles in roleids to
01270  * newrole.  Grants are not touched.
01271  */
01272 void
01273 shdepReassignOwned(List *roleids, Oid newrole)
01274 {
01275     Relation    sdepRel;
01276     ListCell   *cell;
01277 
01278     /*
01279      * We don't need this strong a lock here, but we'll call routines that
01280      * acquire RowExclusiveLock.  Better get that right now to avoid potential
01281      * deadlock problems.
01282      */
01283     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
01284 
01285     foreach(cell, roleids)
01286     {
01287         SysScanDesc scan;
01288         ScanKeyData key[2];
01289         HeapTuple   tuple;
01290         Oid         roleid = lfirst_oid(cell);
01291 
01292         /* Refuse to work on pinned roles */
01293         if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
01294         {
01295             ObjectAddress obj;
01296 
01297             obj.classId = AuthIdRelationId;
01298             obj.objectId = roleid;
01299             obj.objectSubId = 0;
01300 
01301             ereport(ERROR,
01302                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
01303                      errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system",
01304                             getObjectDescription(&obj))));
01305 
01306             /*
01307              * There's no need to tell the whole truth, which is that we
01308              * didn't track these dependencies at all ...
01309              */
01310         }
01311 
01312         ScanKeyInit(&key[0],
01313                     Anum_pg_shdepend_refclassid,
01314                     BTEqualStrategyNumber, F_OIDEQ,
01315                     ObjectIdGetDatum(AuthIdRelationId));
01316         ScanKeyInit(&key[1],
01317                     Anum_pg_shdepend_refobjid,
01318                     BTEqualStrategyNumber, F_OIDEQ,
01319                     ObjectIdGetDatum(roleid));
01320 
01321         scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
01322                                   SnapshotNow, 2, key);
01323 
01324         while ((tuple = systable_getnext(scan)) != NULL)
01325         {
01326             Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
01327 
01328             /*
01329              * We only operate on shared objects and objects in the current
01330              * database
01331              */
01332             if (sdepForm->dbid != MyDatabaseId &&
01333                 sdepForm->dbid != InvalidOid)
01334                 continue;
01335 
01336             /* Unexpected because we checked for pins above */
01337             if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
01338                 elog(ERROR, "unexpected shared pin");
01339 
01340             /* We leave non-owner dependencies alone */
01341             if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER)
01342                 continue;
01343 
01344             /* Issue the appropriate ALTER OWNER call */
01345             switch (sdepForm->classid)
01346             {
01347                 case TypeRelationId:
01348                     AlterTypeOwnerInternal(sdepForm->objid, newrole, true);
01349                     break;
01350 
01351                 case NamespaceRelationId:
01352                     AlterSchemaOwner_oid(sdepForm->objid, newrole);
01353                     break;
01354 
01355                 case RelationRelationId:
01356 
01357                     /*
01358                      * Pass recursing = true so that we don't fail on indexes,
01359                      * owned sequences, etc when we happen to visit them
01360                      * before their parent table.
01361                      */
01362                     ATExecChangeOwner(sdepForm->objid, newrole, true, AccessExclusiveLock);
01363                     break;
01364 
01365                 case DefaultAclRelationId:
01366 
01367                     /*
01368                      * Ignore default ACLs; they should be handled by DROP
01369                      * OWNED, not REASSIGN OWNED.
01370                      */
01371                     break;
01372 
01373                 case ForeignServerRelationId:
01374                     AlterForeignServerOwner_oid(sdepForm->objid, newrole);
01375                     break;
01376 
01377                 case ForeignDataWrapperRelationId:
01378                     AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole);
01379                     break;
01380 
01381                 case EventTriggerRelationId:
01382                     AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
01383                     break;
01384 
01385                 /* Generic alter owner cases */
01386                 case CollationRelationId:
01387                 case ConversionRelationId:
01388                 case OperatorRelationId:
01389                 case ProcedureRelationId:
01390                 case LanguageRelationId:
01391                 case LargeObjectRelationId:
01392                 case OperatorFamilyRelationId:
01393                 case OperatorClassRelationId:
01394                 case ExtensionRelationId:
01395                 case TableSpaceRelationId:
01396                 case DatabaseRelationId:
01397                     {
01398                         Oid         classId = sdepForm->classid;
01399                         Relation    catalog;
01400 
01401                         if (classId == LargeObjectRelationId)
01402                             classId = LargeObjectMetadataRelationId;
01403 
01404                         catalog = heap_open(classId, RowExclusiveLock);
01405 
01406                         AlterObjectOwner_internal(catalog, sdepForm->objid,
01407                                                   newrole);
01408 
01409                         heap_close(catalog, NoLock);
01410                     }
01411                     break;
01412 
01413                 default:
01414                     elog(ERROR, "unexpected classid %u", sdepForm->classid);
01415                     break;
01416             }
01417             /* Make sure the next iteration will see my changes */
01418             CommandCounterIncrement();
01419         }
01420 
01421         systable_endscan(scan);
01422     }
01423 
01424     heap_close(sdepRel, RowExclusiveLock);
01425 }