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 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)
 
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 308 of file pg_shdepend.c.

309 {
310  Relation sdepRel;
311 
312  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
313 
314  /* Adjust the SHARED_DEPENDENCY_OWNER entry */
315  shdepChangeDep(sdepRel,
316  classId, objectId, 0,
317  AuthIdRelationId, newOwnerId,
319 
320  /*----------
321  * There should never be a SHARED_DEPENDENCY_ACL entry for the owner,
322  * so get rid of it if there is one. This can happen if the new owner
323  * was previously granted some rights to the object.
324  *
325  * This step is analogous to aclnewowner's removal of duplicate entries
326  * in the ACL. We have to do it to handle this scenario:
327  * A grants some rights on an object to B
328  * ALTER OWNER changes the object's owner to B
329  * ALTER OWNER changes the object's owner to C
330  * The third step would remove all mention of B from the object's ACL,
331  * but we'd still have a SHARED_DEPENDENCY_ACL for B if we did not do
332  * things this way.
333  *
334  * The rule against having a SHARED_DEPENDENCY_ACL entry for the owner
335  * allows us to fix things up in just this one place, without having
336  * to make the various ALTER OWNER routines each know about it.
337  *----------
338  */
339  shdepDropDependency(sdepRel, classId, objectId, 0, true,
340  AuthIdRelationId, newOwnerId,
342 
343  table_close(sdepRel, RowExclusiveLock);
344 }
@ SHARED_DEPENDENCY_ACL
Definition: dependency.h:75
@ SHARED_DEPENDENCY_OWNER
Definition: dependency.h:74
#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:1074
static void shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, int32 objsubid, Oid refclassid, Oid refobjid, SharedDependencyType deptype)
Definition: pg_shdepend.c:198
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_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 377 of file pg_shdepend.c.

378 {
379  Relation sdepRel;
380 
381  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
382 
383  if (newTablespaceId != DEFAULTTABLESPACE_OID &&
384  newTablespaceId != InvalidOid)
385  shdepChangeDep(sdepRel,
386  classId, objectId, 0,
387  TableSpaceRelationId, newTablespaceId,
389  else
390  shdepDropDependency(sdepRel,
391  classId, objectId, 0, true,
394 
395  table_close(sdepRel, RowExclusiveLock);
396 }
@ SHARED_DEPENDENCY_TABLESPACE
Definition: dependency.h:77
@ SHARED_DEPENDENCY_INVALID
Definition: dependency.h:78
#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 626 of file pg_shdepend.c.

628 {
629  Relation sdepRel;
630  ScanKeyData key[2];
631  SysScanDesc scan;
632  HeapTuple tup;
633  int numReportedDeps = 0;
634  int numNotReportedDeps = 0;
635  int numNotReportedDbs = 0;
636  List *remDeps = NIL;
637  ListCell *cell;
638  ObjectAddress object;
639  ShDependObjectInfo *objects;
640  int numobjects;
641  int allocedobjects;
642  StringInfoData descs;
643  StringInfoData alldescs;
644 
645  /* This case can be dispatched quickly */
646  if (IsPinnedObject(classId, objectId))
647  {
648  object.classId = classId;
649  object.objectId = objectId;
650  object.objectSubId = 0;
651  ereport(ERROR,
652  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
653  errmsg("cannot drop %s because it is required by the database system",
654  getObjectDescription(&object, false))));
655  }
656 
657  /*
658  * We limit the number of dependencies reported to the client to
659  * MAX_REPORTED_DEPS, since client software may not deal well with
660  * enormous error strings. The server log always gets a full report.
661  *
662  * For stability of regression test results, we sort local and shared
663  * objects by OID before reporting them. We don't worry about the order
664  * in which other databases are reported, though.
665  */
666 #define MAX_REPORTED_DEPS 100
667 
668  allocedobjects = 128; /* arbitrary initial array size */
669  objects = (ShDependObjectInfo *)
670  palloc(allocedobjects * sizeof(ShDependObjectInfo));
671  numobjects = 0;
672  initStringInfo(&descs);
673  initStringInfo(&alldescs);
674 
675  sdepRel = table_open(SharedDependRelationId, AccessShareLock);
676 
677  ScanKeyInit(&key[0],
678  Anum_pg_shdepend_refclassid,
679  BTEqualStrategyNumber, F_OIDEQ,
680  ObjectIdGetDatum(classId));
681  ScanKeyInit(&key[1],
682  Anum_pg_shdepend_refobjid,
683  BTEqualStrategyNumber, F_OIDEQ,
684  ObjectIdGetDatum(objectId));
685 
686  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
687  NULL, 2, key);
688 
689  while (HeapTupleIsValid(tup = systable_getnext(scan)))
690  {
691  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
692 
693  object.classId = sdepForm->classid;
694  object.objectId = sdepForm->objid;
695  object.objectSubId = sdepForm->objsubid;
696 
697  /*
698  * If it's a dependency local to this database or it's a shared
699  * object, add it to the objects array.
700  *
701  * If it's a remote dependency, keep track of it so we can report the
702  * number of them later.
703  */
704  if (sdepForm->dbid == MyDatabaseId ||
705  sdepForm->dbid == InvalidOid)
706  {
707  if (numobjects >= allocedobjects)
708  {
709  allocedobjects *= 2;
710  objects = (ShDependObjectInfo *)
711  repalloc(objects,
712  allocedobjects * sizeof(ShDependObjectInfo));
713  }
714  objects[numobjects].object = object;
715  objects[numobjects].deptype = sdepForm->deptype;
716  objects[numobjects].objtype = (sdepForm->dbid == MyDatabaseId) ?
718  numobjects++;
719  }
720  else
721  {
722  /* It's not local nor shared, so it must be remote. */
723  remoteDep *dep;
724  bool stored = false;
725 
726  /*
727  * XXX this info is kept on a simple List. Maybe it's not good
728  * for performance, but using a hash table seems needlessly
729  * complex. The expected number of databases is not high anyway,
730  * I suppose.
731  */
732  foreach(cell, remDeps)
733  {
734  dep = lfirst(cell);
735  if (dep->dbOid == sdepForm->dbid)
736  {
737  dep->count++;
738  stored = true;
739  break;
740  }
741  }
742  if (!stored)
743  {
744  dep = (remoteDep *) palloc(sizeof(remoteDep));
745  dep->dbOid = sdepForm->dbid;
746  dep->count = 1;
747  remDeps = lappend(remDeps, dep);
748  }
749  }
750  }
751 
752  systable_endscan(scan);
753 
754  table_close(sdepRel, AccessShareLock);
755 
756  /*
757  * Sort and report local and shared objects.
758  */
759  if (numobjects > 1)
760  qsort(objects, numobjects,
762 
763  for (int i = 0; i < numobjects; i++)
764  {
765  if (numReportedDeps < MAX_REPORTED_DEPS)
766  {
767  numReportedDeps++;
768  storeObjectDescription(&descs,
769  objects[i].objtype,
770  &objects[i].object,
771  objects[i].deptype,
772  0);
773  }
774  else
775  numNotReportedDeps++;
776  storeObjectDescription(&alldescs,
777  objects[i].objtype,
778  &objects[i].object,
779  objects[i].deptype,
780  0);
781  }
782 
783  /*
784  * Summarize dependencies in remote databases.
785  */
786  foreach(cell, remDeps)
787  {
788  remoteDep *dep = lfirst(cell);
789 
790  object.classId = DatabaseRelationId;
791  object.objectId = dep->dbOid;
792  object.objectSubId = 0;
793 
794  if (numReportedDeps < MAX_REPORTED_DEPS)
795  {
796  numReportedDeps++;
797  storeObjectDescription(&descs, REMOTE_OBJECT, &object,
799  }
800  else
801  numNotReportedDbs++;
802  storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
804  }
805 
806  pfree(objects);
807  list_free_deep(remDeps);
808 
809  if (descs.len == 0)
810  {
811  pfree(descs.data);
812  pfree(alldescs.data);
813  *detail_msg = *detail_log_msg = NULL;
814  return false;
815  }
816 
817  if (numNotReportedDeps > 0)
818  appendStringInfo(&descs, ngettext("\nand %d other object "
819  "(see server log for list)",
820  "\nand %d other objects "
821  "(see server log for list)",
822  numNotReportedDeps),
823  numNotReportedDeps);
824  if (numNotReportedDbs > 0)
825  appendStringInfo(&descs, ngettext("\nand objects in %d other database "
826  "(see server log for list)",
827  "\nand objects in %d other databases "
828  "(see server log for list)",
829  numNotReportedDbs),
830  numNotReportedDbs);
831 
832  *detail_msg = descs.data;
833  *detail_log_msg = alldescs.data;
834  return true;
835 }
#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:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#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:560
#define MAX_REPORTED_DEPS
static void storeObjectDescription(StringInfo descs, SharedDependencyObjectType type, ObjectAddress *object, SharedDependencyType deptype, int count)
Definition: pg_shdepend.c:1226
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 1140 of file pg_shdepend.c.

1141 {
1142  Oid dbId;
1143 
1144  if (IsSharedRelation(classId))
1145  dbId = InvalidOid;
1146  else
1147  dbId = MyDatabaseId;
1148 
1149  return dbId;
1150 }
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 845 of file pg_shdepend.c.

846 {
847  Relation sdepRel;
848  TupleDesc sdepDesc;
849  ScanKeyData key[1];
850  SysScanDesc scan;
851  HeapTuple tup;
852  CatalogIndexState indstate;
853  TupleTableSlot **slot;
854  int max_slots,
855  slot_init_count,
856  slot_stored_count;
857 
858  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
859  sdepDesc = RelationGetDescr(sdepRel);
860 
861  /*
862  * Allocate the slots to use, but delay costly initialization until we
863  * know that they will be used.
864  */
866  slot = palloc(sizeof(TupleTableSlot *) * max_slots);
867 
868  indstate = CatalogOpenIndexes(sdepRel);
869 
870  /* Scan all entries with dbid = templateDbId */
871  ScanKeyInit(&key[0],
872  Anum_pg_shdepend_dbid,
873  BTEqualStrategyNumber, F_OIDEQ,
874  ObjectIdGetDatum(templateDbId));
875 
876  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
877  NULL, 1, key);
878 
879  /* number of slots currently storing tuples */
880  slot_stored_count = 0;
881  /* number of slots currently initialized */
882  slot_init_count = 0;
883 
884  /*
885  * Copy the entries of the original database, changing the database Id to
886  * that of the new database. Note that because we are not copying rows
887  * with dbId == 0 (ie, rows describing dependent shared objects) we won't
888  * copy the ownership dependency of the template database itself; this is
889  * what we want.
890  */
891  while (HeapTupleIsValid(tup = systable_getnext(scan)))
892  {
893  Form_pg_shdepend shdep;
894 
895  if (slot_init_count < max_slots)
896  {
897  slot[slot_stored_count] = MakeSingleTupleTableSlot(sdepDesc, &TTSOpsHeapTuple);
898  slot_init_count++;
899  }
900 
901  ExecClearTuple(slot[slot_stored_count]);
902 
903  memset(slot[slot_stored_count]->tts_isnull, false,
904  slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
905 
906  shdep = (Form_pg_shdepend) GETSTRUCT(tup);
907 
908  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);
909  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_classid - 1] = shdep->classid;
910  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objid - 1] = shdep->objid;
911  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objsubid - 1] = shdep->objsubid;
912  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refclassid - 1] = shdep->refclassid;
913  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refobjid - 1] = shdep->refobjid;
914  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_deptype - 1] = shdep->deptype;
915 
916  ExecStoreVirtualTuple(slot[slot_stored_count]);
917  slot_stored_count++;
918 
919  /* If slots are full, insert a batch of tuples */
920  if (slot_stored_count == max_slots)
921  {
922  CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate);
923  slot_stored_count = 0;
924  }
925  }
926 
927  /* Insert any tuples left in the buffer */
928  if (slot_stored_count > 0)
929  CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate);
930 
931  systable_endscan(scan);
932 
933  CatalogCloseIndexes(indstate);
934  table_close(sdepRel, RowExclusiveLock);
935 
936  /* Drop only the number of slots used */
937  for (int i = 0; i < slot_init_count; i++)
939  pfree(slot);
940 }
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 997 of file pg_shdepend.c.

