PostgreSQL Source Code  git master
pg_shdepend.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_language.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shdepend.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_subscription.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_dict.h"
#include "catalog/pg_type.h"
#include "catalog/pg_user_mapping.h"
#include "commands/alter.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/policy.h"
#include "commands/publicationcmds.h"
#include "commands/schemacmds.h"
#include "commands/subscriptioncmds.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/typecmds.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
Include dependency graph for pg_shdepend.c:

Go to the source code of this file.

Data Structures

struct  ShDependObjectInfo
 
struct  remoteDep
 

Macros

#define MAX_REPORTED_DEPS   100
 

Enumerations

enum  SharedDependencyObjectType { LOCAL_OBJECT , SHARED_OBJECT , REMOTE_OBJECT }
 

Functions

static void getOidListDiff (Oid *list1, int *nlist1, Oid *list2, int *nlist2)
 
static Oid classIdGetDbId (Oid classId)
 
static void shdepChangeDep (Relation sdepRel, Oid classid, Oid objid, int32 objsubid, Oid refclassid, Oid refobjid, SharedDependencyType deptype)
 
static void updateAclDependenciesWorker (Oid classId, Oid objectId, int32 objsubId, Oid ownerId, SharedDependencyType deptype, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
 
static void shdepAddDependency (Relation sdepRel, Oid classId, Oid objectId, int32 objsubId, Oid refclassId, Oid refobjId, SharedDependencyType deptype)
 
static void shdepDropDependency (Relation sdepRel, Oid classId, Oid objectId, int32 objsubId, bool drop_subobjects, Oid refclassId, Oid refobjId, SharedDependencyType deptype)
 
static void storeObjectDescription (StringInfo descs, SharedDependencyObjectType type, ObjectAddress *object, SharedDependencyType deptype, int count)
 
void recordSharedDependencyOn (ObjectAddress *depender, ObjectAddress *referenced, SharedDependencyType deptype)
 
void recordDependencyOnOwner (Oid classId, Oid objectId, Oid owner)
 
void changeDependencyOnOwner (Oid classId, Oid objectId, Oid newOwnerId)
 
void recordDependencyOnTablespace (Oid classId, Oid objectId, Oid tablespace)
 
void changeDependencyOnTablespace (Oid classId, Oid objectId, Oid newTablespaceId)
 
void updateAclDependencies (Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
 
void updateInitAclDependencies (Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
 
static int shared_dependency_comparator (const void *a, const void *b)
 
bool checkSharedDependencies (Oid classId, Oid objectId, char **detail_msg, char **detail_log_msg)
 
void copyTemplateDependencies (Oid templateDbId, Oid newDbId)
 
void dropDatabaseDependencies (Oid databaseId)
 
void deleteSharedDependencyRecordsFor (Oid classId, Oid objectId, int32 objectSubId)
 
void shdepLockAndCheckObject (Oid classId, Oid objectId)
 
void shdepDropOwned (List *roleids, DropBehavior behavior)
 
void shdepReassignOwned (List *roleids, Oid newrole)
 

Macro Definition Documentation

◆ MAX_REPORTED_DEPS

#define MAX_REPORTED_DEPS   100

Enumeration Type Documentation

◆ SharedDependencyObjectType

Enumerator
LOCAL_OBJECT 
SHARED_OBJECT 
REMOTE_OBJECT 

Definition at line 67 of file pg_shdepend.c.

68 {
SharedDependencyObjectType
Definition: pg_shdepend.c:68
@ SHARED_OBJECT
Definition: pg_shdepend.c:70
@ LOCAL_OBJECT
Definition: pg_shdepend.c:69
@ REMOTE_OBJECT
Definition: pg_shdepend.c:71

Function Documentation

◆ changeDependencyOnOwner()

void changeDependencyOnOwner ( Oid  classId,
Oid  objectId,
Oid  newOwnerId 
)

Definition at line 313 of file pg_shdepend.c.

314 {
315  Relation sdepRel;
316 
317  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
318 
319  /* Adjust the SHARED_DEPENDENCY_OWNER entry */
320  shdepChangeDep(sdepRel,
321  classId, objectId, 0,
322  AuthIdRelationId, newOwnerId,
324 
325  /*----------
326  * There should never be a SHARED_DEPENDENCY_ACL entry for the owner,
327  * so get rid of it if there is one. This can happen if the new owner
328  * was previously granted some rights to the object.
329  *
330  * This step is analogous to aclnewowner's removal of duplicate entries
331  * in the ACL. We have to do it to handle this scenario:
332  * A grants some rights on an object to B
333  * ALTER OWNER changes the object's owner to B
334  * ALTER OWNER changes the object's owner to C
335  * The third step would remove all mention of B from the object's ACL,
336  * but we'd still have a SHARED_DEPENDENCY_ACL for B if we did not do
337  * things this way.
338  *
339  * The rule against having a SHARED_DEPENDENCY_ACL entry for the owner
340  * allows us to fix things up in just this one place, without having
341  * to make the various ALTER OWNER routines each know about it.
342  *----------
343  */
344  shdepDropDependency(sdepRel, classId, objectId, 0, true,
345  AuthIdRelationId, newOwnerId,
347 
348  /* The same applies to SHARED_DEPENDENCY_INITACL */
349  shdepDropDependency(sdepRel, classId, objectId, 0, true,
350  AuthIdRelationId, newOwnerId,
352 
353  table_close(sdepRel, RowExclusiveLock);
354 }
@ SHARED_DEPENDENCY_INITACL
Definition: dependency.h:82
@ SHARED_DEPENDENCY_ACL
Definition: dependency.h:81
@ SHARED_DEPENDENCY_OWNER
Definition: dependency.h:80
#define RowExclusiveLock
Definition: lockdefs.h:38
static void shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId, int32 objsubId, bool drop_subobjects, Oid refclassId, Oid refobjId, SharedDependencyType deptype)
Definition: pg_shdepend.c:1116
static void shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, int32 objsubid, Oid refclassid, Oid refobjid, SharedDependencyType deptype)
Definition: pg_shdepend.c:203
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References RowExclusiveLock, SHARED_DEPENDENCY_ACL, SHARED_DEPENDENCY_INITACL, SHARED_DEPENDENCY_OWNER, shdepChangeDep(), shdepDropDependency(), table_close(), and table_open().

Referenced by AlterDatabaseOwner(), AlterEventTriggerOwner_internal(), AlterForeignDataWrapperOwner_internal(), AlterForeignServerOwner_internal(), AlterObjectOwner_internal(), AlterPublicationOwner_internal(), AlterSchemaOwner_internal(), AlterSubscriptionOwner_internal(), AlterTypeOwner_oid(), and ATExecChangeOwner().

◆ changeDependencyOnTablespace()

void changeDependencyOnTablespace ( Oid  classId,
Oid  objectId,
Oid  newTablespaceId 
)

Definition at line 387 of file pg_shdepend.c.

388 {
389  Relation sdepRel;
390 
391  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
392 
393  if (newTablespaceId != DEFAULTTABLESPACE_OID &&
394  newTablespaceId != InvalidOid)
395  shdepChangeDep(sdepRel,
396  classId, objectId, 0,
397  TableSpaceRelationId, newTablespaceId,
399  else
400  shdepDropDependency(sdepRel,
401  classId, objectId, 0, true,
404 
405  table_close(sdepRel, RowExclusiveLock);
406 }
@ SHARED_DEPENDENCY_TABLESPACE
Definition: dependency.h:84
@ SHARED_DEPENDENCY_INVALID
Definition: dependency.h:85
#define InvalidOid
Definition: postgres_ext.h:36

References InvalidOid, RowExclusiveLock, SHARED_DEPENDENCY_INVALID, SHARED_DEPENDENCY_TABLESPACE, shdepChangeDep(), shdepDropDependency(), table_close(), and table_open().

Referenced by SetRelationTableSpace().

◆ checkSharedDependencies()

bool checkSharedDependencies ( Oid  classId,
Oid  objectId,
char **  detail_msg,
char **  detail_log_msg 
)

Definition at line 668 of file pg_shdepend.c.

670 {
671  Relation sdepRel;
672  ScanKeyData key[2];
673  SysScanDesc scan;
674  HeapTuple tup;
675  int numReportedDeps = 0;
676  int numNotReportedDeps = 0;
677  int numNotReportedDbs = 0;
678  List *remDeps = NIL;
679  ListCell *cell;
680  ObjectAddress object;
681  ShDependObjectInfo *objects;
682  int numobjects;
683  int allocedobjects;
684  StringInfoData descs;
685  StringInfoData alldescs;
686 
687  /* This case can be dispatched quickly */
688  if (IsPinnedObject(classId, objectId))
689  {
690  object.classId = classId;
691  object.objectId = objectId;
692  object.objectSubId = 0;
693  ereport(ERROR,
694  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
695  errmsg("cannot drop %s because it is required by the database system",
696  getObjectDescription(&object, false))));
697  }
698 
699  /*
700  * We limit the number of dependencies reported to the client to
701  * MAX_REPORTED_DEPS, since client software may not deal well with
702  * enormous error strings. The server log always gets a full report.
703  *
704  * For stability of regression test results, we sort local and shared
705  * objects by OID before reporting them. We don't worry about the order
706  * in which other databases are reported, though.
707  */
708 #define MAX_REPORTED_DEPS 100
709 
710  allocedobjects = 128; /* arbitrary initial array size */
711  objects = (ShDependObjectInfo *)
712  palloc(allocedobjects * sizeof(ShDependObjectInfo));
713  numobjects = 0;
714  initStringInfo(&descs);
715  initStringInfo(&alldescs);
716 
717  sdepRel = table_open(SharedDependRelationId, AccessShareLock);
718 
719  ScanKeyInit(&key[0],
720  Anum_pg_shdepend_refclassid,
721  BTEqualStrategyNumber, F_OIDEQ,
722  ObjectIdGetDatum(classId));
723  ScanKeyInit(&key[1],
724  Anum_pg_shdepend_refobjid,
725  BTEqualStrategyNumber, F_OIDEQ,
726  ObjectIdGetDatum(objectId));
727 
728  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
729  NULL, 2, key);
730 
731  while (HeapTupleIsValid(tup = systable_getnext(scan)))
732  {
733  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
734 
735  object.classId = sdepForm->classid;
736  object.objectId = sdepForm->objid;
737  object.objectSubId = sdepForm->objsubid;
738 
739  /*
740  * If it's a dependency local to this database or it's a shared
741  * object, add it to the objects array.
742  *
743  * If it's a remote dependency, keep track of it so we can report the
744  * number of them later.
745  */
746  if (sdepForm->dbid == MyDatabaseId ||
747  sdepForm->dbid == InvalidOid)
748  {
749  if (numobjects >= allocedobjects)
750  {
751  allocedobjects *= 2;
752  objects = (ShDependObjectInfo *)
753  repalloc(objects,
754  allocedobjects * sizeof(ShDependObjectInfo));
755  }
756  objects[numobjects].object = object;
757  objects[numobjects].deptype = sdepForm->deptype;
758  objects[numobjects].objtype = (sdepForm->dbid == MyDatabaseId) ?
760  numobjects++;
761  }
762  else
763  {
764  /* It's not local nor shared, so it must be remote. */
765  remoteDep *dep;
766  bool stored = false;
767 
768  /*
769  * XXX this info is kept on a simple List. Maybe it's not good
770  * for performance, but using a hash table seems needlessly
771  * complex. The expected number of databases is not high anyway,
772  * I suppose.
773  */
774  foreach(cell, remDeps)
775  {
776  dep = lfirst(cell);
777  if (dep->dbOid == sdepForm->dbid)
778  {
779  dep->count++;
780  stored = true;
781  break;
782  }
783  }
784  if (!stored)
785  {
786  dep = (remoteDep *) palloc(sizeof(remoteDep));
787  dep->dbOid = sdepForm->dbid;
788  dep->count = 1;
789  remDeps = lappend(remDeps, dep);
790  }
791  }
792  }
793 
794  systable_endscan(scan);
795 
796  table_close(sdepRel, AccessShareLock);
797 
798  /*
799  * Sort and report local and shared objects.
800  */
801  if (numobjects > 1)
802  qsort(objects, numobjects,
804 
805  for (int i = 0; i < numobjects; i++)
806  {
807  if (numReportedDeps < MAX_REPORTED_DEPS)
808  {
809  numReportedDeps++;
810  storeObjectDescription(&descs,
811  objects[i].objtype,
812  &objects[i].object,
813  objects[i].deptype,
814  0);
815  }
816  else
817  numNotReportedDeps++;
818  storeObjectDescription(&alldescs,
819  objects[i].objtype,
820  &objects[i].object,
821  objects[i].deptype,
822  0);
823  }
824 
825  /*
826  * Summarize dependencies in remote databases.
827  */
828  foreach(cell, remDeps)
829  {
830  remoteDep *dep = lfirst(cell);
831 
832  object.classId = DatabaseRelationId;
833  object.objectId = dep->dbOid;
834  object.objectSubId = 0;
835 
836  if (numReportedDeps < MAX_REPORTED_DEPS)
837  {
838  numReportedDeps++;
839  storeObjectDescription(&descs, REMOTE_OBJECT, &object,
841  }
842  else
843  numNotReportedDbs++;
844  storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
846  }
847 
848  pfree(objects);
849  list_free_deep(remDeps);
850 
851  if (descs.len == 0)
852  {
853  pfree(descs.data);
854  pfree(alldescs.data);
855  *detail_msg = *detail_log_msg = NULL;
856  return false;
857  }
858 
859  if (numNotReportedDeps > 0)
860  appendStringInfo(&descs, ngettext("\nand %d other object "
861  "(see server log for list)",
862  "\nand %d other objects "
863  "(see server log for list)",
864  numNotReportedDeps),
865  numNotReportedDeps);
866  if (numNotReportedDbs > 0)
867  appendStringInfo(&descs, ngettext("\nand objects in %d other database "
868  "(see server log for list)",
869  "\nand objects in %d other databases "
870  "(see server log for list)",
871  numNotReportedDbs),
872  numNotReportedDbs);
873 
874  *detail_msg = descs.data;
875  *detail_log_msg = alldescs.data;
876  return true;
877 }
#define ngettext(s, p, n)
Definition: c.h:1181
bool IsPinnedObject(Oid classId, Oid objectId)
Definition: catalog.c:313
int errcode(int sqlerrcode)
Definition: elog.c:857
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
Oid MyDatabaseId
Definition: globals.c:91
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
int i
Definition: isn.c:73
List * lappend(List *list, void *datum)
Definition: list.c:339
void list_free_deep(List *list)
Definition: list.c:1560
#define AccessShareLock
Definition: lockdefs.h:36
void pfree(void *pointer)
Definition: mcxt.c:1520
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1540
void * palloc(Size size)
Definition: mcxt.c:1316
char * getObjectDescription(const ObjectAddress *object, bool missing_ok)
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
static int shared_dependency_comparator(const void *a, const void *b)
Definition: pg_shdepend.c:602
#define MAX_REPORTED_DEPS
static void storeObjectDescription(StringInfo descs, SharedDependencyObjectType type, ObjectAddress *object, SharedDependencyType deptype, int count)
Definition: pg_shdepend.c:1268
FormData_pg_shdepend * Form_pg_shdepend
Definition: pg_shdepend.h:73
#define qsort(a, b, c, d)
Definition: port.h:449
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Definition: pg_list.h:54
ObjectAddress object
Definition: pg_shdepend.c:76
SharedDependencyObjectType objtype
Definition: pg_shdepend.c:78

References AccessShareLock, appendStringInfo(), BTEqualStrategyNumber, remoteDep::count, StringInfoData::data, remoteDep::dbOid, ShDependObjectInfo::deptype, ereport, errcode(), errmsg(), ERROR, getObjectDescription(), GETSTRUCT, HeapTupleIsValid, i, initStringInfo(), InvalidOid, IsPinnedObject(), sort-test::key, lappend(), StringInfoData::len, lfirst, list_free_deep(), LOCAL_OBJECT, MAX_REPORTED_DEPS, MyDatabaseId, ngettext, NIL, ShDependObjectInfo::object, ObjectIdGetDatum(), ShDependObjectInfo::objtype, palloc(), pfree(), qsort, REMOTE_OBJECT, repalloc(), ScanKeyInit(), shared_dependency_comparator(), SHARED_DEPENDENCY_INVALID, SHARED_OBJECT, storeObjectDescription(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by DropRole(), and DropTableSpace().

◆ classIdGetDbId()

static Oid classIdGetDbId ( Oid  classId)
static

Definition at line 1182 of file pg_shdepend.c.

1183 {
1184  Oid dbId;
1185 
1186  if (IsSharedRelation(classId))
1187  dbId = InvalidOid;
1188  else
1189  dbId = MyDatabaseId;
1190 
1191  return dbId;
1192 }
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:243
unsigned int Oid
Definition: postgres_ext.h:31

References InvalidOid, IsSharedRelation(), and MyDatabaseId.

Referenced by shdepAddDependency(), shdepChangeDep(), and shdepDropDependency().

◆ copyTemplateDependencies()

void copyTemplateDependencies ( Oid  templateDbId,
Oid  newDbId 
)

Definition at line 887 of file pg_shdepend.c.

888 {
889  Relation sdepRel;
890  TupleDesc sdepDesc;
891  ScanKeyData key[1];
892  SysScanDesc scan;
893  HeapTuple tup;
894  CatalogIndexState indstate;
895  TupleTableSlot **slot;
896  int max_slots,
897  slot_init_count,
898  slot_stored_count;
899 
900  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
901  sdepDesc = RelationGetDescr(sdepRel);
902 
903  /*
904  * Allocate the slots to use, but delay costly initialization until we
905  * know that they will be used.
906  */
908  slot = palloc(sizeof(TupleTableSlot *) * max_slots);
909 
910  indstate = CatalogOpenIndexes(sdepRel);
911 
912  /* Scan all entries with dbid = templateDbId */
913  ScanKeyInit(&key[0],
914  Anum_pg_shdepend_dbid,
915  BTEqualStrategyNumber, F_OIDEQ,
916  ObjectIdGetDatum(templateDbId));
917 
918  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
919  NULL, 1, key);
920 
921  /* number of slots currently storing tuples */
922  slot_stored_count = 0;
923  /* number of slots currently initialized */
924  slot_init_count = 0;
925 
926  /*
927  * Copy the entries of the original database, changing the database Id to
928  * that of the new database. Note that because we are not copying rows
929  * with dbId == 0 (ie, rows describing dependent shared objects) we won't
930  * copy the ownership dependency of the template database itself; this is
931  * what we want.
932  */
933  while (HeapTupleIsValid(tup = systable_getnext(scan)))
934  {
935  Form_pg_shdepend shdep;
936 
937  if (slot_init_count < max_slots)
938  {
939  slot[slot_stored_count] = MakeSingleTupleTableSlot(sdepDesc, &TTSOpsHeapTuple);
940  slot_init_count++;
941  }
942 
943  ExecClearTuple(slot[slot_stored_count]);
944 
945  memset(slot[slot_stored_count]->tts_isnull, false,
946  slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
947 
948  shdep = (Form_pg_shdepend) GETSTRUCT(tup);
949 
950  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);
951  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_classid - 1] = shdep->classid;
952  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objid - 1] = shdep->objid;
953  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objsubid - 1] = shdep->objsubid;
954  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refclassid - 1] = shdep->refclassid;
955  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refobjid - 1] = shdep->refobjid;
956  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_deptype - 1] = shdep->deptype;
957 
958  ExecStoreVirtualTuple(slot[slot_stored_count]);
959  slot_stored_count++;
960 
961  /* If slots are full, insert a batch of tuples */
962  if (slot_stored_count == max_slots)
963  {
964  CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate);
965  slot_stored_count = 0;
966  }
967  }
968 
969  /* Insert any tuples left in the buffer */
970  if (slot_stored_count > 0)
971  CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate);
972 
973  systable_endscan(scan);
974 
975  CatalogCloseIndexes(indstate);
976  table_close(sdepRel, RowExclusiveLock);
977 
978  /* Drop only the number of slots used */
979  for (int i = 0; i < slot_init_count; i++)
981  pfree(slot);
982 }
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1639
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1325
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:273
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
#define MAX_CATALOG_MULTI_INSERT_BYTES
Definition: indexing.h:33
FormData_pg_shdepend
Definition: pg_shdepend.h:66
#define RelationGetDescr(relation)
Definition: rel.h:531
Datum * tts_values
Definition: tuptable.h:125
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454

