LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_shdepend.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 306 383 79.9 %
Date: 2017-09-29 13:40:31 Functions: 17 18 94.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_shdepend.c
       4             :  *    routines to support manipulation of the pg_shdepend relation
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/catalog/pg_shdepend.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "access/genam.h"
      18             : #include "access/heapam.h"
      19             : #include "access/htup_details.h"
      20             : #include "access/xact.h"
      21             : #include "catalog/catalog.h"
      22             : #include "catalog/dependency.h"
      23             : #include "catalog/indexing.h"
      24             : #include "catalog/pg_authid.h"
      25             : #include "catalog/pg_collation.h"
      26             : #include "catalog/pg_conversion.h"
      27             : #include "catalog/pg_database.h"
      28             : #include "catalog/pg_default_acl.h"
      29             : #include "catalog/pg_event_trigger.h"
      30             : #include "catalog/pg_extension.h"
      31             : #include "catalog/pg_foreign_data_wrapper.h"
      32             : #include "catalog/pg_foreign_server.h"
      33             : #include "catalog/pg_language.h"
      34             : #include "catalog/pg_largeobject.h"
      35             : #include "catalog/pg_largeobject_metadata.h"
      36             : #include "catalog/pg_namespace.h"
      37             : #include "catalog/pg_operator.h"
      38             : #include "catalog/pg_opclass.h"
      39             : #include "catalog/pg_opfamily.h"
      40             : #include "catalog/pg_proc.h"
      41             : #include "catalog/pg_shdepend.h"
      42             : #include "catalog/pg_statistic_ext.h"
      43             : #include "catalog/pg_subscription.h"
      44             : #include "catalog/pg_tablespace.h"
      45             : #include "catalog/pg_ts_config.h"
      46             : #include "catalog/pg_ts_dict.h"
      47             : #include "catalog/pg_type.h"
      48             : #include "catalog/pg_user_mapping.h"
      49             : #include "commands/alter.h"
      50             : #include "commands/dbcommands.h"
      51             : #include "commands/collationcmds.h"
      52             : #include "commands/conversioncmds.h"
      53             : #include "commands/defrem.h"
      54             : #include "commands/event_trigger.h"
      55             : #include "commands/extension.h"
      56             : #include "commands/policy.h"
      57             : #include "commands/proclang.h"
      58             : #include "commands/publicationcmds.h"
      59             : #include "commands/schemacmds.h"
      60             : #include "commands/subscriptioncmds.h"
      61             : #include "commands/tablecmds.h"
      62             : #include "commands/typecmds.h"
      63             : #include "storage/lmgr.h"
      64             : #include "miscadmin.h"
      65             : #include "utils/acl.h"
      66             : #include "utils/fmgroids.h"
      67             : #include "utils/syscache.h"
      68             : #include "utils/tqual.h"
      69             : 
      70             : 
      71             : typedef enum
      72             : {
      73             :     LOCAL_OBJECT,
      74             :     SHARED_OBJECT,
      75             :     REMOTE_OBJECT
      76             : } SharedDependencyObjectType;
      77             : 
      78             : static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2);
      79             : static Oid  classIdGetDbId(Oid classId);
      80             : static void shdepChangeDep(Relation sdepRel,
      81             :                Oid classid, Oid objid, int32 objsubid,
      82             :                Oid refclassid, Oid refobjid,
      83             :                SharedDependencyType deptype);
      84             : static void shdepAddDependency(Relation sdepRel,
      85             :                    Oid classId, Oid objectId, int32 objsubId,
      86             :                    Oid refclassId, Oid refobjId,
      87             :                    SharedDependencyType deptype);
      88             : static void shdepDropDependency(Relation sdepRel,
      89             :                     Oid classId, Oid objectId, int32 objsubId,
      90             :                     bool drop_subobjects,
      91             :                     Oid refclassId, Oid refobjId,
      92             :                     SharedDependencyType deptype);
      93             : static void storeObjectDescription(StringInfo descs,
      94             :                        SharedDependencyObjectType type,
      95             :                        ObjectAddress *object,
      96             :                        SharedDependencyType deptype,
      97             :                        int count);
      98             : static bool isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel);
      99             : 
     100             : 
     101             : /*
     102             :  * recordSharedDependencyOn
     103             :  *
     104             :  * Record a dependency between 2 objects via their respective ObjectAddresses.
     105             :  * The first argument is the dependent object, the second the one it
     106             :  * references (which must be a shared object).
     107             :  *
     108             :  * This locks the referenced object and makes sure it still exists.
     109             :  * Then it creates an entry in pg_shdepend.  The lock is kept until
     110             :  * the end of the transaction.
     111             :  *
     112             :  * Dependencies on pinned objects are not recorded.
     113             :  */
     114             : void
     115        3632 : recordSharedDependencyOn(ObjectAddress *depender,
     116             :                          ObjectAddress *referenced,
     117             :                          SharedDependencyType deptype)
     118             : {
     119             :     Relation    sdepRel;
     120             : 
     121             :     /*
     122             :      * Objects in pg_shdepend can't have SubIds.
     123             :      */
     124        3632 :     Assert(depender->objectSubId == 0);
     125        3632 :     Assert(referenced->objectSubId == 0);
     126             : 
     127             :     /*
     128             :      * During bootstrap, do nothing since pg_shdepend may not exist yet.
     129             :      * initdb will fill in appropriate pg_shdepend entries after bootstrap.
     130             :      */
     131        3632 :     if (IsBootstrapProcessingMode())
     132        3632 :         return;
     133             : 
     134        3632 :     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
     135             : 
     136             :     /* If the referenced object is pinned, do nothing. */
     137        3632 :     if (!isSharedObjectPinned(referenced->classId, referenced->objectId,
     138             :                               sdepRel))
     139             :     {
     140         351 :         shdepAddDependency(sdepRel, depender->classId, depender->objectId,
     141             :                            depender->objectSubId,
     142             :                            referenced->classId, referenced->objectId,
     143             :                            deptype);
     144             :     }
     145             : 
     146        3632 :     heap_close(sdepRel, RowExclusiveLock);
     147             : }
     148             : 
     149             : /*
     150             :  * recordDependencyOnOwner
     151             :  *
     152             :  * A convenient wrapper of recordSharedDependencyOn -- register the specified
     153             :  * user as owner of the given object.
     154             :  *
     155             :  * Note: it's the caller's responsibility to ensure that there isn't an owner
     156             :  * entry for the object already.
     157             :  */
     158             : void
     159        3610 : recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
     160             : {
     161             :     ObjectAddress myself,
     162             :                 referenced;
     163             : 
     164        3610 :     myself.classId = classId;
     165        3610 :     myself.objectId = objectId;
     166        3610 :     myself.objectSubId = 0;
     167             : 
     168        3610 :     referenced.classId = AuthIdRelationId;
     169        3610 :     referenced.objectId = owner;
     170        3610 :     referenced.objectSubId = 0;
     171             : 
     172        3610 :     recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER);
     173        3610 : }
     174             : 
     175             : /*
     176             :  * shdepChangeDep
     177             :  *
     178             :  * Update shared dependency records to account for an updated referenced
     179             :  * object.  This is an internal workhorse for operations such as changing
     180             :  * an object's owner.
     181             :  *
     182             :  * There must be no more than one existing entry for the given dependent
     183             :  * object and dependency type!  So in practice this can only be used for
     184             :  * updating SHARED_DEPENDENCY_OWNER entries, which should have that property.
     185             :  *
     186             :  * If there is no previous entry, we assume it was referencing a PINned
     187             :  * object, so we create a new entry.  If the new referenced object is
     188             :  * PINned, we don't create an entry (and drop the old one, if any).
     189             :  *
     190             :  * sdepRel must be the pg_shdepend relation, already opened and suitably
     191             :  * locked.
     192             :  */
     193             : static void
     194          66 : shdepChangeDep(Relation sdepRel,
     195             :                Oid classid, Oid objid, int32 objsubid,
     196             :                Oid refclassid, Oid refobjid,
     197             :                SharedDependencyType deptype)
     198             : {
     199          66 :     Oid         dbid = classIdGetDbId(classid);
     200          66 :     HeapTuple   oldtup = NULL;
     201             :     HeapTuple   scantup;
     202             :     ScanKeyData key[4];
     203             :     SysScanDesc scan;
     204             : 
     205             :     /*
     206             :      * Make sure the new referenced object doesn't go away while we record the
     207             :      * dependency.
     208             :      */
     209          66 :     shdepLockAndCheckObject(refclassid, refobjid);
     210             : 
     211             :     /*
     212             :      * Look for a previous entry
     213             :      */
     214          66 :     ScanKeyInit(&key[0],
     215             :                 Anum_pg_shdepend_dbid,
     216             :                 BTEqualStrategyNumber, F_OIDEQ,
     217             :                 ObjectIdGetDatum(dbid));
     218          66 :     ScanKeyInit(&key[1],
     219             :                 Anum_pg_shdepend_classid,
     220             :                 BTEqualStrategyNumber, F_OIDEQ,
     221             :                 ObjectIdGetDatum(classid));
     222          66 :     ScanKeyInit(&key[2],
     223             :                 Anum_pg_shdepend_objid,
     224             :                 BTEqualStrategyNumber, F_OIDEQ,
     225             :                 ObjectIdGetDatum(objid));
     226          66 :     ScanKeyInit(&key[3],
     227             :                 Anum_pg_shdepend_objsubid,
     228             :                 BTEqualStrategyNumber, F_INT4EQ,
     229             :                 Int32GetDatum(objsubid));
     230             : 
     231          66 :     scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
     232             :                               NULL, 4, key);
     233             : 
     234         177 :     while ((scantup = systable_getnext(scan)) != NULL)
     235             :     {
     236             :         /* Ignore if not of the target dependency type */
     237          45 :         if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype)
     238           3 :             continue;
     239             :         /* Caller screwed up if multiple matches */
     240          42 :         if (oldtup)
     241           0 :             elog(ERROR,
     242             :                  "multiple pg_shdepend entries for object %u/%u/%d deptype %c",
     243             :                  classid, objid, objsubid, deptype);
     244          42 :         oldtup = heap_copytuple(scantup);
     245             :     }
     246             : 
     247          66 :     systable_endscan(scan);
     248             : 
     249          66 :     if (isSharedObjectPinned(refclassid, refobjid, sdepRel))
     250             :     {
     251             :         /* No new entry needed, so just delete existing entry if any */
     252           0 :         if (oldtup)
     253           0 :             CatalogTupleDelete(sdepRel, &oldtup->t_self);
     254             :     }
     255          66 :     else if (oldtup)
     256             :     {
     257             :         /* Need to update existing entry */
     258          42 :         Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup);
     259             : 
     260             :         /* Since oldtup is a copy, we can just modify it in-memory */
     261          42 :         shForm->refclassid = refclassid;
     262          42 :         shForm->refobjid = refobjid;
     263             : 
     264          42 :         CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup);
     265             :     }
     266             :     else
     267             :     {
     268             :         /* Need to insert new entry */
     269             :         Datum       values[Natts_pg_shdepend];
     270             :         bool        nulls[Natts_pg_shdepend];
     271             : 
     272          24 :         memset(nulls, false, sizeof(nulls));
     273             : 
     274          24 :         values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid);
     275          24 :         values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid);
     276          24 :         values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid);
     277          24 :         values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubid);
     278             : 
     279          24 :         values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid);
     280          24 :         values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid);
     281          24 :         values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
     282             : 
     283             :         /*
     284             :          * we are reusing oldtup just to avoid declaring a new variable, but
     285             :          * it's certainly a new tuple
     286             :          */
     287          24 :         oldtup = heap_form_tuple(RelationGetDescr(sdepRel), values, nulls);
     288          24 :         CatalogTupleInsert(sdepRel, oldtup);
     289             :     }
     290             : 
     291          66 :     if (oldtup)
     292          66 :         heap_freetuple(oldtup);
     293          66 : }
     294             : 
     295             : /*
     296             :  * changeDependencyOnOwner
     297             :  *
     298             :  * Update the shared dependencies to account for the new owner.
     299             :  *
     300             :  * Note: we don't need an objsubid argument because only whole objects
     301             :  * have owners.
     302             :  */
     303             : void
     304          66 : changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
     305             : {
     306             :     Relation    sdepRel;
     307             : 
     308          66 :     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
     309             : 
     310             :     /* Adjust the SHARED_DEPENDENCY_OWNER entry */
     311          66 :     shdepChangeDep(sdepRel,
     312             :                    classId, objectId, 0,
     313             :                    AuthIdRelationId, newOwnerId,
     314             :                    SHARED_DEPENDENCY_OWNER);
     315             : 
     316             :     /*----------
     317             :      * There should never be a SHARED_DEPENDENCY_ACL entry for the owner,
     318             :      * so get rid of it if there is one.  This can happen if the new owner
     319             :      * was previously granted some rights to the object.
     320             :      *
     321             :      * This step is analogous to aclnewowner's removal of duplicate entries
     322             :      * in the ACL.  We have to do it to handle this scenario:
     323             :      *      A grants some rights on an object to B
     324             :      *      ALTER OWNER changes the object's owner to B
     325             :      *      ALTER OWNER changes the object's owner to C
     326             :      * The third step would remove all mention of B from the object's ACL,
     327             :      * but we'd still have a SHARED_DEPENDENCY_ACL for B if we did not do
     328             :      * things this way.
     329             :      *
     330             :      * The rule against having a SHARED_DEPENDENCY_ACL entry for the owner
     331             :      * allows us to fix things up in just this one place, without having
     332             :      * to make the various ALTER OWNER routines each know about it.
     333             :      *----------
     334             :      */
     335          66 :     shdepDropDependency(sdepRel, classId, objectId, 0, true,
     336             :                         AuthIdRelationId, newOwnerId,
     337             :                         SHARED_DEPENDENCY_ACL);
     338             : 
     339          66 :     heap_close(sdepRel, RowExclusiveLock);
     340          66 : }
     341             : 
     342             : /*
     343             :  * getOidListDiff
     344             :  *      Helper for updateAclDependencies.
     345             :  *
     346             :  * Takes two Oid arrays and removes elements that are common to both arrays,
     347             :  * leaving just those that are in one input but not the other.
     348             :  * We assume both arrays have been sorted and de-duped.
     349             :  */
     350             : static void
     351         415 : getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
     352             : {
     353             :     int         in1,
     354             :                 in2,
     355             :                 out1,
     356             :                 out2;
     357             : 
     358         415 :     in1 = in2 = out1 = out2 = 0;
     359        1041 :     while (in1 < *nlist1 && in2 < *nlist2)
     360             :     {
     361         211 :         if (list1[in1] == list2[in2])
     362             :         {
     363             :             /* skip over duplicates */
     364         199 :             in1++;
     365         199 :             in2++;
     366             :         }
     367          12 :         else if (list1[in1] < list2[in2])
     368             :         {
     369             :             /* list1[in1] is not in list2 */
     370           5 :             list1[out1++] = list1[in1++];
     371             :         }
     372             :         else
     373             :         {
     374             :             /* list2[in2] is not in list1 */
     375           7 :             list2[out2++] = list2[in2++];
     376             :         }
     377             :     }
     378             : 
     379             :     /* any remaining list1 entries are not in list2 */
     380         875 :     while (in1 < *nlist1)
     381             :     {
     382          45 :         list1[out1++] = list1[in1++];
     383             :     }
     384             : 
     385             :     /* any remaining list2 entries are not in list1 */
     386        1245 :     while (in2 < *nlist2)
     387             :     {
     388         415 :         list2[out2++] = list2[in2++];
     389             :     }
     390             : 
     391         415 :     *nlist1 = out1;
     392         415 :     *nlist2 = out2;
     393         415 : }
     394             : 
     395             : /*
     396             :  * updateAclDependencies
     397             :  *      Update the pg_shdepend info for an object's ACL during GRANT/REVOKE.
     398             :  *
     399             :  * classId, objectId, objsubId: identify the object whose ACL this is
     400             :  * ownerId: role owning the object
     401             :  * noldmembers, oldmembers: array of roleids appearing in old ACL
     402             :  * nnewmembers, newmembers: array of roleids appearing in new ACL
     403             :  *
     404             :  * We calculate the differences between the new and old lists of roles,
     405             :  * and then insert or delete from pg_shdepend as appropriate.
     406             :  *
     407             :  * Note that we can't just insert all referenced roles blindly during GRANT,
     408             :  * because we would end up with duplicate registered dependencies.  We could
     409             :  * check for existence of the tuples before inserting, but that seems to be
     410             :  * more expensive than what we are doing here.  Likewise we can't just delete
     411             :  * blindly during REVOKE, because the user may still have other privileges.
     412             :  * It is also possible that REVOKE actually adds dependencies, due to
     413             :  * instantiation of a formerly implicit default ACL (although at present,
     414             :  * all such dependencies should be for the owning role, which we ignore here).
     415             :  *
     416             :  * NOTE: Both input arrays must be sorted and de-duped.  (Typically they
     417             :  * are extracted from an ACL array by aclmembers(), which takes care of
     418             :  * both requirements.)  The arrays are pfreed before return.
     419             :  */
     420             : void
     421         415 : updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
     422             :                       Oid ownerId,
     423             :                       int noldmembers, Oid *oldmembers,
     424             :                       int nnewmembers, Oid *newmembers)
     425             : {
     426             :     Relation    sdepRel;
     427             :     int         i;
     428             : 
     429             :     /*
     430             :      * Remove entries that are common to both lists; those represent existing
     431             :      * dependencies we don't need to change.
     432             :      *
     433             :      * OK to overwrite the inputs since we'll pfree them anyway.
     434             :      */
     435         415 :     getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers);
     436             : 
     437         415 :     if (noldmembers > 0 || nnewmembers > 0)
     438             :     {
     439         362 :         sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
     440             : 
     441             :         /* Add new dependencies that weren't already present */
     442         784 :         for (i = 0; i < nnewmembers; i++)
     443             :         {
     444         422 :             Oid         roleid = newmembers[i];
     445             : 
     446             :             /*
     447             :              * Skip the owner: he has an OWNER shdep entry instead. (This is
     448             :              * not just a space optimization; it makes ALTER OWNER easier. See
     449             :              * notes in changeDependencyOnOwner.)
     450             :              */
     451         422 :             if (roleid == ownerId)
     452         280 :                 continue;
     453             : 
     454             :             /* Skip pinned roles; they don't need dependency entries */
     455         142 :             if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
     456           2 :                 continue;
     457             : 
     458         140 :             shdepAddDependency(sdepRel, classId, objectId, objsubId,
     459             :                                AuthIdRelationId, roleid,
     460             :                                SHARED_DEPENDENCY_ACL);
     461             :         }
     462             : 
     463             :         /* Drop no-longer-used old dependencies */
     464         412 :         for (i = 0; i < noldmembers; i++)
     465             :         {
     466          50 :             Oid         roleid = oldmembers[i];
     467             : 
     468             :             /* Skip the owner, same as above */
     469          50 :             if (roleid == ownerId)
     470           6 :                 continue;
     471             : 
     472             :             /* Skip pinned roles */
     473          44 :             if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
     474           0 :                 continue;
     475             : 
     476          44 :             shdepDropDependency(sdepRel, classId, objectId, objsubId,
     477             :                                 false,  /* exact match on objsubId */
     478             :                                 AuthIdRelationId, roleid,
     479             :                                 SHARED_DEPENDENCY_ACL);
     480             :         }
     481             : 
     482         362 :         heap_close(sdepRel, RowExclusiveLock);
     483             :     }
     484             : 
     485         415 :     if (oldmembers)
     486         125 :         pfree(oldmembers);
     487         415 :     if (newmembers)
     488         399 :         pfree(newmembers);
     489         415 : }
     490             : 
     491             : /*
     492             :  * A struct to keep track of dependencies found in other databases.
     493             :  */
     494             : typedef struct
     495             : {
     496             :     Oid         dbOid;
     497             :     int         count;
     498             : } remoteDep;
     499             : 
     500             : /*
     501             :  * checkSharedDependencies
     502             :  *
     503             :  * Check whether there are shared dependency entries for a given shared
     504             :  * object; return true if so.
     505             :  *
     506             :  * In addition, return a string containing a newline-separated list of object
     507             :  * descriptions that depend on the shared object, or NULL if none is found.
     508             :  * We actually return two such strings; the "detail" result is suitable for
     509             :  * returning to the client as an errdetail() string, and is limited in size.
     510             :  * The "detail_log" string is potentially much longer, and should be emitted
     511             :  * to the server log only.
     512             :  *
     513             :  * We can find three different kinds of dependencies: dependencies on objects
     514             :  * of the current database; dependencies on shared objects; and dependencies
     515             :  * on objects local to other databases.  We can (and do) provide descriptions
     516             :  * of the two former kinds of objects, but we can't do that for "remote"
     517             :  * objects, so we just provide a count of them.
     518             :  *
     519             :  * If we find a SHARED_DEPENDENCY_PIN entry, we can error out early.
     520             :  */
     521             : bool
     522         120 : checkSharedDependencies(Oid classId, Oid objectId,
     523             :                         char **detail_msg, char **detail_log_msg)
     524             : {
     525             :     Relation    sdepRel;
     526             :     ScanKeyData key[2];
     527             :     SysScanDesc scan;
     528             :     HeapTuple   tup;
     529         120 :     int         numReportedDeps = 0;
     530         120 :     int         numNotReportedDeps = 0;
     531         120 :     int         numNotReportedDbs = 0;
     532         120 :     List       *remDeps = NIL;
     533             :     ListCell   *cell;
     534             :     ObjectAddress object;
     535             :     StringInfoData descs;
     536             :     StringInfoData alldescs;
     537             : 
     538             :     /*
     539             :      * We limit the number of dependencies reported to the client to
     540             :      * MAX_REPORTED_DEPS, since client software may not deal well with
     541             :      * enormous error strings.  The server log always gets a full report.
     542             :      */
     543             : #define MAX_REPORTED_DEPS 100
     544             : 
     545         120 :     initStringInfo(&descs);
     546         120 :     initStringInfo(&alldescs);
     547             : 
     548         120 :     sdepRel = heap_open(SharedDependRelationId, AccessShareLock);
     549             : 
     550         120 :     ScanKeyInit(&key[0],
     551             :                 Anum_pg_shdepend_refclassid,
     552             :                 BTEqualStrategyNumber, F_OIDEQ,
     553             :                 ObjectIdGetDatum(classId));
     554         120 :     ScanKeyInit(&key[1],
     555             :                 Anum_pg_shdepend_refobjid,
     556             :                 BTEqualStrategyNumber, F_OIDEQ,
     557             :                 ObjectIdGetDatum(objectId));
     558             : 
     559         120 :     scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
     560             :                               NULL, 2, key);
     561             : 
     562         271 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     563             :     {
     564          31 :         Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
     565             : 
     566             :         /* This case can be dispatched quickly */
     567          31 :         if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
     568             :         {
     569           0 :             object.classId = classId;
     570           0 :             object.objectId = objectId;
     571           0 :             object.objectSubId = 0;
     572           0 :             ereport(ERROR,
     573             :                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
     574             :                      errmsg("cannot drop %s because it is required by the database system",
     575             :                             getObjectDescription(&object))));
     576             :         }
     577             : 
     578          31 :         object.classId = sdepForm->classid;
     579          31 :         object.objectId = sdepForm->objid;
     580          31 :         object.objectSubId = sdepForm->objsubid;
     581             : 
     582             :         /*
     583             :          * If it's a dependency local to this database or it's a shared
     584             :          * object, describe it.
     585             :          *
     586             :          * If it's a remote dependency, keep track of it so we can report the
     587             :          * number of them later.
     588             :          */
     589          31 :         if (sdepForm->dbid == MyDatabaseId)
     590             :         {
     591          30 :             if (numReportedDeps < MAX_REPORTED_DEPS)
     592             :             {
     593          30 :                 numReportedDeps++;
     594          30 :                 storeObjectDescription(&descs, LOCAL_OBJECT, &object,
     595          30 :                                        sdepForm->deptype, 0);
     596             :             }
     597             :             else
     598           0 :                 numNotReportedDeps++;
     599          30 :             storeObjectDescription(&alldescs, LOCAL_OBJECT, &object,
     600          30 :                                    sdepForm->deptype, 0);
     601             :         }
     602           1 :         else if (sdepForm->dbid == InvalidOid)
     603             :         {
     604           1 :             if (numReportedDeps < MAX_REPORTED_DEPS)
     605             :             {
     606           1 :                 numReportedDeps++;
     607           1 :                 storeObjectDescription(&descs, SHARED_OBJECT, &object,
     608           1 :                                        sdepForm->deptype, 0);
     609             :             }
     610             :             else
     611           0 :                 numNotReportedDeps++;
     612           1 :             storeObjectDescription(&alldescs, SHARED_OBJECT, &object,
     613           1 :                                    sdepForm->deptype, 0);
     614             :         }
     615             :         else
     616             :         {
     617             :             /* It's not local nor shared, so it must be remote. */
     618             :             remoteDep  *dep;
     619           0 :             bool        stored = false;
     620             : 
     621             :             /*
     622             :              * XXX this info is kept on a simple List.  Maybe it's not good
     623             :              * for performance, but using a hash table seems needlessly
     624             :              * complex.  The expected number of databases is not high anyway,
     625             :              * I suppose.
     626             :              */
     627           0 :             foreach(cell, remDeps)
     628             :             {
     629           0 :                 dep = lfirst(cell);
     630           0 :                 if (dep->dbOid == sdepForm->dbid)
     631             :                 {
     632           0 :                     dep->count++;
     633           0 :                     stored = true;
     634           0 :                     break;
     635             :                 }
     636             :             }
     637           0 :             if (!stored)
     638             :             {
     639           0 :                 dep = (remoteDep *) palloc(sizeof(remoteDep));
     640           0 :                 dep->dbOid = sdepForm->dbid;
     641           0 :                 dep->count = 1;
     642           0 :                 remDeps = lappend(remDeps, dep);
     643             :             }
     644             :         }
     645             :     }
     646             : 
     647         120 :     systable_endscan(scan);
     648             : 
     649         120 :     heap_close(sdepRel, AccessShareLock);
     650             : 
     651             :     /*
     652             :      * Summarize dependencies in remote databases.
     653             :      */
     654         120 :     foreach(cell, remDeps)
     655             :     {
     656           0 :         remoteDep  *dep = lfirst(cell);
     657             : 
     658           0 :         object.classId = DatabaseRelationId;
     659           0 :         object.objectId = dep->dbOid;
     660           0 :         object.objectSubId = 0;
     661             : 
     662           0 :         if (numReportedDeps < MAX_REPORTED_DEPS)
     663             :         {
     664           0 :             numReportedDeps++;
     665           0 :             storeObjectDescription(&descs, REMOTE_OBJECT, &object,
     666             :                                    SHARED_DEPENDENCY_INVALID, dep->count);
     667             :         }
     668             :         else
     669           0 :             numNotReportedDbs++;
     670           0 :         storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
     671             :                                SHARED_DEPENDENCY_INVALID, dep->count);
     672             :     }
     673             : 
     674         120 :     list_free_deep(remDeps);
     675             : 
     676         120 :     if (descs.len == 0)
     677             :     {
     678         106 :         pfree(descs.data);
     679         106 :         pfree(alldescs.data);
     680         106 :         *detail_msg = *detail_log_msg = NULL;
     681         106 :         return false;
     682             :     }
     683             : 
     684          14 :     if (numNotReportedDeps > 0)
     685           0 :         appendStringInfo(&descs, ngettext("\nand %d other object "
     686             :                                           "(see server log for list)",
     687             :                                           "\nand %d other objects "
     688             :                                           "(see server log for list)",
     689             :                                           numNotReportedDeps),
     690             :                          numNotReportedDeps);
     691          14 :     if (numNotReportedDbs > 0)
     692           0 :         appendStringInfo(&descs, ngettext("\nand objects in %d other database "
     693             :                                           "(see server log for list)",
     694             :                                           "\nand objects in %d other databases "
     695             :                                           "(see server log for list)",
     696             :                                           numNotReportedDbs),
     697             :                          numNotReportedDbs);
     698             : 
     699          14 :     *detail_msg = descs.data;
     700          14 :     *detail_log_msg = alldescs.data;
     701          14 :     return true;
     702             : }
     703             : 
     704             : /*
     705             :  * copyTemplateDependencies
     706             :  *
     707             :  * Routine to create the initial shared dependencies of a new database.
     708             :  * We simply copy the dependencies from the template database.
     709             :  */
     710             : void
     711           3 : copyTemplateDependencies(Oid templateDbId, Oid newDbId)
     712             : {
     713             :     Relation    sdepRel;
     714             :     TupleDesc   sdepDesc;
     715             :     ScanKeyData key[1];
     716             :     SysScanDesc scan;
     717             :     HeapTuple   tup;
     718             :     CatalogIndexState indstate;
     719             :     Datum       values[Natts_pg_shdepend];
     720             :     bool        nulls[Natts_pg_shdepend];
     721             :     bool        replace[Natts_pg_shdepend];
     722             : 
     723           3 :     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
     724           3 :     sdepDesc = RelationGetDescr(sdepRel);
     725             : 
     726           3 :     indstate = CatalogOpenIndexes(sdepRel);
     727             : 
     728             :     /* Scan all entries with dbid = templateDbId */
     729           3 :     ScanKeyInit(&key[0],
     730             :                 Anum_pg_shdepend_dbid,
     731             :                 BTEqualStrategyNumber, F_OIDEQ,
     732             :                 ObjectIdGetDatum(templateDbId));
     733             : 
     734           3 :     scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
     735             :                               NULL, 1, key);
     736             : 
     737             :     /* Set up to copy the tuples except for inserting newDbId */
     738           3 :     memset(values, 0, sizeof(values));
     739           3 :     memset(nulls, false, sizeof(nulls));
     740           3 :     memset(replace, false, sizeof(replace));
     741             : 
     742           3 :     replace[Anum_pg_shdepend_dbid - 1] = true;
     743           3 :     values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);
     744             : 
     745             :     /*
     746             :      * Copy the entries of the original database, changing the database Id to
     747             :      * that of the new database.  Note that because we are not copying rows
     748             :      * with dbId == 0 (ie, rows describing dependent shared objects) we won't
     749             :      * copy the ownership dependency of the template database itself; this is
     750             :      * what we want.
     751             :      */
     752           6 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     753             :     {
     754             :         HeapTuple   newtup;
     755             : 
     756           0 :         newtup = heap_modify_tuple(tup, sdepDesc, values, nulls, replace);
     757           0 :         CatalogTupleInsertWithInfo(sdepRel, newtup, indstate);
     758             : 
     759           0 :         heap_freetuple(newtup);
     760             :     }
     761             : 
     762           3 :     systable_endscan(scan);
     763             : 
     764           3 :     CatalogCloseIndexes(indstate);
     765           3 :     heap_close(sdepRel, RowExclusiveLock);
     766           3 : }
     767             : 
     768             : /*
     769             :  * dropDatabaseDependencies
     770             :  *
     771             :  * Delete pg_shdepend entries corresponding to a database that's being
     772             :  * dropped.
     773             :  */
     774             : void
     775           0 : dropDatabaseDependencies(Oid databaseId)
     776             : {
     777             :     Relation    sdepRel;
     778             :     ScanKeyData key[1];
     779             :     SysScanDesc scan;
     780             :     HeapTuple   tup;
     781             : 
     782           0 :     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
     783             : 
     784             :     /*
     785             :      * First, delete all the entries that have the database Oid in the dbid
     786             :      * field.
     787             :      */
     788           0 :     ScanKeyInit(&key[0],
     789             :                 Anum_pg_shdepend_dbid,
     790             :                 BTEqualStrategyNumber, F_OIDEQ,
     791             :                 ObjectIdGetDatum(databaseId));
     792             :     /* We leave the other index fields unspecified */
     793             : 
     794           0 :     scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
     795             :                               NULL, 1, key);
     796             : 
     797           0 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     798             :     {
     799           0 :         CatalogTupleDelete(sdepRel, &tup->t_self);
     800             :     }
     801             : 
     802           0 :     systable_endscan(scan);
     803             : 
     804             :     /* Now delete all entries corresponding to the database itself */
     805           0 :     shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true,
     806             :                         InvalidOid, InvalidOid,
     807             :                         SHARED_DEPENDENCY_INVALID);
     808             : 
     809           0 :     heap_close(sdepRel, RowExclusiveLock);
     810           0 : }
     811             : 
     812             : /*
     813             :  * deleteSharedDependencyRecordsFor
     814             :  *
     815             :  * Delete all pg_shdepend entries corresponding to an object that's being
     816             :  * dropped or modified.  The object is assumed to be either a shared object
     817             :  * or local to the current database (the classId tells us which).
     818             :  *
     819             :  * If objectSubId is zero, we are deleting a whole object, so get rid of
     820             :  * pg_shdepend entries for subobjects as well.
     821             :  */
     822             : void
     823        9153 : deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
     824             : {
     825             :     Relation    sdepRel;
     826             : 
     827        9153 :     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
     828             : 
     829        9153 :     shdepDropDependency(sdepRel, classId, objectId, objectSubId,
     830             :                         (objectSubId == 0),
     831             :                         InvalidOid, InvalidOid,
     832             :                         SHARED_DEPENDENCY_INVALID);
     833             : 
     834        9153 :     heap_close(sdepRel, RowExclusiveLock);
     835        9153 : }
     836             : 
     837             : /*
     838             :  * shdepAddDependency
     839             :  *      Internal workhorse for inserting into pg_shdepend
     840             :  *
     841             :  * sdepRel must be the pg_shdepend relation, already opened and suitably
     842             :  * locked.
     843             :  */
     844             : static void
     845         491 : shdepAddDependency(Relation sdepRel,
     846             :                    Oid classId, Oid objectId, int32 objsubId,
     847             :                    Oid refclassId, Oid refobjId,
     848             :                    SharedDependencyType deptype)
     849             : {
     850             :     HeapTuple   tup;
     851             :     Datum       values[Natts_pg_shdepend];
     852             :     bool        nulls[Natts_pg_shdepend];
     853             : 
     854             :     /*
     855             :      * Make sure the object doesn't go away while we record the dependency on
     856             :      * it.  DROP routines should lock the object exclusively before they check
     857             :      * shared dependencies.
     858             :      */
     859         491 :     shdepLockAndCheckObject(refclassId, refobjId);
     860             : 
     861         491 :     memset(nulls, false, sizeof(nulls));
     862             : 
     863             :     /*
     864             :      * Form the new tuple and record the dependency.
     865             :      */
     866         491 :     values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
     867         491 :     values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
     868         491 :     values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
     869         491 :     values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId);
     870             : 
     871         491 :     values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
     872         491 :     values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
     873         491 :     values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
     874             : 
     875         491 :     tup = heap_form_tuple(sdepRel->rd_att, values, nulls);
     876             : 
     877         491 :     CatalogTupleInsert(sdepRel, tup);
     878             : 
     879             :     /* clean up */
     880         491 :     heap_freetuple(tup);
     881         491 : }
     882             : 
     883             : /*
     884             :  * shdepDropDependency
     885             :  *      Internal workhorse for deleting entries from pg_shdepend.
     886             :  *
     887             :  * We drop entries having the following properties:
     888             :  *  dependent object is the one identified by classId/objectId/objsubId
     889             :  *  if refclassId isn't InvalidOid, it must match the entry's refclassid
     890             :  *  if refobjId isn't InvalidOid, it must match the entry's refobjid
     891             :  *  if deptype isn't SHARED_DEPENDENCY_INVALID, it must match entry's deptype
     892             :  *
     893             :  * If drop_subobjects is true, we ignore objsubId and consider all entries
     894             :  * matching classId/objectId.
     895             :  *
     896             :  * sdepRel must be the pg_shdepend relation, already opened and suitably
     897             :  * locked.
     898             :  */
     899             : static void
     900        9263 : shdepDropDependency(Relation sdepRel,
     901             :                     Oid classId, Oid objectId, int32 objsubId,
     902             :                     bool drop_subobjects,
     903             :                     Oid refclassId, Oid refobjId,
     904             :                     SharedDependencyType deptype)
     905             : {
     906             :     ScanKeyData key[4];
     907             :     int         nkeys;
     908             :     SysScanDesc scan;
     909             :     HeapTuple   tup;
     910             : 
     911             :     /* Scan for entries matching the dependent object */
     912        9263 :     ScanKeyInit(&key[0],
     913             :                 Anum_pg_shdepend_dbid,
     914             :                 BTEqualStrategyNumber, F_OIDEQ,
     915             :                 ObjectIdGetDatum(classIdGetDbId(classId)));
     916        9263 :     ScanKeyInit(&key[1],
     917             :                 Anum_pg_shdepend_classid,
     918             :                 BTEqualStrategyNumber, F_OIDEQ,
     919             :                 ObjectIdGetDatum(classId));
     920        9263 :     ScanKeyInit(&key[2],
     921             :                 Anum_pg_shdepend_objid,
     922             :                 BTEqualStrategyNumber, F_OIDEQ,
     923             :                 ObjectIdGetDatum(objectId));
     924        9263 :     if (drop_subobjects)
     925        9102 :         nkeys = 3;
     926             :     else
     927             :     {
     928         161 :         ScanKeyInit(&key[3],
     929             :                     Anum_pg_shdepend_objsubid,
     930             :                     BTEqualStrategyNumber, F_INT4EQ,
     931             :                     Int32GetDatum(objsubId));
     932         161 :         nkeys = 4;
     933             :     }
     934             : 
     935        9263 :     scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
     936             :                               NULL, nkeys, key);
     937             : 
     938       19125 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     939             :     {
     940         599 :         Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
     941             : 
     942             :         /* Filter entries according to additional parameters */
     943         599 :         if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId)
     944           0 :             continue;
     945         599 :         if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId)
     946          80 :             continue;
     947         564 :         if (deptype != SHARED_DEPENDENCY_INVALID &&
     948          45 :             shdepForm->deptype != deptype)
     949           0 :             continue;
     950             : 
     951             :         /* OK, delete it */
     952         519 :         CatalogTupleDelete(sdepRel, &tup->t_self);
     953             :     }
     954             : 
     955        9263 :     systable_endscan(scan);
     956        9263 : }
     957             : 
     958             : /*
     959             :  * classIdGetDbId
     960             :  *
     961             :  * Get the database Id that should be used in pg_shdepend, given the OID
     962             :  * of the catalog containing the object.  For shared objects, it's 0
     963             :  * (InvalidOid); for all other objects, it's the current database Id.
     964             :  */
     965             : static Oid
     966        9820 : classIdGetDbId(Oid classId)
     967             : {
     968             :     Oid         dbId;
     969             : 
     970        9820 :     if (IsSharedRelation(classId))
     971          16 :         dbId = InvalidOid;
     972             :     else
     973        9804 :         dbId = MyDatabaseId;
     974             : 
     975        9820 :     return dbId;
     976             : }
     977             : 
     978             : /*
     979             :  * shdepLockAndCheckObject
     980             :  *
     981             :  * Lock the object that we are about to record a dependency on.
     982             :  * After it's locked, verify that it hasn't been dropped while we
     983             :  * weren't looking.  If the object has been dropped, this function
     984             :  * does not return!
     985             :  */
     986             : void
     987         583 : shdepLockAndCheckObject(Oid classId, Oid objectId)
     988             : {
     989             :     /* AccessShareLock should be OK, since we are not modifying the object */
     990         583 :     LockSharedObject(classId, objectId, 0, AccessShareLock);
     991             : 
     992         583 :     switch (classId)
     993             :     {
     994             :         case AuthIdRelationId:
     995         577 :             if (!SearchSysCacheExists1(AUTHOID, ObjectIdGetDatum(objectId)))
     996           0 :                 ereport(ERROR,
     997             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
     998             :                          errmsg("role %u was concurrently dropped",
     999             :                                 objectId)));
    1000         577 :             break;
    1001             : 
    1002             :             /*
    1003             :              * Currently, this routine need not support any other shared
    1004             :              * object types besides roles.  If we wanted to record explicit
    1005             :              * dependencies on databases or tablespaces, we'd need code along
    1006             :              * these lines:
    1007             :              */
    1008             : #ifdef NOT_USED
    1009             :         case TableSpaceRelationId:
    1010             :             {
    1011             :                 /* For lack of a syscache on pg_tablespace, do this: */
    1012             :                 char       *tablespace = get_tablespace_name(objectId);
    1013             : 
    1014             :                 if (tablespace == NULL)
    1015             :                     ereport(ERROR,
    1016             :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
    1017             :                              errmsg("tablespace %u was concurrently dropped",
    1018             :                                     objectId)));
    1019             :                 pfree(tablespace);
    1020             :                 break;
    1021             :             }
    1022             : #endif
    1023             : 
    1024             :         case DatabaseRelationId:
    1025             :             {
    1026             :                 /* For lack of a syscache on pg_database, do this: */
    1027           6 :                 char       *database = get_database_name(objectId);
    1028             : 
    1029           6 :                 if (database == NULL)
    1030           0 :                     ereport(ERROR,
    1031             :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
    1032             :                              errmsg("database %u was concurrently dropped",
    1033             :                                     objectId)));
    1034           6 :                 pfree(database);
    1035           6 :                 break;
    1036             :             }
    1037             : 
    1038             : 
    1039             :         default:
    1040           0 :             elog(ERROR, "unrecognized shared classId: %u", classId);
    1041             :     }
    1042         583 : }
    1043             : 
    1044             : 
    1045             : /*
    1046             :  * storeObjectDescription
    1047             :  *      Append the description of a dependent object to "descs"
    1048             :  *
    1049             :  * While searching for dependencies of a shared object, we stash the
    1050             :  * descriptions of dependent objects we find in a single string, which we
    1051             :  * later pass to ereport() in the DETAIL field when somebody attempts to
    1052             :  * drop a referenced shared object.
    1053             :  *
    1054             :  * When type is LOCAL_OBJECT or SHARED_OBJECT, we expect object to be the
    1055             :  * dependent object, deptype is the dependency type, and count is not used.
    1056             :  * When type is REMOTE_OBJECT, we expect object to be the database object,
    1057             :  * and count to be nonzero; deptype is not used in this case.
    1058             :  */
    1059             : static void
    1060          62 : storeObjectDescription(StringInfo descs,
    1061             :                        SharedDependencyObjectType type,
    1062             :                        ObjectAddress *object,
    1063             :                        SharedDependencyType deptype,
    1064             :                        int count)
    1065             : {
    1066          62 :     char       *objdesc = getObjectDescription(object);
    1067             : 
    1068             :     /* separate entries with a newline */
    1069          62 :     if (descs->len != 0)
    1070          34 :         appendStringInfoChar(descs, '\n');
    1071             : 
    1072          62 :     switch (type)
    1073             :     {
    1074             :         case LOCAL_OBJECT:
    1075             :         case SHARED_OBJECT:
    1076          62 :             if (deptype == SHARED_DEPENDENCY_OWNER)
    1077          36 :                 appendStringInfo(descs, _("owner of %s"), objdesc);
    1078          26 :             else if (deptype == SHARED_DEPENDENCY_ACL)
    1079          22 :                 appendStringInfo(descs, _("privileges for %s"), objdesc);
    1080           4 :             else if (deptype == SHARED_DEPENDENCY_POLICY)
    1081           4 :                 appendStringInfo(descs, _("target of %s"), objdesc);
    1082             :             else
    1083           0 :                 elog(ERROR, "unrecognized dependency type: %d",
    1084             :                      (int) deptype);
    1085          62 :             break;
    1086             : 
    1087             :         case REMOTE_OBJECT:
    1088             :             /* translator: %s will always be "database %s" */
    1089           0 :             appendStringInfo(descs, ngettext("%d object in %s",
    1090             :                                              "%d objects in %s",
    1091             :                                              count),
    1092             :                              count, objdesc);
    1093           0 :             break;
    1094             : 
    1095             :         default:
    1096           0 :             elog(ERROR, "unrecognized object type: %d", type);
    1097             :     }
    1098             : 
    1099          62 :     pfree(objdesc);
    1100          62 : }
    1101             : 
    1102             : 
    1103             : /*
    1104             :  * isSharedObjectPinned
    1105             :  *      Return whether a given shared object has a SHARED_DEPENDENCY_PIN entry.
    1106             :  *
    1107             :  * sdepRel must be the pg_shdepend relation, already opened and suitably
    1108             :  * locked.
    1109             :  */
    1110             : static bool
    1111        3906 : isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
    1112             : {
    1113        3906 :     bool        result = false;
    1114             :     ScanKeyData key[2];
    1115             :     SysScanDesc scan;
    1116             :     HeapTuple   tup;
    1117             : 
    1118        3906 :     ScanKeyInit(&key[0],
    1119             :                 Anum_pg_shdepend_refclassid,
    1120             :                 BTEqualStrategyNumber, F_OIDEQ,
    1121             :                 ObjectIdGetDatum(classId));
    1122        3906 :     ScanKeyInit(&key[1],
    1123             :                 Anum_pg_shdepend_refobjid,
    1124             :                 BTEqualStrategyNumber, F_OIDEQ,
    1125             :                 ObjectIdGetDatum(objectId));
    1126             : 
    1127        3906 :     scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
    1128             :                               NULL, 2, key);
    1129             : 
    1130             :     /*
    1131             :      * Since we won't generate additional pg_shdepend entries for pinned
    1132             :      * objects, there can be at most one entry referencing a pinned object.
    1133             :      * Hence, it's sufficient to look at the first returned tuple; we don't
    1134             :      * need to loop.
    1135             :      */
    1136        3906 :     tup = systable_getnext(scan);
    1137        3906 :     if (HeapTupleIsValid(tup))
    1138             :     {
    1139        3809 :         Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
    1140             : 
    1141        3809 :         if (shdepForm->deptype == SHARED_DEPENDENCY_PIN)
    1142        3283 :             result = true;
    1143             :     }
    1144             : 
    1145        3906 :     systable_endscan(scan);
    1146             : 
    1147        3906 :     return result;
    1148             : }
    1149             : 
    1150             : /*
    1151             :  * shdepDropOwned
    1152             :  *
    1153             :  * Drop the objects owned by any one of the given RoleIds.  If a role has
    1154             :  * access to an object, the grant will be removed as well (but the object
    1155             :  * will not, of course).
    1156             :  *
    1157             :  * We can revoke grants immediately while doing the scan, but drops are
    1158             :  * saved up and done all at once with performMultipleDeletions.  This
    1159             :  * is necessary so that we don't get failures from trying to delete
    1160             :  * interdependent objects in the wrong order.
    1161             :  */
    1162             : void
    1163          14 : shdepDropOwned(List *roleids, DropBehavior behavior)
    1164             : {
    1165             :     Relation    sdepRel;
    1166             :     ListCell   *cell;
    1167             :     ObjectAddresses *deleteobjs;
    1168             : 
    1169          14 :     deleteobjs = new_object_addresses();
    1170             : 
    1171             :     /*
    1172             :      * We don't need this strong a lock here, but we'll call routines that
    1173             :      * acquire RowExclusiveLock.  Better get that right now to avoid potential
    1174             :      * deadlock failures.
    1175             :      */
    1176          14 :     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
    1177             : 
    1178             :     /*
    1179             :      * For each role, find the dependent objects and drop them using the
    1180             :      * regular (non-shared) dependency management.
    1181             :      */
    1182          34 :     foreach(cell, roleids)
    1183             :     {
    1184          20 :         Oid         roleid = lfirst_oid(cell);
    1185             :         ScanKeyData key[2];
    1186             :         SysScanDesc scan;
    1187             :         HeapTuple   tuple;
    1188             : 
    1189             :         /* Doesn't work for pinned objects */
    1190          20 :         if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
    1191             :         {
    1192             :             ObjectAddress obj;
    1193             : 
    1194           0 :             obj.classId = AuthIdRelationId;
    1195           0 :             obj.objectId = roleid;
    1196           0 :             obj.objectSubId = 0;
    1197             : 
    1198           0 :             ereport(ERROR,
    1199             :                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
    1200             :                      errmsg("cannot drop objects owned by %s because they are "
    1201             :                             "required by the database system",
    1202             :                             getObjectDescription(&obj))));
    1203             :         }
    1204             : 
    1205          20 :         ScanKeyInit(&key[0],
    1206             :                     Anum_pg_shdepend_refclassid,
    1207             :                     BTEqualStrategyNumber, F_OIDEQ,
    1208             :                     ObjectIdGetDatum(AuthIdRelationId));
    1209          20 :         ScanKeyInit(&key[1],
    1210             :                     Anum_pg_shdepend_refobjid,
    1211             :                     BTEqualStrategyNumber, F_OIDEQ,
    1212             :                     ObjectIdGetDatum(roleid));
    1213             : 
    1214          20 :         scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
    1215             :                                   NULL, 2, key);
    1216             : 
    1217         111 :         while ((tuple = systable_getnext(scan)) != NULL)
    1218             :         {
    1219          71 :             Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
    1220             :             ObjectAddress obj;
    1221             : 
    1222             :             /*
    1223             :              * We only operate on shared objects and objects in the current
    1224             :              * database
    1225             :              */
    1226          72 :             if (sdepForm->dbid != MyDatabaseId &&
    1227           1 :                 sdepForm->dbid != InvalidOid)
    1228           0 :                 continue;
    1229             : 
    1230          71 :             switch (sdepForm->deptype)
    1231             :             {
    1232             :                     /* Shouldn't happen */
    1233             :                 case SHARED_DEPENDENCY_PIN:
    1234             :                 case SHARED_DEPENDENCY_INVALID:
    1235           0 :                     elog(ERROR, "unexpected dependency type");
    1236             :                     break;
    1237             :                 case SHARED_DEPENDENCY_ACL:
    1238           5 :                     RemoveRoleFromObjectACL(roleid,
    1239             :                                             sdepForm->classid,
    1240             :                                             sdepForm->objid);
    1241           5 :                     break;
    1242             :                 case SHARED_DEPENDENCY_POLICY:
    1243             :                     /* If unable to remove role from policy, remove policy. */
    1244           3 :                     if (!RemoveRoleFromObjectPolicy(roleid,
    1245             :                                                     sdepForm->classid,
    1246             :                                                     sdepForm->objid))
    1247             :                     {
    1248           1 :                         obj.classId = sdepForm->classid;
    1249           1 :                         obj.objectId = sdepForm->objid;
    1250           1 :                         obj.objectSubId = sdepForm->objsubid;
    1251           1 :                         add_exact_object_address(&obj, deleteobjs);
    1252             :                     }
    1253           3 :                     break;
    1254             :                 case SHARED_DEPENDENCY_OWNER:
    1255             :                     /* If a local object, save it for deletion below */
    1256          63 :                     if (sdepForm->dbid == MyDatabaseId)
    1257             :                     {
    1258          63 :                         obj.classId = sdepForm->classid;
    1259          63 :                         obj.objectId = sdepForm->objid;
    1260          63 :                         obj.objectSubId = sdepForm->objsubid;
    1261          63 :                         add_exact_object_address(&obj, deleteobjs);
    1262             :                     }
    1263          63 :                     break;
    1264             :             }
    1265             :         }
    1266             : 
    1267          20 :         systable_endscan(scan);
    1268             :     }
    1269             : 
    1270             :     /* the dependency mechanism does the actual work */
    1271          14 :     performMultipleDeletions(deleteobjs, behavior, 0);
    1272             : 
    1273          13 :     heap_close(sdepRel, RowExclusiveLock);
    1274             : 
    1275          13 :     free_object_addresses(deleteobjs);
    1276          13 : }
    1277             : 
    1278             : /*
    1279             :  * shdepReassignOwned
    1280             :  *
    1281             :  * Change the owner of objects owned by any of the roles in roleids to
    1282             :  * newrole.  Grants are not touched.
    1283             :  */
    1284             : void
    1285           2 : shdepReassignOwned(List *roleids, Oid newrole)
    1286             : {
    1287             :     Relation    sdepRel;
    1288             :     ListCell   *cell;
    1289             : 
    1290             :     /*
    1291             :      * We don't need this strong a lock here, but we'll call routines that
    1292             :      * acquire RowExclusiveLock.  Better get that right now to avoid potential
    1293             :      * deadlock problems.
    1294             :      */
    1295           2 :     sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
    1296             : 
    1297           4 :     foreach(cell, roleids)
    1298             :     {
    1299             :         SysScanDesc scan;
    1300             :         ScanKeyData key[2];
    1301             :         HeapTuple   tuple;
    1302           2 :         Oid         roleid = lfirst_oid(cell);
    1303             : 
    1304             :         /* Refuse to work on pinned roles */
    1305           2 :         if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
    1306             :         {
    1307             :             ObjectAddress obj;
    1308             : 
    1309           0 :             obj.classId = AuthIdRelationId;
    1310           0 :             obj.objectId = roleid;
    1311           0 :             obj.objectSubId = 0;
    1312             : 
    1313           0 :             ereport(ERROR,
    1314             :                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
    1315             :                      errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system",
    1316             :                             getObjectDescription(&obj))));
    1317             : 
    1318             :             /*
    1319             :              * There's no need to tell the whole truth, which is that we
    1320             :              * didn't track these dependencies at all ...
    1321             :              */
    1322             :         }
    1323             : 
    1324           2 :         ScanKeyInit(&key[0],
    1325             :                     Anum_pg_shdepend_refclassid,
    1326             :                     BTEqualStrategyNumber, F_OIDEQ,
    1327             :                     ObjectIdGetDatum(AuthIdRelationId));
    1328           2 :         ScanKeyInit(&key[1],
    1329             :                     Anum_pg_shdepend_refobjid,
    1330             :                     BTEqualStrategyNumber, F_OIDEQ,
    1331             :                     ObjectIdGetDatum(roleid));
    1332             : 
    1333           2 :         scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
    1334             :                                   NULL, 2, key);
    1335             : 
    1336          22 :         while ((tuple = systable_getnext(scan)) != NULL)
    1337             :         {
    1338          18 :             Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
    1339             : 
    1340             :             /*
    1341             :              * We only operate on shared objects and objects in the current
    1342             :              * database
    1343             :              */
    1344          19 :             if (sdepForm->dbid != MyDatabaseId &&
    1345           1 :                 sdepForm->dbid != InvalidOid)
    1346           0 :                 continue;
    1347             : 
    1348             :             /* Unexpected because we checked for pins above */
    1349          18 :             if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
    1350           0 :                 elog(ERROR, "unexpected shared pin");
    1351             : 
    1352             :             /* We leave non-owner dependencies alone */
    1353          18 :             if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER)
    1354           4 :                 continue;
    1355             : 
    1356             :             /* Issue the appropriate ALTER OWNER call */
    1357          14 :             switch (sdepForm->classid)
    1358             :             {
    1359             :                 case TypeRelationId:
    1360           3 :                     AlterTypeOwner_oid(sdepForm->objid, newrole, true);
    1361           3 :                     break;
    1362             : 
    1363             :                 case NamespaceRelationId:
    1364           1 :                     AlterSchemaOwner_oid(sdepForm->objid, newrole);
    1365           1 :                     break;
    1366             : 
    1367             :                 case RelationRelationId:
    1368             : 
    1369             :                     /*
    1370             :                      * Pass recursing = true so that we don't fail on indexes,
    1371             :                      * owned sequences, etc when we happen to visit them
    1372             :                      * before their parent table.
    1373             :                      */
    1374           4 :                     ATExecChangeOwner(sdepForm->objid, newrole, true, AccessExclusiveLock);
    1375           4 :                     break;
    1376             : 
    1377             :                 case DefaultAclRelationId:
    1378             : 
    1379             :                     /*
    1380             :                      * Ignore default ACLs; they should be handled by DROP
    1381             :                      * OWNED, not REASSIGN OWNED.
    1382             :                      */
    1383           1 :                     break;
    1384             : 
    1385             :                 case UserMappingRelationId:
    1386             :                     /* ditto */
    1387           2 :                     break;
    1388             : 
    1389             :                 case ForeignServerRelationId:
    1390           2 :                     AlterForeignServerOwner_oid(sdepForm->objid, newrole);
    1391           2 :                     break;
    1392             : 
    1393             :                 case ForeignDataWrapperRelationId:
    1394           0 :                     AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole);
    1395           0 :                     break;
    1396             : 
    1397             :                 case EventTriggerRelationId:
    1398           0 :                     AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
    1399           0 :                     break;
    1400             : 
    1401             :                 case PublicationRelationId:
    1402           0 :                     AlterPublicationOwner_oid(sdepForm->objid, newrole);
    1403           0 :                     break;
    1404             : 
    1405             :                 case SubscriptionRelationId:
    1406           0 :                     AlterSubscriptionOwner_oid(sdepForm->objid, newrole);
    1407           0 :                     break;
    1408             : 
    1409             :                     /* Generic alter owner cases */
    1410             :                 case CollationRelationId:
    1411             :                 case ConversionRelationId:
    1412             :                 case OperatorRelationId:
    1413             :                 case ProcedureRelationId:
    1414             :                 case LanguageRelationId:
    1415             :                 case LargeObjectRelationId:
    1416             :                 case OperatorFamilyRelationId:
    1417             :                 case OperatorClassRelationId:
    1418             :                 case ExtensionRelationId:
    1419             :                 case StatisticExtRelationId:
    1420             :                 case TableSpaceRelationId:
    1421             :                 case DatabaseRelationId:
    1422             :                 case TSConfigRelationId:
    1423             :                 case TSDictionaryRelationId:
    1424             :                     {
    1425           1 :                         Oid         classId = sdepForm->classid;
    1426             :                         Relation    catalog;
    1427             : 
    1428           1 :                         if (classId == LargeObjectRelationId)
    1429           0 :                             classId = LargeObjectMetadataRelationId;
    1430             : 
    1431           1 :                         catalog = heap_open(classId, RowExclusiveLock);
    1432             : 
    1433           1 :                         AlterObjectOwner_internal(catalog, sdepForm->objid,
    1434             :                                                   newrole);
    1435             : 
    1436           1 :                         heap_close(catalog, NoLock);
    1437             :                     }
    1438           1 :                     break;
    1439             : 
    1440             :                 default:
    1441           0 :                     elog(ERROR, "unexpected classid %u", sdepForm->classid);
    1442             :                     break;
    1443             :             }
    1444             :             /* Make sure the next iteration will see my changes */
    1445          14 :             CommandCounterIncrement();
    1446             :         }
    1447             : 
    1448           2 :         systable_endscan(scan);
    1449             :     }
    1450             : 
    1451           2 :     heap_close(sdepRel, RowExclusiveLock);
    1452           2 : }

Generated by: LCOV version 1.11