998 {
999  Relation sdepRel;
1000 
1001  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1002 
1003  shdepDropDependency(sdepRel, classId, objectId, objectSubId,
1004  (objectSubId == 0),
1007 
1008  table_close(sdepRel, RowExclusiveLock);
1009 }

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 949 of file pg_shdepend.c.

950 {
951  Relation sdepRel;
952  ScanKeyData key[1];
953  SysScanDesc scan;
954  HeapTuple tup;
955 
956  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
957 
958  /*
959  * First, delete all the entries that have the database Oid in the dbid
960  * field.
961  */
962  ScanKeyInit(&key[0],
963  Anum_pg_shdepend_dbid,
964  BTEqualStrategyNumber, F_OIDEQ,
965  ObjectIdGetDatum(databaseId));
966  /* We leave the other index fields unspecified */
967 
968  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
969  NULL, 1, key);
970 
971  while (HeapTupleIsValid(tup = systable_getnext(scan)))
972  {
973  CatalogTupleDelete(sdepRel, &tup->t_self);
974  }
975 
976  systable_endscan(scan);
977 
978  /* Now delete all entries corresponding to the database itself */
979  shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true,
982 
983  table_close(sdepRel, RowExclusiveLock);
984 }
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 407 of file pg_shdepend.c.

408 {
409  int in1,
410  in2,
411  out1,
412  out2;
413 
414  in1 = in2 = out1 = out2 = 0;
415  while (in1 < *nlist1 && in2 < *nlist2)
416  {
417  if (list1[in1] == list2[in2])
418  {
419  /* skip over duplicates */
420  in1++;
421  in2++;
422  }
423  else if (list1[in1] < list2[in2])
424  {
425  /* list1[in1] is not in list2 */
426  list1[out1++] = list1[in1++];
427  }
428  else
429  {
430  /* list2[in2] is not in list1 */
431  list2[out2++] = list2[in2++];
432  }
433  }
434 
435  /* any remaining list1 entries are not in list2 */
436  while (in1 < *nlist1)
437  {
438  list1[out1++] = list1[in1++];
439  }
440 
441  /* any remaining list2 entries are not in list1 */
442  while (in2 < *nlist2)
443  {
444  list2[out2++] = list2[in2++];
445  }
446 
447  *nlist1 = out1;
448  *nlist2 = out2;
449 }