References BTEqualStrategyNumber, CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTuplesMultiInsertWithInfo(), ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecStoreVirtualTuple(), FormData_pg_shdepend, GETSTRUCT, HeapTupleIsValid, i, sort-test::key, MakeSingleTupleTableSlot(), MAX_CATALOG_MULTI_INSERT_BYTES, ObjectIdGetDatum(), palloc(), pfree(), RelationGetDescr, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TupleTableSlot::tts_values, and TTSOpsHeapTuple.

Referenced by createdb().

◆ deleteSharedDependencyRecordsFor()

void deleteSharedDependencyRecordsFor ( Oid  classId,
Oid  objectId,
int32  objectSubId 
)

Definition at line 1039 of file pg_shdepend.c.

1040 {
1041  Relation sdepRel;
1042 
1043  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1044 
1045  shdepDropDependency(sdepRel, classId, objectId, objectSubId,
1046  (objectSubId == 0),
1049 
1050  table_close(sdepRel, RowExclusiveLock);
1051 }

References InvalidOid, RowExclusiveLock, SHARED_DEPENDENCY_INVALID, shdepDropDependency(), table_close(), and table_open().

Referenced by AlterPolicy(), deleteOneObject(), DelRoleMems(), DropRole(), DropSubscription(), DropTableSpace(), GenerateTypeDependencies(), makeConfigurationDependencies(), makeOperatorDependencies(), and RemoveRoleFromObjectPolicy().

◆ dropDatabaseDependencies()

void dropDatabaseDependencies ( Oid  databaseId)

Definition at line 991 of file pg_shdepend.c.

992 {
993  Relation sdepRel;
994  ScanKeyData key[1];
995  SysScanDesc scan;
996  HeapTuple tup;
997 
998  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
999 
1000  /*
1001  * First, delete all the entries that have the database Oid in the dbid
1002  * field.
1003  */
1004  ScanKeyInit(&key[0],
1005  Anum_pg_shdepend_dbid,
1006  BTEqualStrategyNumber, F_OIDEQ,
1007  ObjectIdGetDatum(databaseId));
1008  /* We leave the other index fields unspecified */
1009 
1010  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
1011  NULL, 1, key);
1012 
1013  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1014  {
1015  CatalogTupleDelete(sdepRel, &tup->t_self);
1016  }
1017 
1018  systable_endscan(scan);
1019 
1020  /* Now delete all entries corresponding to the database itself */
1021  shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true,
1024 
1025  table_close(sdepRel, RowExclusiveLock);
1026 }
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
ItemPointerData t_self
Definition: htup.h:65

