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

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

Function Documentation

◆ changeDependencyOnOwner()

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

Definition at line 312 of file pg_shdepend.c.

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

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

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

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

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

1145 {
1146  Oid dbId;
1147 
1148  if (IsSharedRelation(classId))
1149  dbId = InvalidOid;
1150  else
1151  dbId = MyDatabaseId;
1152 
1153  return dbId;
1154 }
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 849 of file pg_shdepend.c.

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

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

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

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

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

◆ dropDatabaseDependencies()

void dropDatabaseDependencies ( Oid  databaseId)

Definition at line 953 of file pg_shdepend.c.

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

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

Referenced by updateAclDependencies().

◆ recordDependencyOnOwner()

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

◆ recordDependencyOnTablespace()

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

Definition at line 360 of file pg_shdepend.c.

361 {
362  ObjectAddress myself,
363  referenced;
364 
365  ObjectAddressSet(myself, classId, objectId);
366  ObjectAddressSet(referenced, TableSpaceRelationId, tablespace);
367 
368  recordSharedDependencyOn(&myself, &referenced,
370 }
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
char * tablespace
Definition: pgbench.c:229

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

Referenced by heap_create().

◆ recordSharedDependencyOn()

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

Definition at line 121 of file pg_shdepend.c.

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

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

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

1027 {
1028  HeapTuple tup;
1029  Datum values[Natts_pg_shdepend];
1030  bool nulls[Natts_pg_shdepend];
1031 
1032  /*
1033  * Make sure the object doesn't go away while we record the dependency on
1034  * it. DROP routines should lock the object exclusively before they check
1035  * shared dependencies.
1036  */
1037  shdepLockAndCheckObject(refclassId, refobjId);
1038 
1039  memset(nulls, false, sizeof(nulls));
1040 
1041  /*
1042  * Form the new tuple and record the dependency.
1043  */
1044  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
1045  values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
1046  values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
1047  values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId);
1048 
1049  values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
1050  values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
1051  values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
1052 
1053  tup = heap_form_tuple(sdepRel->rd_att, values, nulls);
1054 
1055  CatalogTupleInsert(sdepRel, tup);
1056 
1057  /* clean up */
1058  heap_freetuple(tup);
1059 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
static Oid classIdGetDbId(Oid classId)
Definition: pg_shdepend.c:1144
void shdepLockAndCheckObject(Oid classId, Oid objectId)
Definition: pg_shdepend.c:1165
uintptr_t Datum
Definition: postgres.h:411
#define Int32GetDatum(X)
Definition: postgres.h:523
#define CharGetDatum(X)
Definition: postgres.h:460
TupleDesc rd_att
Definition: rel.h:110

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

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

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

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

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

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

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

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

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

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

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

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 generate_unaccent_rules::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 481 of file pg_shdepend.c.

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

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

Referenced by ExecGrant_Attribute(), ExecGrant_Database(), ExecGrant_Fdw(), ExecGrant_ForeignServer(), ExecGrant_Function(), ExecGrant_Language(), ExecGrant_Largeobject(), ExecGrant_Namespace(), ExecGrant_Parameter(), ExecGrant_Relation(), ExecGrant_Tablespace(), ExecGrant_Type(), recordDependencyOnNewAcl(), and SetDefaultACL().