Referenced by updateAclDependencies().

◆ recordDependencyOnOwner()

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

◆ recordDependencyOnTablespace()

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

Definition at line 356 of file pg_shdepend.c.

357 {
358  ObjectAddress myself,
359  referenced;
360 
361  ObjectAddressSet(myself, classId, objectId);
362  ObjectAddressSet(referenced, TableSpaceRelationId, tablespace);
363 
364  recordSharedDependencyOn(&myself, &referenced,
366 }
#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 117 of file pg_shdepend.c.

120 {
121  Relation sdepRel;
122 
123  /*
124  * Objects in pg_shdepend can't have SubIds.
125  */
126  Assert(depender->objectSubId == 0);
127  Assert(referenced->objectSubId == 0);
128 
129  /*
130  * During bootstrap, do nothing since pg_shdepend may not exist yet.
131  * initdb will fill in appropriate pg_shdepend entries after bootstrap.
132  */
134  return;
135 
136  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
137 
138  /* If the referenced object is pinned, do nothing. */
139  if (!IsPinnedObject(referenced->classId, referenced->objectId))
140  {
141  shdepAddDependency(sdepRel, depender->classId, depender->objectId,
142  depender->objectSubId,
143  referenced->classId, referenced->objectId,
144  deptype);
145  }
146 
147  table_close(sdepRel, RowExclusiveLock);
148 }
#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:1019

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 560 of file pg_shdepend.c.

561 {
562  const ShDependObjectInfo *obja = (const ShDependObjectInfo *) a;
563  const ShDependObjectInfo *objb = (const ShDependObjectInfo *) b;
564 
565  /*
566  * Primary sort key is OID ascending.
567  */
568  if (obja->object.objectId < objb->object.objectId)
569  return -1;
570  if (obja->object.objectId > objb->object.objectId)
571  return 1;
572 
573  /*
574  * Next sort on catalog ID, in case identical OIDs appear in different
575  * catalogs. Sort direction is pretty arbitrary here.
576  */
577  if (obja->object.classId < objb->object.classId)
578  return -1;
579  if (obja->object.classId > objb->object.classId)
580  return 1;
581 
582  /*
583  * Sort on object subId.
584  *
585  * We sort the subId as an unsigned int so that 0 (the whole object) will
586  * come first.
587  */
588  if ((unsigned int) obja->object.objectSubId < (unsigned int) objb->object.objectSubId)
589  return -1;
590  if ((unsigned int) obja->object.objectSubId > (unsigned int) objb->object.objectSubId)
591  return 1;
592 
593  /*
594  * Last, sort on deptype, in case the same object has multiple dependency
595  * types. (Note that there's no need to consider objtype, as that's
596  * determined by the catalog OID.)
597  */
598  if (obja->deptype < objb->deptype)
599  return -1;
600  if (obja->deptype > objb->deptype)
601  return 1;
602 
603  return 0;
604 }
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 1019 of file pg_shdepend.c.

1023 {
1024  HeapTuple tup;
1025  Datum values[Natts_pg_shdepend];
1026  bool nulls[Natts_pg_shdepend];
1027 
1028  /*
1029  * Make sure the object doesn't go away while we record the dependency on
1030  * it. DROP routines should lock the object exclusively before they check
1031  * shared dependencies.
1032  */
1033  shdepLockAndCheckObject(refclassId, refobjId);
1034 
1035  memset(nulls, false, sizeof(nulls));
1036 
1037  /*
1038  * Form the new tuple and record the dependency.
1039  */
1040  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
1041  values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
1042  values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
1043  values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId);
1044 
1045  values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
1046  values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
1047  values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
1048 
1049  tup = heap_form_tuple(sdepRel->rd_att, values, nulls);
1050 
1051  CatalogTupleInsert(sdepRel, tup);
1052 
1053  /* clean up */
1054  heap_freetuple(tup);
1055 }
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:1140
void shdepLockAndCheckObject(Oid classId, Oid objectId)
Definition: pg_shdepend.c:1161
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 updateAclDependencies().