References BTEqualStrategyNumber, CatalogTupleDelete(), HeapTupleIsValid, InvalidOid, sort-test::key, ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), SHARED_DEPENDENCY_INVALID, shdepDropDependency(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by dropdb().

◆ getOidListDiff()

static void getOidListDiff ( Oid list1,
int *  nlist1,
Oid list2,
int *  nlist2 
)
static

Definition at line 417 of file pg_shdepend.c.

418 {
419  int in1,
420  in2,
421  out1,
422  out2;
423 
424  in1 = in2 = out1 = out2 = 0;
425  while (in1 < *nlist1 && in2 < *nlist2)
426  {
427  if (list1[in1] == list2[in2])
428  {
429  /* skip over duplicates */
430  in1++;
431  in2++;
432  }
433  else if (list1[in1] < list2[in2])
434  {
435  /* list1[in1] is not in list2 */
436  list1[out1++] = list1[in1++];
437  }
438  else
439  {
440  /* list2[in2] is not in list1 */
441  list2[out2++] = list2[in2++];
442  }
443  }
444 
445  /* any remaining list1 entries are not in list2 */
446  while (in1 < *nlist1)
447  {
448  list1[out1++] = list1[in1++];
449  }
450 
451  /* any remaining list2 entries are not in list1 */
452  while (in2 < *nlist2)
453  {
454  list2[out2++] = list2[in2++];
455  }
456 
457  *nlist1 = out1;
458  *nlist2 = out2;
459 }

Referenced by updateAclDependenciesWorker().

◆ recordDependencyOnOwner()

void recordDependencyOnOwner ( Oid  classId,
Oid  objectId,
Oid  owner 
)

◆ recordDependencyOnTablespace()

void recordDependencyOnTablespace ( Oid  classId,
Oid  objectId,
Oid  tablespace 
)

Definition at line 366 of file pg_shdepend.c.

367 {
368  ObjectAddress myself,
369  referenced;
370 
371  ObjectAddressSet(myself, classId, objectId);
372  ObjectAddressSet(referenced, TableSpaceRelationId, tablespace);
373 
374  recordSharedDependencyOn(&myself, &referenced,
376 }
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
char * tablespace
Definition: pgbench.c:216

References ObjectAddressSet, recordSharedDependencyOn(), SHARED_DEPENDENCY_TABLESPACE, and tablespace.

Referenced by heap_create().

◆ recordSharedDependencyOn()

void recordSharedDependencyOn ( ObjectAddress depender,
ObjectAddress referenced,
SharedDependencyType  deptype 
)

Definition at line 122 of file pg_shdepend.c.

125 {
126  Relation sdepRel;
127 
128  /*
129  * Objects in pg_shdepend can't have SubIds.
130  */
131  Assert(depender->objectSubId == 0);
132  Assert(referenced->objectSubId == 0);
133 
134  /*
135  * During bootstrap, do nothing since pg_shdepend may not exist yet.
136  * initdb will fill in appropriate pg_shdepend entries after bootstrap.
137  */
139  return;
140 
141  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
142 
143  /* If the referenced object is pinned, do nothing. */
144  if (!IsPinnedObject(referenced->classId, referenced->objectId))
145  {
146  shdepAddDependency(sdepRel, depender->classId, depender->objectId,
147  depender->objectSubId,
148  referenced->classId, referenced->objectId,
149  deptype);
150  }
151 
152  table_close(sdepRel, RowExclusiveLock);
153 }
#define Assert(condition)
Definition: c.h:858
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:454
static void shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId, int32 objsubId, Oid refclassId, Oid refobjId, SharedDependencyType deptype)
Definition: pg_shdepend.c:1061

References Assert, ObjectAddress::classId, IsBootstrapProcessingMode, IsPinnedObject(), ObjectAddress::objectId, ObjectAddress::objectSubId, RowExclusiveLock, shdepAddDependency(), table_close(), and table_open().

Referenced by AlterPolicy(), CreatePolicy(), recordDependencyOnOwner(), recordDependencyOnTablespace(), and RemoveRoleFromObjectPolicy().

◆ shared_dependency_comparator()

static int shared_dependency_comparator ( const void *  a,
const void *  b 
)
static

Definition at line 602 of file pg_shdepend.c.

603 {
604  const ShDependObjectInfo *obja = (const ShDependObjectInfo *) a;
605  const ShDependObjectInfo *objb = (const ShDependObjectInfo *) b;
606 
607  /*
608  * Primary sort key is OID ascending.
609  */
610  if (obja->object.objectId < objb->object.objectId)
611  return -1;
612  if (obja->object.objectId > objb->object.objectId)
613  return 1;
614 
615  /*
616  * Next sort on catalog ID, in case identical OIDs appear in different
617  * catalogs. Sort direction is pretty arbitrary here.
618  */
619  if (obja->object.classId < objb->object.classId)
620  return -1;
621  if (obja->object.classId > objb->object.classId)
622  return 1;
623 
624  /*
625  * Sort on object subId.
626  *
627  * We sort the subId as an unsigned int so that 0 (the whole object) will
628  * come first.
629  */
630  if ((unsigned int) obja->object.objectSubId < (unsigned int) objb->object.objectSubId)
631  return -1;
632  if ((unsigned int) obja->object.objectSubId > (unsigned int) objb->object.objectSubId)
633  return 1;
634 
635  /*
636  * Last, sort on deptype, in case the same object has multiple dependency
637  * types. (Note that there's no need to consider objtype, as that's
638  * determined by the catalog OID.)
639  */
640  if (obja->deptype < objb->deptype)
641  return -1;
642  if (obja->deptype > objb->deptype)
643  return 1;
644 
645  return 0;
646 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, b, ObjectAddress::classId, ShDependObjectInfo::deptype, ShDependObjectInfo::object, ObjectAddress::objectId, and ObjectAddress::objectSubId.

Referenced by checkSharedDependencies().

◆ shdepAddDependency()

static void shdepAddDependency ( Relation  sdepRel,
Oid  classId,
Oid  objectId,
int32  objsubId,
Oid  refclassId,
Oid  refobjId,
SharedDependencyType  deptype 
)
static

Definition at line 1061 of file pg_shdepend.c.

1065 {
1066  HeapTuple tup;
1067  Datum values[Natts_pg_shdepend];
1068  bool nulls[Natts_pg_shdepend];
1069 
1070  /*
1071  * Make sure the object doesn't go away while we record the dependency on
1072  * it. DROP routines should lock the object exclusively before they check
1073  * shared dependencies.
1074  */
1075  shdepLockAndCheckObject(refclassId, refobjId);
1076 
1077  memset(nulls, false, sizeof(nulls));
1078 
1079  /*
1080  * Form the new tuple and record the dependency.
1081  */
1082  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
1083  values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
1084  values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
1085  values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId);
1086 
1087  values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
1088  values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
1089  values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
1090 
1091  tup = heap_form_tuple(sdepRel->rd_att, values, nulls);
1092 
1093  CatalogTupleInsert(sdepRel, tup);
1094 
1095  /* clean up */
1096  heap_freetuple(tup);
1097 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
static Oid classIdGetDbId(Oid classId)
Definition: pg_shdepend.c:1182
void shdepLockAndCheckObject(Oid classId, Oid objectId)
Definition: pg_shdepend.c:1203
uintptr_t Datum
Definition: postgres.h:64
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:122
TupleDesc rd_att
Definition: rel.h:112

References CatalogTupleInsert(), CharGetDatum(), classIdGetDbId(), heap_form_tuple(), heap_freetuple(), Int32GetDatum(), ObjectIdGetDatum(), RelationData::rd_att, shdepLockAndCheckObject(), and values.

Referenced by recordSharedDependencyOn(), and updateAclDependenciesWorker().

◆ shdepChangeDep()

static void shdepChangeDep ( Relation  sdepRel,
Oid  classid,
Oid  objid,
int32  objsubid,
Oid  refclassid,
Oid  refobjid,
SharedDependencyType  deptype 
)
static

Definition at line 203 of file pg_shdepend.c.

207 {
208  Oid dbid = classIdGetDbId(classid);
209  HeapTuple oldtup = NULL;
210  HeapTuple scantup;
211  ScanKeyData key[4];
212  SysScanDesc scan;
213 
214  /*
215  * Make sure the new referenced object doesn't go away while we record the
216  * dependency.
217  */
218  shdepLockAndCheckObject(refclassid, refobjid);
219 
220  /*
221  * Look for a previous entry
222  */
223  ScanKeyInit(&key[0],
224  Anum_pg_shdepend_dbid,
225  BTEqualStrategyNumber, F_OIDEQ,
226  ObjectIdGetDatum(dbid));
227  ScanKeyInit(&key[1],
228  Anum_pg_shdepend_classid,
229  BTEqualStrategyNumber, F_OIDEQ,
230  ObjectIdGetDatum(classid));
231  ScanKeyInit(&key[2],
232  Anum_pg_shdepend_objid,
233  BTEqualStrategyNumber, F_OIDEQ,
234  ObjectIdGetDatum(objid));
235  ScanKeyInit(&key[3],
236  Anum_pg_shdepend_objsubid,
237  BTEqualStrategyNumber, F_INT4EQ,
238  Int32GetDatum(objsubid));
239 
240  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
241  NULL, 4, key);
242 
243  while ((scantup = systable_getnext(scan)) != NULL)
244  {
245  /* Ignore if not of the target dependency type */
246  if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype)
247  continue;
248  /* Caller screwed up if multiple matches */
249  if (oldtup)
250  elog(ERROR,
251  "multiple pg_shdepend entries for object %u/%u/%d deptype %c",
252  classid, objid, objsubid, deptype);
253  oldtup = heap_copytuple(scantup);
254  }
255 
256  systable_endscan(scan);
257 
258  if (IsPinnedObject(refclassid, refobjid))
259  {
260  /* No new entry needed, so just delete existing entry if any */
261  if (oldtup)
262  CatalogTupleDelete(sdepRel, &oldtup->t_self);
263  }
264  else if (oldtup)
265  {
266  /* Need to update existing entry */
267  Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup);
268 
269  /* Since oldtup is a copy, we can just modify it in-memory */
270  shForm->refclassid = refclassid;
271  shForm->refobjid = refobjid;
272 
273  CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup);
274  }
275  else
276  {
277  /* Need to insert new entry */
278  Datum values[Natts_pg_shdepend];
279  bool nulls[Natts_pg_shdepend];
280 
281  memset(nulls, false, sizeof(nulls));
282 
283  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid);
284  values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid);
285  values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid);
286  values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubid);
287 
288  values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid);
289  values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid);
290  values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
291 
292  /*
293  * we are reusing oldtup just to avoid declaring a new variable, but
294  * it's certainly a new tuple
295  */
296  oldtup = heap_form_tuple(RelationGetDescr(sdepRel), values, nulls);
297  CatalogTupleInsert(sdepRel, oldtup);
298  }
299 
300  if (oldtup)
301  heap_freetuple(oldtup);
302 }
#define elog(elevel,...)
Definition: elog.h:224
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313

