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_largeobject_metadata.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/collationcmds.h"
#include "commands/conversioncmds.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/policy.h"
#include "commands/proclang.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 72 of file pg_shdepend.c.

73 {
SharedDependencyObjectType
Definition: pg_shdepend.c:73
@ SHARED_OBJECT
Definition: pg_shdepend.c:75
@ LOCAL_OBJECT
Definition: pg_shdepend.c:74
@ REMOTE_OBJECT
Definition: pg_shdepend.c:76

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  table_close(sdepRel, RowExclusiveLock);
349 }
@ 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:1079
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_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 382 of file pg_shdepend.c.

383 {
384  Relation sdepRel;
385 
386  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
387 
388  if (newTablespaceId != DEFAULTTABLESPACE_OID &&
389  newTablespaceId != InvalidOid)
390  shdepChangeDep(sdepRel,
391  classId, objectId, 0,
392  TableSpaceRelationId, newTablespaceId,
394  else
395  shdepDropDependency(sdepRel,
396  classId, objectId, 0, true,
399 
400  table_close(sdepRel, RowExclusiveLock);
401 }
@ 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 631 of file pg_shdepend.c.

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

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

1146 {
1147  Oid dbId;
1148 
1149  if (IsSharedRelation(classId))
1150  dbId = InvalidOid;
1151  else
1152  dbId = MyDatabaseId;
1153 
1154  return dbId;
1155 }
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:245
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 850 of file pg_shdepend.c.

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

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

1003 {
1004  Relation sdepRel;
1005 
1006  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1007 
1008  shdepDropDependency(sdepRel, classId, objectId, objectSubId,
1009  (objectSubId == 0),
1012 
1013  table_close(sdepRel, RowExclusiveLock);
1014 }

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

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

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

Referenced by updateAclDependencies().

◆ recordDependencyOnOwner()

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

◆ recordDependencyOnTablespace()

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

Definition at line 361 of file pg_shdepend.c.

362 {
363  ObjectAddress myself,
364  referenced;
365 
366  ObjectAddressSet(myself, classId, objectId);
367  ObjectAddressSet(referenced, TableSpaceRelationId, tablespace);
368 
369  recordSharedDependencyOn(&myself, &referenced,
371 }
#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 }
Assert(fmt[strlen(fmt) - 1] !='\n')
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:417
static void shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId, int32 objsubId, Oid refclassId, Oid refobjId, SharedDependencyType deptype)
Definition: pg_shdepend.c:1024

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

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

1028 {
1029  HeapTuple tup;
1030  Datum values[Natts_pg_shdepend];
1031  bool nulls[Natts_pg_shdepend];
1032 
1033  /*
1034  * Make sure the object doesn't go away while we record the dependency on
1035  * it. DROP routines should lock the object exclusively before they check
1036  * shared dependencies.
1037  */
1038  shdepLockAndCheckObject(refclassId, refobjId);
1039 
1040  memset(nulls, false, sizeof(nulls));
1041 
1042  /*
1043  * Form the new tuple and record the dependency.
1044  */
1045  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
1046  values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
1047  values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
1048  values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId);
1049 
1050  values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
1051  values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
1052  values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
1053 
1054  tup = heap_form_tuple(sdepRel->rd_att, values, nulls);
1055 
1056  CatalogTupleInsert(sdepRel, tup);
1057 
1058  /* clean up */
1059  heap_freetuple(tup);
1060 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
static Oid classIdGetDbId(Oid classId)
Definition: pg_shdepend.c:1145
void shdepLockAndCheckObject(Oid classId, Oid objectId)
Definition: pg_shdepend.c:1166
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 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 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:777
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 1079 of file pg_shdepend.c.

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

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

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

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

1167 {
1168  /* AccessShareLock should be OK, since we are not modifying the object */
1169  LockSharedObject(classId, objectId, 0, AccessShareLock);
1170 
1171  switch (classId)
1172  {
1173  case AuthIdRelationId:
1175  ereport(ERROR,
1176  (errcode(ERRCODE_UNDEFINED_OBJECT),
1177  errmsg("role %u was concurrently dropped",
1178  objectId)));
1179  break;
1180 
1181  case TableSpaceRelationId:
1182  {
1183  /* For lack of a syscache on pg_tablespace, do this: */
1184  char *tablespace = get_tablespace_name(objectId);
1185 
1186  if (tablespace == NULL)
1187  ereport(ERROR,
1188  (errcode(ERRCODE_UNDEFINED_OBJECT),
1189  errmsg("tablespace %u was concurrently dropped",
1190  objectId)));
1191  pfree(tablespace);
1192  break;
1193  }
1194 
1195  case DatabaseRelationId:
1196  {
1197  /* For lack of a syscache on pg_database, do this: */
1198  char *database = get_database_name(objectId);
1199 
1200  if (database == NULL)
1201  ereport(ERROR,
1202  (errcode(ERRCODE_UNDEFINED_OBJECT),
1203  errmsg("database %u was concurrently dropped",
1204  objectId)));
1205  pfree(database);
1206  break;
1207  }
1208 
1209 
1210  default:
1211  elog(ERROR, "unrecognized shared classId: %u", classId);
1212  }
1213 }
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1478
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3089
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1046
@ AUTHOID
Definition: syscache.h:45
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:191

References AccessShareLock, AUTHOID, 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 1468 of file pg_shdepend.c.

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

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, NoLock, 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 1231 of file pg_shdepend.c.

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

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

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().