◆ shdepChangeDep()

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

Definition at line 198 of file pg_shdepend.c.

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

1079 {
1080  ScanKeyData key[4];
1081  int nkeys;
1082  SysScanDesc scan;
1083  HeapTuple tup;
1084 
1085  /* Scan for entries matching the dependent object */
1086  ScanKeyInit(&key[0],
1087  Anum_pg_shdepend_dbid,
1088  BTEqualStrategyNumber, F_OIDEQ,
1089  ObjectIdGetDatum(classIdGetDbId(classId)));
1090  ScanKeyInit(&key[1],
1091  Anum_pg_shdepend_classid,
1092  BTEqualStrategyNumber, F_OIDEQ,
1093  ObjectIdGetDatum(classId));
1094  ScanKeyInit(&key[2],
1095  Anum_pg_shdepend_objid,
1096  BTEqualStrategyNumber, F_OIDEQ,
1097  ObjectIdGetDatum(objectId));
1098  if (drop_subobjects)
1099  nkeys = 3;
1100  else
1101  {
1102  ScanKeyInit(&key[3],
1103  Anum_pg_shdepend_objsubid,
1104  BTEqualStrategyNumber, F_INT4EQ,
1105  Int32GetDatum(objsubId));
1106  nkeys = 4;
1107  }
1108 
1109  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
1110  NULL, nkeys, key);
1111 
1112  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1113  {
1114  Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
1115 
1116  /* Filter entries according to additional parameters */
1117  if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId)
1118  continue;
1119  if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId)
1120  continue;
1121  if (deptype != SHARED_DEPENDENCY_INVALID &&
1122  shdepForm->deptype != deptype)
1123  continue;
1124 
1125  /* OK, delete it */
1126  CatalogTupleDelete(sdepRel, &tup->t_self);
1127  }
1128 
1129  systable_endscan(scan);
1130 }
#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 updateAclDependencies().