References BTEqualStrategyNumber, CatalogTupleDelete(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum(), classIdGetDbId(), elog, ERROR, GETSTRUCT, heap_copytuple(), heap_form_tuple(), heap_freetuple(), Int32GetDatum(), IsPinnedObject(), sort-test::key, ObjectIdGetDatum(), RelationGetDescr, ScanKeyInit(), shdepLockAndCheckObject(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, and values.

Referenced by changeDependencyOnOwner(), and changeDependencyOnTablespace().

◆ shdepDropDependency()

static void shdepDropDependency ( Relation  sdepRel,
Oid  classId,
Oid  objectId,
int32  objsubId,
bool  drop_subobjects,
Oid  refclassId,
Oid  refobjId,
SharedDependencyType  deptype 
)
static

Definition at line 1116 of file pg_shdepend.c.

1121 {
1122  ScanKeyData key[4];
1123  int nkeys;
1124  SysScanDesc scan;
1125  HeapTuple tup;
1126 
1127  /* Scan for entries matching the dependent object */
1128  ScanKeyInit(&key[0],
1129  Anum_pg_shdepend_dbid,
1130  BTEqualStrategyNumber, F_OIDEQ,
1131  ObjectIdGetDatum(classIdGetDbId(classId)));
1132  ScanKeyInit(&key[1],
1133  Anum_pg_shdepend_classid,
1134  BTEqualStrategyNumber, F_OIDEQ,
1135  ObjectIdGetDatum(classId));
1136  ScanKeyInit(&key[2],
1137  Anum_pg_shdepend_objid,
1138  BTEqualStrategyNumber, F_OIDEQ,
1139  ObjectIdGetDatum(objectId));
1140  if (drop_subobjects)
1141  nkeys = 3;
1142  else
1143  {
1144  ScanKeyInit(&key[3],
1145  Anum_pg_shdepend_objsubid,
1146  BTEqualStrategyNumber, F_INT4EQ,
1147  Int32GetDatum(objsubId));
1148  nkeys = 4;
1149  }
1150 
1151  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
1152  NULL, nkeys, key);
1153 
1154  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1155  {
1156  Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
1157 
1158  /* Filter entries according to additional parameters */
1159  if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId)
1160  continue;
1161  if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId)
1162  continue;
1163  if (deptype != SHARED_DEPENDENCY_INVALID &&
1164  shdepForm->deptype != deptype)
1165  continue;
1166 
1167  /* OK, delete it */
1168  CatalogTupleDelete(sdepRel, &tup->t_self);
1169  }
1170 
1171  systable_endscan(scan);
1172 }
#define OidIsValid(objectId)
Definition: c.h:775