◆ shdepDropOwned()

void shdepDropOwned ( List roleids,
DropBehavior  behavior 
)

Definition at line 1290 of file pg_shdepend.c.

1291 {
1292  Relation sdepRel;
1293  ListCell *cell;
1294  ObjectAddresses *deleteobjs;
1295 
1296  deleteobjs = new_object_addresses();
1297 
1298  /*
1299  * We don't need this strong a lock here, but we'll call routines that
1300  * acquire RowExclusiveLock. Better get that right now to avoid potential
1301  * deadlock failures.
1302  */
1303  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1304 
1305  /*
1306  * For each role, find the dependent objects and drop them using the
1307  * regular (non-shared) dependency management.
1308  */
1309  foreach(cell, roleids)
1310  {
1311  Oid roleid = lfirst_oid(cell);
1312  ScanKeyData key[2];
1313  SysScanDesc scan;
1314  HeapTuple tuple;
1315 
1316  /* Doesn't work for pinned objects */
1317  if (IsPinnedObject(AuthIdRelationId, roleid))
1318  {
1319  ObjectAddress obj;
1320 
1321  obj.classId = AuthIdRelationId;
1322  obj.objectId = roleid;
1323  obj.objectSubId = 0;
1324 
1325  ereport(ERROR,
1326  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1327  errmsg("cannot drop objects owned by %s because they are "
1328  "required by the database system",
1329  getObjectDescription(&obj, false))));
1330  }
1331 
1332  ScanKeyInit(&key[0],
1333  Anum_pg_shdepend_refclassid,
1334  BTEqualStrategyNumber, F_OIDEQ,
1335  ObjectIdGetDatum(AuthIdRelationId));
1336  ScanKeyInit(&key[1],
1337  Anum_pg_shdepend_refobjid,
1338  BTEqualStrategyNumber, F_OIDEQ,
1339  ObjectIdGetDatum(roleid));
1340 
1341  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1342  NULL, 2, key);
1343 
1344  while ((tuple = systable_getnext(scan)) != NULL)
1345  {
1346  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
1347  ObjectAddress obj;
1348 
1349  /*
1350  * We only operate on shared objects and objects in the current
1351  * database
1352  */
1353  if (sdepForm->dbid != MyDatabaseId &&
1354  sdepForm->dbid != InvalidOid)
1355  continue;
1356 
1357  switch (sdepForm->deptype)
1358  {
1359  /* Shouldn't happen */
1361  elog(ERROR, "unexpected dependency type");
1362  break;
1364 
1365  /*
1366  * Try to remove role from policy; if unable to, remove
1367  * policy.
1368  */
1369  if (!RemoveRoleFromObjectPolicy(roleid,
1370  sdepForm->classid,
1371  sdepForm->objid))
1372  {
1373  obj.classId = sdepForm->classid;
1374  obj.objectId = sdepForm->objid;
1375  obj.objectSubId = sdepForm->objsubid;
1376 
1377  /*
1378  * Acquire lock on object, then verify this dependency
1379  * is still relevant. If not, the object might have
1380  * been dropped or the policy modified. Ignore the
1381  * object in that case.
1382  */
1383  AcquireDeletionLock(&obj, 0);
1384  if (!systable_recheck_tuple(scan, tuple))
1385  {
1386  ReleaseDeletionLock(&obj);
1387  break;
1388  }
1389  add_exact_object_address(&obj, deleteobjs);
1390  }
1391  break;
1392  case SHARED_DEPENDENCY_ACL:
1393 
1394  /*
1395  * Dependencies on role grants are recorded using
1396  * SHARED_DEPENDENCY_ACL, but unlike a regular ACL list
1397  * which stores all permissions for a particular object in
1398  * a single ACL array, there's a separate catalog row for
1399  * each grant - so removing the grant just means removing
1400  * the entire row.
1401  */
1402  if (sdepForm->classid != AuthMemRelationId)
1403  {
1404  RemoveRoleFromObjectACL(roleid,
1405  sdepForm->classid,
1406  sdepForm->objid);
1407  break;
1408  }
1409  /* FALLTHROUGH */
1410 
1412 
1413  /*
1414  * Save it for deletion below, if it's a local object or a
1415  * role grant. Other shared objects, such as databases,
1416  * should not be removed here.
1417  */
1418  if (sdepForm->dbid == MyDatabaseId ||
1419  sdepForm->classid == AuthMemRelationId)
1420  {
1421  obj.classId = sdepForm->classid;
1422  obj.objectId = sdepForm->objid;
1423  obj.objectSubId = sdepForm->objsubid;
1424  /* as above */
1425  AcquireDeletionLock(&obj, 0);
1426  if (!systable_recheck_tuple(scan, tuple))
1427  {
1428  ReleaseDeletionLock(&obj);
1429  break;
1430  }
1431  add_exact_object_address(&obj, deleteobjs);
1432  }
1433  break;
1434  }
1435  }
1436 
1437  systable_endscan(scan);
1438  }
1439 
1440  /*
1441  * For stability of deletion-report ordering, sort the objects into
1442  * approximate reverse creation order before deletion. (This might also
1443  * make the deletion go a bit faster, since there's less chance of having
1444  * to rearrange the objects due to dependencies.)
1445  */
1446  sort_object_addresses(deleteobjs);
1447 
1448  /* the dependency mechanism does the actual work */
1449  performMultipleDeletions(deleteobjs, behavior, 0);
1450 
1451  table_close(sdepRel, RowExclusiveLock);
1452 
1453  free_object_addresses(deleteobjs);
1454 }
void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
Definition: aclchk.c:1453
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:76
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(), 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(), RemoveRoleFromObjectACL(), RemoveRoleFromObjectPolicy(), RowExclusiveLock, ScanKeyInit(), SHARED_DEPENDENCY_ACL, 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 1161 of file pg_shdepend.c.

1162 {
1163  /* AccessShareLock should be OK, since we are not modifying the object */
1164  LockSharedObject(classId, objectId, 0, AccessShareLock);
1165 
1166  switch (classId)
1167  {
1168  case AuthIdRelationId:
1169  if (!SearchSysCacheExists1(AUTHOID, ObjectIdGetDatum(objectId)))
1170  ereport(ERROR,
1171  (errcode(ERRCODE_UNDEFINED_OBJECT),
1172  errmsg("role %u was concurrently dropped",
1173  objectId)));
1174  break;
1175 
1176  case TableSpaceRelationId:
1177  {
1178  /* For lack of a syscache on pg_tablespace, do this: */
1179  char *tablespace = get_tablespace_name(objectId);
1180 
1181  if (tablespace == NULL)
1182  ereport(ERROR,
1183  (errcode(ERRCODE_UNDEFINED_OBJECT),
1184  errmsg("tablespace %u was concurrently dropped",
1185  objectId)));
1186  pfree(tablespace);
1187  break;
1188  }
1189 
1190  case DatabaseRelationId:
1191  {
1192  /* For lack of a syscache on pg_database, do this: */
1193  char *database = get_database_name(objectId);
1194 
1195  if (database == NULL)
1196  ereport(ERROR,
1197  (errcode(ERRCODE_UNDEFINED_OBJECT),
1198  errmsg("database %u was concurrently dropped",
1199  objectId)));
1200  pfree(database);
1201  break;
1202  }
1203 
1204 
1205  default:
1206  elog(ERROR, "unrecognized shared classId: %u", classId);
1207  }
1208 }
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3153
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 1463 of file pg_shdepend.c.