References BTEqualStrategyNumber, CatalogTupleDelete(), classIdGetDbId(), GETSTRUCT, HeapTupleIsValid, Int32GetDatum(), sort-test::key, ObjectIdGetDatum(), OidIsValid, ScanKeyInit(), SHARED_DEPENDENCY_INVALID, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.

Referenced by changeDependencyOnOwner(), changeDependencyOnTablespace(), deleteSharedDependencyRecordsFor(), dropDatabaseDependencies(), and updateAclDependenciesWorker().

◆ shdepDropOwned()

void shdepDropOwned ( List roleids,
DropBehavior  behavior 
)

Definition at line 1334 of file pg_shdepend.c.

1335 {
1336  Relation sdepRel;
1337  ListCell *cell;
1338  ObjectAddresses *deleteobjs;
1339 
1340  deleteobjs = new_object_addresses();
1341 
1342  /*
1343  * We don't need this strong a lock here, but we'll call routines that
1344  * acquire RowExclusiveLock. Better get that right now to avoid potential
1345  * deadlock failures.
1346  */
1347  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1348 
1349  /*
1350  * For each role, find the dependent objects and drop them using the
1351  * regular (non-shared) dependency management.
1352  */
1353  foreach(cell, roleids)
1354  {
1355  Oid roleid = lfirst_oid(cell);
1356  ScanKeyData key[2];
1357  SysScanDesc scan;
1358  HeapTuple tuple;
1359 
1360  /* Doesn't work for pinned objects */
1361  if (IsPinnedObject(AuthIdRelationId, roleid))
1362  {
1363  ObjectAddress obj;
1364 
1365  obj.classId = AuthIdRelationId;
1366  obj.objectId = roleid;
1367  obj.objectSubId = 0;
1368 
1369  ereport(ERROR,
1370  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1371  errmsg("cannot drop objects owned by %s because they are "
1372  "required by the database system",
1373  getObjectDescription(&obj, false))));
1374  }
1375 
1376  ScanKeyInit(&key[0],
1377  Anum_pg_shdepend_refclassid,
1378  BTEqualStrategyNumber, F_OIDEQ,
1379  ObjectIdGetDatum(AuthIdRelationId));
1380  ScanKeyInit(&key[1],
1381  Anum_pg_shdepend_refobjid,
1382  BTEqualStrategyNumber, F_OIDEQ,
1383  ObjectIdGetDatum(roleid));
1384 
1385  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1386  NULL, 2, key);
1387 
1388  while ((tuple = systable_getnext(scan)) != NULL)
1389  {
1390  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
1391  ObjectAddress obj;
1392 
1393  /*
1394  * We only operate on shared objects and objects in the current
1395  * database
1396  */
1397  if (sdepForm->dbid != MyDatabaseId &&
1398  sdepForm->dbid != InvalidOid)
1399  continue;
1400 
1401  switch (sdepForm->deptype)
1402  {
1403  /* Shouldn't happen */
1405  elog(ERROR, "unexpected dependency type");
1406  break;
1408 
1409  /*
1410  * Try to remove role from policy; if unable to, remove
1411  * policy.
1412  */
1413  if (!RemoveRoleFromObjectPolicy(roleid,
1414  sdepForm->classid,
1415  sdepForm->objid))
1416  {
1417  obj.classId = sdepForm->classid;
1418  obj.objectId = sdepForm->objid;
1419  obj.objectSubId = sdepForm->objsubid;
1420 
1421  /*
1422  * Acquire lock on object, then verify this dependency
1423  * is still relevant. If not, the object might have
1424  * been dropped or the policy modified. Ignore the
1425  * object in that case.
1426  */
1427  AcquireDeletionLock(&obj, 0);
1428  if (!systable_recheck_tuple(scan, tuple))
1429  {
1430  ReleaseDeletionLock(&obj);
1431  break;
1432  }
1433  add_exact_object_address(&obj, deleteobjs);
1434  }
1435  break;
1436  case SHARED_DEPENDENCY_ACL:
1437 
1438  /*
1439  * Dependencies on role grants are recorded using
1440  * SHARED_DEPENDENCY_ACL, but unlike a regular ACL list
1441  * which stores all permissions for a particular object in
1442  * a single ACL array, there's a separate catalog row for
1443  * each grant - so removing the grant just means removing
1444  * the entire row.
1445  */
1446  if (sdepForm->classid != AuthMemRelationId)
1447  {
1448  RemoveRoleFromObjectACL(roleid,
1449  sdepForm->classid,
1450  sdepForm->objid);
1451  break;
1452  }
1453  /* FALLTHROUGH */
1454 
1456 
1457  /*
1458  * Save it for deletion below, if it's a local object or a
1459  * role grant. Other shared objects, such as databases,
1460  * should not be removed here.
1461  */
1462  if (sdepForm->dbid == MyDatabaseId ||
1463  sdepForm->classid == AuthMemRelationId)
1464  {
1465  obj.classId = sdepForm->classid;
1466  obj.objectId = sdepForm->objid;
1467  obj.objectSubId = sdepForm->objsubid;
1468  /* as above */
1469  AcquireDeletionLock(&obj, 0);
1470  if (!systable_recheck_tuple(scan, tuple))
1471  {
1472  ReleaseDeletionLock(&obj);
1473  break;
1474  }
1475  add_exact_object_address(&obj, deleteobjs);
1476  }
1477  break;
1479  /* Shouldn't see a role grant here */
1480  Assert(sdepForm->classid != AuthMemRelationId);
1481  RemoveRoleFromInitPriv(roleid,
1482  sdepForm->classid,
1483  sdepForm->objid,
1484  sdepForm->objsubid);
1485  break;
1486  }
1487  }
1488 
1489  systable_endscan(scan);
1490  }
1491 
1492  /*
1493  * For stability of deletion-report ordering, sort the objects into
1494  * approximate reverse creation order before deletion. (This might also
1495  * make the deletion go a bit faster, since there's less chance of having
1496  * to rearrange the objects due to dependencies.)
1497  */
1498  sort_object_addresses(deleteobjs);
1499 
1500  /* the dependency mechanism does the actual work */
1501  performMultipleDeletions(deleteobjs, behavior, 0);
1502 
1503  table_close(sdepRel, RowExclusiveLock);
1504 
1505  free_object_addresses(deleteobjs);
1506 }
void RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
Definition: aclchk.c:4855
void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
Definition: aclchk.c:1465
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:332
void sort_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2759
void AcquireDeletionLock(const ObjectAddress *object, int flags)
Definition: dependency.c:1494
void ReleaseDeletionLock(const ObjectAddress *object)
Definition: dependency.c:1526
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2485
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2531
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2771
@ SHARED_DEPENDENCY_POLICY
Definition: dependency.h:83
bool systable_recheck_tuple(SysScanDesc sysscan, HeapTuple tup)
Definition: genam.c:562
#define lfirst_oid(lc)
Definition: pg_list.h:174
bool RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
Definition: policy.c:416