1464 {
1465  Relation sdepRel;
1466  ListCell *cell;
1467 
1468  /*
1469  * We don't need this strong a lock here, but we'll call routines that
1470  * acquire RowExclusiveLock. Better get that right now to avoid potential
1471  * deadlock problems.
1472  */
1473  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1474 
1475  foreach(cell, roleids)
1476  {
1477  SysScanDesc scan;
1478  ScanKeyData key[2];
1479  HeapTuple tuple;
1480  Oid roleid = lfirst_oid(cell);
1481 
1482  /* Refuse to work on pinned roles */
1483  if (IsPinnedObject(AuthIdRelationId, roleid))
1484  {
1485  ObjectAddress obj;
1486 
1487  obj.classId = AuthIdRelationId;
1488  obj.objectId = roleid;
1489  obj.objectSubId = 0;
1490 
1491  ereport(ERROR,
1492  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1493  errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system",
1494  getObjectDescription(&obj, false))));
1495 
1496  /*
1497  * There's no need to tell the whole truth, which is that we
1498  * didn't track these dependencies at all ...
1499  */
1500  }
1501 
1502  ScanKeyInit(&key[0],
1503  Anum_pg_shdepend_refclassid,
1504  BTEqualStrategyNumber, F_OIDEQ,
1505  ObjectIdGetDatum(AuthIdRelationId));
1506  ScanKeyInit(&key[1],
1507  Anum_pg_shdepend_refobjid,
1508  BTEqualStrategyNumber, F_OIDEQ,
1509  ObjectIdGetDatum(roleid));
1510 
1511  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1512  NULL, 2, key);
1513 
1514  while ((tuple = systable_getnext(scan)) != NULL)
1515  {
1516  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
1517  MemoryContext cxt,
1518  oldcxt;
1519 
1520  /*
1521  * We only operate on shared objects and objects in the current
1522  * database
1523  */
1524  if (sdepForm->dbid != MyDatabaseId &&
1525  sdepForm->dbid != InvalidOid)
1526  continue;
1527 
1528  /* We leave non-owner dependencies alone */
1529  if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER)
1530  continue;
1531 
1532  /*
1533  * The various ALTER OWNER routines tend to leak memory in
1534  * CurrentMemoryContext. That's not a problem when they're only
1535  * called once per command; but in this usage where we might be
1536  * touching many objects, it can amount to a serious memory leak.
1537  * Fix that by running each call in a short-lived context.
1538  */
1540  "shdepReassignOwned",
1542  oldcxt = MemoryContextSwitchTo(cxt);
1543 
1544  /* Issue the appropriate ALTER OWNER call */
1545  switch (sdepForm->classid)
1546  {
1547  case TypeRelationId:
1548  AlterTypeOwner_oid(sdepForm->objid, newrole, true);
1549  break;
1550 
1551  case NamespaceRelationId:
1552  AlterSchemaOwner_oid(sdepForm->objid, newrole);
1553  break;
1554 
1555  case RelationRelationId:
1556 
1557  /*
1558  * Pass recursing = true so that we don't fail on indexes,
1559  * owned sequences, etc when we happen to visit them
1560  * before their parent table.
1561  */
1562  ATExecChangeOwner(sdepForm->objid, newrole, true, AccessExclusiveLock);
1563  break;
1564 
1565  case DefaultAclRelationId:
1566 
1567  /*
1568  * Ignore default ACLs; they should be handled by DROP
1569  * OWNED, not REASSIGN OWNED.
1570  */
1571  break;
1572 
1573  case UserMappingRelationId:
1574  /* ditto */
1575  break;
1576 
1577  case ForeignServerRelationId:
1578  AlterForeignServerOwner_oid(sdepForm->objid, newrole);
1579  break;
1580 
1581  case ForeignDataWrapperRelationId:
1582  AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole);
1583  break;
1584 
1585  case EventTriggerRelationId:
1586  AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
1587  break;
1588 
1589  case PublicationRelationId:
1590  AlterPublicationOwner_oid(sdepForm->objid, newrole);
1591  break;
1592 
1593  case SubscriptionRelationId:
1594  AlterSubscriptionOwner_oid(sdepForm->objid, newrole);
1595  break;
1596 
1597  /* Generic alter owner cases */
1598  case CollationRelationId:
1599  case ConversionRelationId:
1600  case OperatorRelationId:
1601  case ProcedureRelationId:
1602  case LanguageRelationId:
1603  case LargeObjectRelationId:
1604  case OperatorFamilyRelationId:
1605  case OperatorClassRelationId:
1606  case ExtensionRelationId:
1607  case StatisticExtRelationId:
1608  case TableSpaceRelationId:
1609  case DatabaseRelationId:
1610  case TSConfigRelationId:
1611  case TSDictionaryRelationId:
1612  AlterObjectOwner_internal(sdepForm->classid,
1613  sdepForm->objid,
1614  newrole);
1615  break;
1616 
1617  default:
1618  elog(ERROR, "unexpected classid %u", sdepForm->classid);
1619  break;
1620  }
1621 
1622  /* Clean up */
1623  MemoryContextSwitchTo(oldcxt);
1624  MemoryContextDelete(cxt);
1625 
1626  /* Make sure the next iteration will see my changes */
1628  }
1629 
1630  systable_endscan(scan);
1631  }
1632 
1633  table_close(sdepRel, RowExclusiveLock);
1634 }
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:14982
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3949
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 1226 of file pg_shdepend.c.

1231 {
1232  char *objdesc = getObjectDescription(object, false);
1233 
1234  /*
1235  * An object being dropped concurrently doesn't need to be reported.
1236  */
1237  if (objdesc == NULL)
1238  return;
1239 
1240  /* separate entries with a newline */
1241  if (descs->len != 0)
1242  appendStringInfoChar(descs, '\n');
1243 
1244  switch (type)
1245  {
1246  case LOCAL_OBJECT:
1247  case SHARED_OBJECT:
1248  if (deptype == SHARED_DEPENDENCY_OWNER)
1249  appendStringInfo(descs, _("owner of %s"), objdesc);
1250  else if (deptype == SHARED_DEPENDENCY_ACL)
1251  appendStringInfo(descs, _("privileges for %s"), objdesc);
1252  else if (deptype == SHARED_DEPENDENCY_POLICY)
1253  appendStringInfo(descs, _("target of %s"), objdesc);
1254  else if (deptype == SHARED_DEPENDENCY_TABLESPACE)
1255  appendStringInfo(descs, _("tablespace for %s"), objdesc);
1256  else
1257  elog(ERROR, "unrecognized dependency type: %d",
1258  (int) deptype);
1259  break;
1260 
1261  case REMOTE_OBJECT:
1262  /* translator: %s will always be "database %s" */
1263  appendStringInfo(descs, ngettext("%d object in %s",
1264  "%d objects in %s",
1265  count),
1266  count, objdesc);
1267  break;
1268 
1269  default:
1270  elog(ERROR, "unrecognized object type: %d", type);
1271  }
1272 
1273  pfree(objdesc);
1274 }
#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_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 477 of file pg_shdepend.c.

481 {
482  Relation sdepRel;
483  int i;
484 
485  /*
486  * Remove entries that are common to both lists; those represent existing
487  * dependencies we don't need to change.
488  *
489  * OK to overwrite the inputs since we'll pfree them anyway.
490  */
491  getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers);
492 
493  if (noldmembers > 0 || nnewmembers > 0)
494  {
495  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
496 
497  /* Add new dependencies that weren't already present */
498  for (i = 0; i < nnewmembers; i++)
499  {
500  Oid roleid = newmembers[i];
501 
502  /*
503  * Skip the owner: he has an OWNER shdep entry instead. (This is
504  * not just a space optimization; it makes ALTER OWNER easier. See
505  * notes in changeDependencyOnOwner.)
506  */
507  if (roleid == ownerId)
508  continue;
509 
510  /* Skip pinned roles; they don't need dependency entries */
511  if (IsPinnedObject(AuthIdRelationId, roleid))
512  continue;
513 
514  shdepAddDependency(sdepRel, classId, objectId, objsubId,
515  AuthIdRelationId, roleid,
517  }
518 
519  /* Drop no-longer-used old dependencies */
520  for (i = 0; i < noldmembers; i++)
521  {
522  Oid roleid = oldmembers[i];
523 
524  /* Skip the owner, same as above */
525  if (roleid == ownerId)
526  continue;
527 
528  /* Skip pinned roles */
529  if (IsPinnedObject(AuthIdRelationId, roleid))
530  continue;
531 
532  shdepDropDependency(sdepRel, classId, objectId, objsubId,
533  false, /* exact match on objsubId */
534  AuthIdRelationId, roleid,
536  }
537 
538  table_close(sdepRel, RowExclusiveLock);
539  }
540 
541  if (oldmembers)
542  pfree(oldmembers);
543  if (newmembers)
544  pfree(newmembers);
545 }
static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
Definition: pg_shdepend.c:407

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

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