References AcquireDeletionLock(), add_exact_object_address(), Assert, BTEqualStrategyNumber, ObjectAddress::classId, elog, ereport, errcode(), errmsg(), ERROR, free_object_addresses(), getObjectDescription(), GETSTRUCT, InvalidOid, IsPinnedObject(), sort-test::key, lfirst_oid, MyDatabaseId, new_object_addresses(), ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, performMultipleDeletions(), ReleaseDeletionLock(), RemoveRoleFromInitPriv(), RemoveRoleFromObjectACL(), RemoveRoleFromObjectPolicy(), RowExclusiveLock, ScanKeyInit(), SHARED_DEPENDENCY_ACL, SHARED_DEPENDENCY_INITACL, SHARED_DEPENDENCY_INVALID, SHARED_DEPENDENCY_OWNER, SHARED_DEPENDENCY_POLICY, sort_object_addresses(), systable_beginscan(), systable_endscan(), systable_getnext(), systable_recheck_tuple(), table_close(), and table_open().

Referenced by DropOwnedObjects().

◆ shdepLockAndCheckObject()

void shdepLockAndCheckObject ( Oid  classId,
Oid  objectId 
)

Definition at line 1203 of file pg_shdepend.c.

1204 {
1205  /* AccessShareLock should be OK, since we are not modifying the object */
1206  LockSharedObject(classId, objectId, 0, AccessShareLock);
1207 
1208  switch (classId)
1209  {
1210  case AuthIdRelationId:
1211  if (!SearchSysCacheExists1(AUTHOID, ObjectIdGetDatum(objectId)))
1212  ereport(ERROR,
1213  (errcode(ERRCODE_UNDEFINED_OBJECT),
1214  errmsg("role %u was concurrently dropped",
1215  objectId)));
1216  break;
1217 
1218  case TableSpaceRelationId:
1219  {
1220  /* For lack of a syscache on pg_tablespace, do this: */
1221  char *tablespace = get_tablespace_name(objectId);
1222 
1223  if (tablespace == NULL)
1224  ereport(ERROR,
1225  (errcode(ERRCODE_UNDEFINED_OBJECT),
1226  errmsg("tablespace %u was concurrently dropped",
1227  objectId)));
1228  pfree(tablespace);
1229  break;
1230  }
1231 
1232  case DatabaseRelationId:
1233  {
1234  /* For lack of a syscache on pg_database, do this: */
1235  char *database = get_database_name(objectId);
1236 
1237  if (database == NULL)
1238  ereport(ERROR,
1239  (errcode(ERRCODE_UNDEFINED_OBJECT),
1240  errmsg("database %u was concurrently dropped",
1241  objectId)));
1242  pfree(database);
1243  break;
1244  }
1245 
1246 
1247  default:
1248  elog(ERROR, "unrecognized shared classId: %u", classId);
1249  }
1250 }
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3154
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1083
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:95

References AccessShareLock, elog, ereport, errcode(), errmsg(), ERROR, get_database_name(), get_tablespace_name(), LockSharedObject(), ObjectIdGetDatum(), pfree(), SearchSysCacheExists1, and tablespace.

Referenced by AlterDatabaseSet(), AlterRoleSet(), shdepAddDependency(), and shdepChangeDep().

◆ shdepReassignOwned()

void shdepReassignOwned ( List roleids,
Oid  newrole 
)

Definition at line 1515 of file pg_shdepend.c.

1516 {
1517  Relation sdepRel;
1518  ListCell *cell;
1519 
1520  /*
1521  * We don't need this strong a lock here, but we'll call routines that
1522  * acquire RowExclusiveLock. Better get that right now to avoid potential
1523  * deadlock problems.
1524  */
1525  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1526 
1527  foreach(cell, roleids)
1528  {
1529  SysScanDesc scan;
1530  ScanKeyData key[2];
1531  HeapTuple tuple;
1532  Oid roleid = lfirst_oid(cell);
1533 
1534  /* Refuse to work on pinned roles */
1535  if (IsPinnedObject(AuthIdRelationId, roleid))
1536  {
1537  ObjectAddress obj;
1538 
1539  obj.classId = AuthIdRelationId;
1540  obj.objectId = roleid;
1541  obj.objectSubId = 0;
1542 
1543  ereport(ERROR,
1544  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1545  errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system",
1546  getObjectDescription(&obj, false))));
1547 
1548  /*
1549  * There's no need to tell the whole truth, which is that we
1550  * didn't track these dependencies at all ...
1551  */
1552  }
1553 
1554  ScanKeyInit(&key[0],
1555  Anum_pg_shdepend_refclassid,
1556  BTEqualStrategyNumber, F_OIDEQ,
1557  ObjectIdGetDatum(AuthIdRelationId));
1558  ScanKeyInit(&key[1],
1559  Anum_pg_shdepend_refobjid,
1560  BTEqualStrategyNumber, F_OIDEQ,
1561  ObjectIdGetDatum(roleid));
1562 
1563  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1564  NULL, 2, key);
1565 
1566  while ((tuple = systable_getnext(scan)) != NULL)
1567  {
1568  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
1569  MemoryContext cxt,
1570  oldcxt;
1571 
1572  /*
1573  * We only operate on shared objects and objects in the current
1574  * database
1575  */
1576  if (sdepForm->dbid != MyDatabaseId &&
1577  sdepForm->dbid != InvalidOid)
1578  continue;
1579 
1580  /* We leave non-owner dependencies alone */
1581  if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER)
1582  continue;
1583 
1584  /*
1585  * The various ALTER OWNER routines tend to leak memory in
1586  * CurrentMemoryContext. That's not a problem when they're only
1587  * called once per command; but in this usage where we might be
1588  * touching many objects, it can amount to a serious memory leak.
1589  * Fix that by running each call in a short-lived context.
1590  */
1592  "shdepReassignOwned",
1594  oldcxt = MemoryContextSwitchTo(cxt);
1595 
1596  /* Issue the appropriate ALTER OWNER call */
1597  switch (sdepForm->classid)
1598  {
1599  case TypeRelationId:
1600  AlterTypeOwner_oid(sdepForm->objid, newrole, true);
1601  break;
1602 
1603  case NamespaceRelationId:
1604  AlterSchemaOwner_oid(sdepForm->objid, newrole);
1605  break;
1606 
1607  case RelationRelationId:
1608 
1609  /*
1610  * Pass recursing = true so that we don't fail on indexes,
1611  * owned sequences, etc when we happen to visit them
1612  * before their parent table.
1613  */
1614  ATExecChangeOwner(sdepForm->objid, newrole, true, AccessExclusiveLock);
1615  break;
1616 
1617  case DefaultAclRelationId:
1618 
1619  /*
1620  * Ignore default ACLs; they should be handled by DROP
1621  * OWNED, not REASSIGN OWNED.
1622  */
1623  break;
1624 
1625  case UserMappingRelationId:
1626  /* ditto */
1627  break;
1628 
1629  case ForeignServerRelationId:
1630  AlterForeignServerOwner_oid(sdepForm->objid, newrole);
1631  break;
1632 
1633  case ForeignDataWrapperRelationId:
1634  AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole);
1635  break;
1636 
1637  case EventTriggerRelationId:
1638  AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
1639  break;
1640 
1641  case PublicationRelationId:
1642  AlterPublicationOwner_oid(sdepForm->objid, newrole);
1643  break;
1644 
1645  case SubscriptionRelationId:
1646  AlterSubscriptionOwner_oid(sdepForm->objid, newrole);
1647  break;
1648 
1649  /* Generic alter owner cases */
1650  case CollationRelationId:
1651  case ConversionRelationId:
1652  case OperatorRelationId:
1653  case ProcedureRelationId:
1654  case LanguageRelationId:
1655  case LargeObjectRelationId:
1656  case OperatorFamilyRelationId:
1657  case OperatorClassRelationId:
1658  case ExtensionRelationId:
1659  case StatisticExtRelationId:
1660  case TableSpaceRelationId:
1661  case DatabaseRelationId:
1662  case TSConfigRelationId:
1663  case TSDictionaryRelationId:
1664  AlterObjectOwner_internal(sdepForm->classid,
1665  sdepForm->objid,
1666  newrole);
1667  break;
1668 
1669  default:
1670  elog(ERROR, "unexpected classid %u", sdepForm->classid);
1671  break;
1672  }
1673 
1674  /* Clean up */
1675  MemoryContextSwitchTo(oldcxt);
1676  MemoryContextDelete(cxt);
1677 
1678  /* Make sure the next iteration will see my changes */
1680  }
1681 
1682  systable_endscan(scan);
1683  }
1684 
1685  table_close(sdepRel, RowExclusiveLock);
1686 }
void AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId)
Definition: alter.c:916
void AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
void AlterForeignServerOwner_oid(Oid srvId, Oid newOwnerId)
Definition: foreigncmds.c:450
void AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId)
Definition: foreigncmds.c:313
#define AccessExclusiveLock
Definition: lockdefs.h:43
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
void AlterPublicationOwner_oid(Oid subid, Oid newOwnerId)
MemoryContextSwitchTo(old_ctx)
void AlterSchemaOwner_oid(Oid schemaoid, Oid newOwnerId)
Definition: schemacmds.c:307
void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId)
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:14279
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3947
void CommandCounterIncrement(void)
Definition: xact.c:1097

References AccessExclusiveLock, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, AlterEventTriggerOwner_oid(), AlterForeignDataWrapperOwner_oid(), AlterForeignServerOwner_oid(), AlterObjectOwner_internal(), AlterPublicationOwner_oid(), AlterSchemaOwner_oid(), AlterSubscriptionOwner_oid(), AlterTypeOwner_oid(), ATExecChangeOwner(), BTEqualStrategyNumber, ObjectAddress::classId, CommandCounterIncrement(), CurrentMemoryContext, elog, ereport, errcode(), errmsg(), ERROR, getObjectDescription(), GETSTRUCT, InvalidOid, IsPinnedObject(), sort-test::key, lfirst_oid, MemoryContextDelete(), MemoryContextSwitchTo(), MyDatabaseId, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, RowExclusiveLock, ScanKeyInit(), SHARED_DEPENDENCY_OWNER, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ReassignOwnedObjects().

◆ storeObjectDescription()

static void storeObjectDescription ( StringInfo  descs,
SharedDependencyObjectType  type,
ObjectAddress object,
SharedDependencyType  deptype,
int  count 
)
static

Definition at line 1268 of file pg_shdepend.c.

1273 {
1274  char *objdesc = getObjectDescription(object, false);
1275 
1276  /*
1277  * An object being dropped concurrently doesn't need to be reported.
1278  */
1279  if (objdesc == NULL)
1280  return;
1281 
1282  /* separate entries with a newline */
1283  if (descs->len != 0)
1284  appendStringInfoChar(descs, '\n');
1285 
1286  switch (type)
1287  {
1288  case LOCAL_OBJECT:
1289  case SHARED_OBJECT:
1290  if (deptype == SHARED_DEPENDENCY_OWNER)
1291  appendStringInfo(descs, _("owner of %s"), objdesc);
1292  else if (deptype == SHARED_DEPENDENCY_ACL)
1293  appendStringInfo(descs, _("privileges for %s"), objdesc);
1294  else if (deptype == SHARED_DEPENDENCY_INITACL)
1295  appendStringInfo(descs, _("initial privileges for %s"), objdesc);
1296  else if (deptype == SHARED_DEPENDENCY_POLICY)
1297  appendStringInfo(descs, _("target of %s"), objdesc);
1298  else if (deptype == SHARED_DEPENDENCY_TABLESPACE)
1299  appendStringInfo(descs, _("tablespace for %s"), objdesc);
1300  else
1301  elog(ERROR, "unrecognized dependency type: %d",
1302  (int) deptype);
1303  break;
1304 
1305  case REMOTE_OBJECT:
1306  /* translator: %s will always be "database %s" */
1307  appendStringInfo(descs, ngettext("%d object in %s",
1308  "%d objects in %s",
1309  count),
1310  count, objdesc);
1311  break;
1312 
1313  default:
1314  elog(ERROR, "unrecognized object type: %d", type);
1315  }
1316 
1317  pfree(objdesc);
1318 }
#define _(x)
Definition: elog.c:90
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
const char * type

References _, appendStringInfo(), appendStringInfoChar(), elog, ERROR, getObjectDescription(), StringInfoData::len, LOCAL_OBJECT, ngettext, pfree(), REMOTE_OBJECT, SHARED_DEPENDENCY_ACL, SHARED_DEPENDENCY_INITACL, SHARED_DEPENDENCY_OWNER, SHARED_DEPENDENCY_POLICY, SHARED_DEPENDENCY_TABLESPACE, SHARED_OBJECT, and type.

Referenced by checkSharedDependencies().

◆ updateAclDependencies()

void updateAclDependencies ( Oid  classId,
Oid  objectId,
int32  objsubId,
Oid  ownerId,
int  noldmembers,
Oid oldmembers,
int  nnewmembers,
Oid newmembers 
)

Definition at line 487 of file pg_shdepend.c.

491 {
492  updateAclDependenciesWorker(classId, objectId, objsubId,
493  ownerId, SHARED_DEPENDENCY_ACL,
494  noldmembers, oldmembers,
495  nnewmembers, newmembers);
496 }
static void updateAclDependenciesWorker(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, SharedDependencyType deptype, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:519

References SHARED_DEPENDENCY_ACL, and updateAclDependenciesWorker().

Referenced by AddRoleMems(), ExecGrant_Attribute(), ExecGrant_common(), ExecGrant_Largeobject(), ExecGrant_Parameter(), ExecGrant_Relation(), recordDependencyOnNewAcl(), and SetDefaultACL().

◆ updateAclDependenciesWorker()

static void updateAclDependenciesWorker ( Oid  classId,
Oid  objectId,
int32  objsubId,
Oid  ownerId,
SharedDependencyType  deptype,
int  noldmembers,
Oid oldmembers,
int  nnewmembers,
Oid newmembers 
)
static

Definition at line 519 of file pg_shdepend.c.

523 {
524  Relation sdepRel;
525  int i;
526 
527  /*
528  * Remove entries that are common to both lists; those represent existing
529  * dependencies we don't need to change.
530  *
531  * OK to overwrite the inputs since we'll pfree them anyway.
532  */
533  getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers);
534 
535  if (noldmembers > 0 || nnewmembers > 0)
536  {
537  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
538 
539  /* Add new dependencies that weren't already present */
540  for (i = 0; i < nnewmembers; i++)
541  {
542  Oid roleid = newmembers[i];
543 
544  /*
545  * Skip the owner: he has an OWNER shdep entry instead. (This is
546  * not just a space optimization; it makes ALTER OWNER easier. See
547  * notes in changeDependencyOnOwner.)
548  */
549  if (roleid == ownerId)
550  continue;
551 
552  /* Skip pinned roles; they don't need dependency entries */
553  if (IsPinnedObject(AuthIdRelationId, roleid))
554  continue;
555 
556  shdepAddDependency(sdepRel, classId, objectId, objsubId,
557  AuthIdRelationId, roleid,
558  deptype);
559  }
560 
561  /* Drop no-longer-used old dependencies */
562  for (i = 0; i < noldmembers; i++)
563  {
564  Oid roleid = oldmembers[i];
565 
566  /* Skip the owner, same as above */
567  if (roleid == ownerId)
568  continue;
569 
570  /* Skip pinned roles */
571  if (IsPinnedObject(AuthIdRelationId, roleid))
572  continue;
573 
574  shdepDropDependency(sdepRel, classId, objectId, objsubId,
575  false, /* exact match on objsubId */
576  AuthIdRelationId, roleid,
577  deptype);
578  }
579 
580  table_close(sdepRel, RowExclusiveLock);
581  }
582 
583  if (oldmembers)
584  pfree(oldmembers);
585  if (newmembers)
586  pfree(newmembers);
587 }
static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
Definition: pg_shdepend.c:417

References getOidListDiff(), i, IsPinnedObject(), pfree(), RowExclusiveLock, shdepAddDependency(), shdepDropDependency(), table_close(), and table_open().

Referenced by updateAclDependencies(), and updateInitAclDependencies().

◆ updateInitAclDependencies()

void updateInitAclDependencies ( Oid  classId,
Oid  objectId,
int32  objsubId,
Oid  ownerId,
int  noldmembers,
Oid oldmembers,
int  nnewmembers,
Oid newmembers 
)

Definition at line 506 of file pg_shdepend.c.

510 {
511  updateAclDependenciesWorker(classId, objectId, objsubId,
512  ownerId, SHARED_DEPENDENCY_INITACL,
513  noldmembers, oldmembers,
514  nnewmembers, newmembers);
515 }

References SHARED_DEPENDENCY_INITACL, and updateAclDependenciesWorker().

Referenced by recordExtensionInitPrivWorker(), and RemoveRoleFromInitPriv().