PostgreSQL Source Code  git master
dependency.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/heap.h"
#include "catalog/index.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_depend.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_init_privs.h"
#include "catalog/pg_language.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_parameter_acl.h"
#include "catalog/pg_policy.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication.h"
#include "catalog/pg_publication_namespace.h"
#include "catalog/pg_publication_rel.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_subscription.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_transform.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_dict.h"
#include "catalog/pg_ts_parser.h"
#include "catalog/pg_ts_template.h"
#include "catalog/pg_type.h"
#include "catalog/pg_user_mapping.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/policy.h"
#include "commands/publicationcmds.h"
#include "commands/seclabel.h"
#include "commands/sequence.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteRemove.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for dependency.c:

Go to the source code of this file.

Data Structures

struct  ObjectAddressExtra
 
struct  ObjectAddresses
 
struct  ObjectAddressStack
 
struct  ObjectAddressAndFlags
 
struct  find_expr_references_context
 

Macros

#define DEPFLAG_ORIGINAL   0x0001 /* an original deletion target */
 
#define DEPFLAG_NORMAL   0x0002 /* reached via normal dependency */
 
#define DEPFLAG_AUTO   0x0004 /* reached via auto dependency */
 
#define DEPFLAG_INTERNAL   0x0008 /* reached via internal dependency */
 
#define DEPFLAG_PARTITION   0x0010 /* reached via partition dependency */
 
#define DEPFLAG_EXTENSION   0x0020 /* reached via extension dependency */
 
#define DEPFLAG_REVERSE   0x0040 /* reverse internal/extension link */
 
#define DEPFLAG_IS_PART   0x0080 /* has a partition dependency */
 
#define DEPFLAG_SUBOBJECT   0x0100 /* subobject of another deletable object */
 
#define MAX_REPORTED_DEPS   100
 

Typedefs

typedef struct ObjectAddressStack ObjectAddressStack
 

Functions

 StaticAssertDecl (lengthof(object_classes)==LAST_OCLASS+1, "object_classes[] must cover all ObjectClasses")
 
static void findDependentObjects (const ObjectAddress *object, int objflags, int flags, ObjectAddressStack *stack, ObjectAddresses *targetObjects, const ObjectAddresses *pendingObjects, Relation *depRel)
 
static void reportDependentObjects (const ObjectAddresses *targetObjects, DropBehavior behavior, int flags, const ObjectAddress *origObject)
 
static void deleteOneObject (const ObjectAddress *object, Relation *depRel, int32 flags)
 
static void doDeletion (const ObjectAddress *object, int flags)
 
static bool find_expr_references_walker (Node *node, find_expr_references_context *context)
 
static void process_function_rte_ref (RangeTblEntry *rte, AttrNumber attnum, find_expr_references_context *context)
 
static void eliminate_duplicate_dependencies (ObjectAddresses *addrs)
 
static int object_address_comparator (const void *a, const void *b)
 
static void add_object_address (ObjectClass oclass, Oid objectId, int32 subId, ObjectAddresses *addrs)
 
static void add_exact_object_address_extra (const ObjectAddress *object, const ObjectAddressExtra *extra, ObjectAddresses *addrs)
 
static bool object_address_present_add_flags (const ObjectAddress *object, int flags, ObjectAddresses *addrs)
 
static bool stack_address_present_add_flags (const ObjectAddress *object, int flags, ObjectAddressStack *stack)
 
static void DeleteInitPrivs (const ObjectAddress *object)
 
static void deleteObjectsInList (ObjectAddresses *targetObjects, Relation *depRel, int flags)
 
void performDeletion (const ObjectAddress *object, DropBehavior behavior, int flags)
 
void performMultipleDeletions (const ObjectAddresses *objects, DropBehavior behavior, int flags)
 
static void DropObjectById (const ObjectAddress *object)
 
static void deleteOneObject (const ObjectAddress *object, Relation *depRel, int flags)
 
void AcquireDeletionLock (const ObjectAddress *object, int flags)
 
void ReleaseDeletionLock (const ObjectAddress *object)
 
void recordDependencyOnExpr (const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
 
void recordDependencyOnSingleRelExpr (const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
 
ObjectAddressesnew_object_addresses (void)
 
void add_exact_object_address (const ObjectAddress *object, ObjectAddresses *addrs)
 
bool object_address_present (const ObjectAddress *object, const ObjectAddresses *addrs)
 
void record_object_address_dependencies (const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
 
void sort_object_addresses (ObjectAddresses *addrs)
 
void free_object_addresses (ObjectAddresses *addrs)
 
ObjectClass getObjectClass (const ObjectAddress *object)
 

Variables

static const Oid object_classes []
 

Macro Definition Documentation

◆ DEPFLAG_AUTO

#define DEPFLAG_AUTO   0x0004 /* reached via auto dependency */

Definition at line 105 of file dependency.c.

◆ DEPFLAG_EXTENSION

#define DEPFLAG_EXTENSION   0x0020 /* reached via extension dependency */

Definition at line 108 of file dependency.c.

◆ DEPFLAG_INTERNAL

#define DEPFLAG_INTERNAL   0x0008 /* reached via internal dependency */

Definition at line 106 of file dependency.c.

◆ DEPFLAG_IS_PART

#define DEPFLAG_IS_PART   0x0080 /* has a partition dependency */

Definition at line 110 of file dependency.c.

◆ DEPFLAG_NORMAL

#define DEPFLAG_NORMAL   0x0002 /* reached via normal dependency */

Definition at line 104 of file dependency.c.

◆ DEPFLAG_ORIGINAL

#define DEPFLAG_ORIGINAL   0x0001 /* an original deletion target */

Definition at line 103 of file dependency.c.

◆ DEPFLAG_PARTITION

#define DEPFLAG_PARTITION   0x0010 /* reached via partition dependency */

Definition at line 107 of file dependency.c.

◆ DEPFLAG_REVERSE

#define DEPFLAG_REVERSE   0x0040 /* reverse internal/extension link */

Definition at line 109 of file dependency.c.

◆ DEPFLAG_SUBOBJECT

#define DEPFLAG_SUBOBJECT   0x0100 /* subobject of another deletable object */

Definition at line 111 of file dependency.c.

◆ MAX_REPORTED_DEPS

#define MAX_REPORTED_DEPS   100

Typedef Documentation

◆ ObjectAddressStack

Function Documentation

◆ AcquireDeletionLock()

void AcquireDeletionLock ( const ObjectAddress object,
int  flags 
)

Definition at line 1552 of file dependency.c.

1553 {
1554  if (object->classId == RelationRelationId)
1555  {
1556  /*
1557  * In DROP INDEX CONCURRENTLY, take only ShareUpdateExclusiveLock on
1558  * the index for the moment. index_drop() will promote the lock once
1559  * it's safe to do so. In all other cases we need full exclusive
1560  * lock.
1561  */
1562  if (flags & PERFORM_DELETION_CONCURRENTLY)
1564  else
1566  }
1567  else if (object->classId == AuthMemRelationId)
1568  LockSharedObject(object->classId, object->objectId, 0,
1570  else
1571  {
1572  /* assume we should lock the whole object not a sub-object */
1573  LockDatabaseObject(object->classId, object->objectId, 0,
1575  }
1576 }
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:137
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1046
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1005
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39

References AccessExclusiveLock, ObjectAddress::classId, ObjectAddressStack::flags, LockDatabaseObject(), LockRelationOid(), LockSharedObject(), ObjectAddressStack::object, ObjectAddress::objectId, PERFORM_DELETION_CONCURRENTLY, and ShareUpdateExclusiveLock.

Referenced by findDependentObjects(), performDeletion(), performMultipleDeletions(), and shdepDropOwned().

◆ add_exact_object_address()

void add_exact_object_address ( const ObjectAddress object,
ObjectAddresses addrs 
)

Definition at line 2588 of file dependency.c.

2590 {
2591  ObjectAddress *item;
2592 
2593  /* enlarge array if needed */
2594  if (addrs->numrefs >= addrs->maxrefs)
2595  {
2596  addrs->maxrefs *= 2;
2597  addrs->refs = (ObjectAddress *)
2598  repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
2599  Assert(!addrs->extras);
2600  }
2601  /* record this item */
2602  item = addrs->refs + addrs->numrefs;
2603  *item = *object;
2604  addrs->numrefs++;
2605 }
Assert(fmt[strlen(fmt) - 1] !='\n')
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1451
ObjectAddressExtra * extras
Definition: dependency.c:118
ObjectAddress * refs
Definition: dependency.c:117

References Assert(), ObjectAddresses::extras, ObjectAddresses::maxrefs, ObjectAddresses::numrefs, ObjectAddressStack::object, ObjectAddresses::refs, and repalloc().

Referenced by AggregateCreate(), AlterConstraintNamespaces(), AlterIndexNamespaces(), AlterRelationNamespaceInternal(), AlterTypeNamespaceInternal(), ATExecDropColumn(), ATPostAlterTypeCleanup(), CastCreate(), CreateConstraintEntry(), CreateProceduralLanguage(), CreateTransform(), DropClonedTriggersFromPartition(), GenerateTypeDependencies(), heap_create_with_catalog(), index_create(), InsertExtensionTuple(), makeConfigurationDependencies(), makeDictionaryDependencies(), makeOperatorDependencies(), makeParserDependencies(), makeTSTemplateDependencies(), PreCommit_on_commit_actions(), ProcedureCreate(), RangeCreate(), recordDependencyOnSingleRelExpr(), ReindexRelationConcurrently(), RemoveObjects(), RemoveRelations(), shdepDropOwned(), and StorePartitionKey().

◆ add_exact_object_address_extra()

static void add_exact_object_address_extra ( const ObjectAddress object,
const ObjectAddressExtra extra,
ObjectAddresses addrs 
)
static

Definition at line 2613 of file dependency.c.

2616 {
2617  ObjectAddress *item;
2618  ObjectAddressExtra *itemextra;
2619 
2620  /* allocate extra space if first time */
2621  if (!addrs->extras)
2622  addrs->extras = (ObjectAddressExtra *)
2623  palloc(addrs->maxrefs * sizeof(ObjectAddressExtra));
2624 
2625  /* enlarge array if needed */
2626  if (addrs->numrefs >= addrs->maxrefs)
2627  {
2628  addrs->maxrefs *= 2;
2629  addrs->refs = (ObjectAddress *)
2630  repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
2631  addrs->extras = (ObjectAddressExtra *)
2632  repalloc(addrs->extras, addrs->maxrefs * sizeof(ObjectAddressExtra));
2633  }
2634  /* record this item */
2635  item = addrs->refs + addrs->numrefs;
2636  *item = *object;
2637  itemextra = addrs->extras + addrs->numrefs;
2638  *itemextra = *extra;
2639  addrs->numrefs++;
2640 }
void * palloc(Size size)
Definition: mcxt.c:1201

References ObjectAddresses::extras, ObjectAddresses::maxrefs, ObjectAddresses::numrefs, ObjectAddressStack::object, palloc(), ObjectAddresses::refs, and repalloc().

Referenced by findDependentObjects().

◆ add_object_address()

static void add_object_address ( ObjectClass  oclass,
Oid  objectId,
int32  subId,
ObjectAddresses addrs 
)
static

Definition at line 2561 of file dependency.c.

2563 {
2564  ObjectAddress *item;
2565 
2566  /* enlarge array if needed */
2567  if (addrs->numrefs >= addrs->maxrefs)
2568  {
2569  addrs->maxrefs *= 2;
2570  addrs->refs = (ObjectAddress *)
2571  repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
2572  Assert(!addrs->extras);
2573  }
2574  /* record this item */
2575  item = addrs->refs + addrs->numrefs;
2576  item->classId = object_classes[oclass];
2577  item->objectId = objectId;
2578  item->objectSubId = subId;
2579  addrs->numrefs++;
2580 }
static const Oid object_classes[]
Definition: dependency.c:151

References Assert(), ObjectAddress::classId, ObjectAddresses::extras, ObjectAddresses::maxrefs, ObjectAddresses::numrefs, object_classes, ObjectAddress::objectId, ObjectAddress::objectSubId, ObjectAddresses::refs, and repalloc().

Referenced by find_expr_references_walker(), and process_function_rte_ref().

◆ DeleteInitPrivs()

static void DeleteInitPrivs ( const ObjectAddress object)
static

Definition at line 2987 of file dependency.c.

2988 {
2989  Relation relation;
2990  ScanKeyData key[3];
2991  SysScanDesc scan;
2992  HeapTuple oldtuple;
2993 
2994  relation = table_open(InitPrivsRelationId, RowExclusiveLock);
2995 
2996  ScanKeyInit(&key[0],
2997  Anum_pg_init_privs_objoid,
2998  BTEqualStrategyNumber, F_OIDEQ,
2999  ObjectIdGetDatum(object->objectId));
3000  ScanKeyInit(&key[1],
3001  Anum_pg_init_privs_classoid,
3002  BTEqualStrategyNumber, F_OIDEQ,
3003  ObjectIdGetDatum(object->classId));
3004  ScanKeyInit(&key[2],
3005  Anum_pg_init_privs_objsubid,
3006  BTEqualStrategyNumber, F_INT4EQ,
3007  Int32GetDatum(object->objectSubId));
3008 
3009  scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
3010  NULL, 3, key);
3011 
3012  while (HeapTupleIsValid(oldtuple = systable_getnext(scan)))
3013  CatalogTupleDelete(relation, &oldtuple->t_self);
3014 
3015  systable_endscan(scan);
3016 
3017  table_close(relation, RowExclusiveLock);
3018 }
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
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
#define RowExclusiveLock
Definition: lockdefs.h:38
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
ItemPointerData t_self
Definition: htup.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References BTEqualStrategyNumber, CatalogTupleDelete(), ObjectAddress::classId, HeapTupleIsValid, Int32GetDatum(), sort-test::key, ObjectAddressStack::object, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by deleteOneObject().

◆ deleteObjectsInList()

static void deleteObjectsInList ( ObjectAddresses targetObjects,
Relation depRel,
int  flags 
)
static

Definition at line 241 of file dependency.c.

243 {
244  int i;
245 
246  /*
247  * Keep track of objects for event triggers, if necessary.
248  */
250  {
251  for (i = 0; i < targetObjects->numrefs; i++)
252  {
253  const ObjectAddress *thisobj = &targetObjects->refs[i];
254  const ObjectAddressExtra *extra = &targetObjects->extras[i];
255  bool original = false;
256  bool normal = false;
257 
258  if (extra->flags & DEPFLAG_ORIGINAL)
259  original = true;
260  if (extra->flags & DEPFLAG_NORMAL)
261  normal = true;
262  if (extra->flags & DEPFLAG_REVERSE)
263  normal = true;
264 
266  {
267  EventTriggerSQLDropAddObject(thisobj, original, normal);
268  }
269  }
270  }
271 
272  /*
273  * Delete all the objects in the proper order, except that if told to, we
274  * should skip the original object(s).
275  */
276  for (i = 0; i < targetObjects->numrefs; i++)
277  {
278  ObjectAddress *thisobj = targetObjects->refs + i;
279  ObjectAddressExtra *thisextra = targetObjects->extras + i;
280 
281  if ((flags & PERFORM_DELETION_SKIP_ORIGINAL) &&
282  (thisextra->flags & DEPFLAG_ORIGINAL))
283  continue;
284 
285  deleteOneObject(thisobj, depRel, flags);
286  }
287 }
ObjectClass getObjectClass(const ObjectAddress *object)
Definition: dependency.c:2843
static void deleteOneObject(const ObjectAddress *object, Relation *depRel, int32 flags)
#define DEPFLAG_ORIGINAL
Definition: dependency.c:103
#define DEPFLAG_REVERSE
Definition: dependency.c:109
#define DEPFLAG_NORMAL
Definition: dependency.c:104
#define PERFORM_DELETION_SKIP_ORIGINAL
Definition: dependency.h:139
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:136
void EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
bool trackDroppedObjectsNeeded(void)
bool EventTriggerSupportsObjectClass(ObjectClass objclass)
int i
Definition: isn.c:73

References deleteOneObject(), DEPFLAG_NORMAL, DEPFLAG_ORIGINAL, DEPFLAG_REVERSE, EventTriggerSQLDropAddObject(), EventTriggerSupportsObjectClass(), ObjectAddresses::extras, ObjectAddressExtra::flags, ObjectAddressStack::flags, getObjectClass(), i, ObjectAddresses::numrefs, PERFORM_DELETION_INTERNAL, PERFORM_DELETION_SKIP_ORIGINAL, ObjectAddresses::refs, and trackDroppedObjectsNeeded().

Referenced by performDeletion(), and performMultipleDeletions().

◆ deleteOneObject() [1/2]

static void deleteOneObject ( const ObjectAddress object,
Relation depRel,
int  flags 
)
static

Definition at line 1302 of file dependency.c.

1303 {
1304  ScanKeyData key[3];
1305  int nkeys;
1306  SysScanDesc scan;
1307  HeapTuple tup;
1308 
1309  /* DROP hook of the objects being removed */
1310  InvokeObjectDropHookArg(object->classId, object->objectId,
1311  object->objectSubId, flags);
1312 
1313  /*
1314  * Close depRel if we are doing a drop concurrently. The object deletion
1315  * subroutine will commit the current transaction, so we can't keep the
1316  * relation open across doDeletion().
1317  */
1318  if (flags & PERFORM_DELETION_CONCURRENTLY)
1319  table_close(*depRel, RowExclusiveLock);
1320 
1321  /*
1322  * Delete the object itself, in an object-type-dependent way.
1323  *
1324  * We used to do this after removing the outgoing dependency links, but it
1325  * seems just as reasonable to do it beforehand. In the concurrent case
1326  * we *must* do it in this order, because we can't make any transactional
1327  * updates before calling doDeletion() --- they'd get committed right
1328  * away, which is not cool if the deletion then fails.
1329  */
1330  doDeletion(object, flags);
1331 
1332  /*
1333  * Reopen depRel if we closed it above
1334  */
1335  if (flags & PERFORM_DELETION_CONCURRENTLY)
1336  *depRel = table_open(DependRelationId, RowExclusiveLock);
1337 
1338  /*
1339  * Now remove any pg_depend records that link from this object to others.
1340  * (Any records linking to this object should be gone already.)
1341  *
1342  * When dropping a whole object (subId = 0), remove all pg_depend records
1343  * for its sub-objects too.
1344  */
1345  ScanKeyInit(&key[0],
1346  Anum_pg_depend_classid,
1347  BTEqualStrategyNumber, F_OIDEQ,
1348  ObjectIdGetDatum(object->classId));
1349  ScanKeyInit(&key[1],
1350  Anum_pg_depend_objid,
1351  BTEqualStrategyNumber, F_OIDEQ,
1352  ObjectIdGetDatum(object->objectId));
1353  if (object->objectSubId != 0)
1354  {
1355  ScanKeyInit(&key[2],
1356  Anum_pg_depend_objsubid,
1357  BTEqualStrategyNumber, F_INT4EQ,
1358  Int32GetDatum(object->objectSubId));
1359  nkeys = 3;
1360  }
1361  else
1362  nkeys = 2;
1363 
1364  scan = systable_beginscan(*depRel, DependDependerIndexId, true,
1365  NULL, nkeys, key);
1366 
1367  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1368  {
1369  CatalogTupleDelete(*depRel, &tup->t_self);
1370  }
1371 
1372  systable_endscan(scan);
1373 
1374  /*
1375  * Delete shared dependency references related to this object. Again, if
1376  * subId = 0, remove records for sub-objects too.
1377  */
1379  object->objectSubId);
1380 
1381 
1382  /*
1383  * Delete any comments, security labels, or initial privileges associated
1384  * with this object. (This is a convenient place to do these things,
1385  * rather than having every object type know to do it.)
1386  */
1387  DeleteComments(object->objectId, object->classId, object->objectSubId);
1388  DeleteSecurityLabel(object);
1389  DeleteInitPrivs(object);
1390 
1391  /*
1392  * CommandCounterIncrement here to ensure that preceding changes are all
1393  * visible to the next deletion step.
1394  */
1396 
1397  /*
1398  * And we're done!
1399  */
1400 }
void DeleteComments(Oid oid, Oid classoid, int32 subid)
Definition: comment.c:326
static void doDeletion(const ObjectAddress *object, int flags)
Definition: dependency.c:1406
static void DeleteInitPrivs(const ObjectAddress *object)
Definition: dependency.c:2987
#define InvokeObjectDropHookArg(classId, objectId, subId, dropflags)
Definition: objectaccess.h:184
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:1002
void DeleteSecurityLabel(const ObjectAddress *object)
Definition: seclabel.c:523
void CommandCounterIncrement(void)
Definition: xact.c:1078

References BTEqualStrategyNumber, CatalogTupleDelete(), ObjectAddress::classId, CommandCounterIncrement(), DeleteComments(), DeleteInitPrivs(), DeleteSecurityLabel(), deleteSharedDependencyRecordsFor(), doDeletion(), ObjectAddressStack::flags, HeapTupleIsValid, Int32GetDatum(), InvokeObjectDropHookArg, sort-test::key, ObjectAddressStack::object, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, PERFORM_DELETION_CONCURRENTLY, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

◆ deleteOneObject() [2/2]

static void deleteOneObject ( const ObjectAddress object,
Relation depRel,
int32  flags 
)
static

Referenced by deleteObjectsInList().

◆ doDeletion()

static void doDeletion ( const ObjectAddress object,
int  flags 
)
static

Definition at line 1406 of file dependency.c.

1407 {
1408  switch (getObjectClass(object))
1409  {
1410  case OCLASS_CLASS:
1411  {
1412  char relKind = get_rel_relkind(object->objectId);
1413 
1414  if (relKind == RELKIND_INDEX ||
1415  relKind == RELKIND_PARTITIONED_INDEX)
1416  {
1417  bool concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) != 0);
1418  bool concurrent_lock_mode = ((flags & PERFORM_DELETION_CONCURRENT_LOCK) != 0);
1419 
1420  Assert(object->objectSubId == 0);
1421  index_drop(object->objectId, concurrent, concurrent_lock_mode);
1422  }
1423  else
1424  {
1425  if (object->objectSubId != 0)
1426  RemoveAttributeById(object->objectId,
1427  object->objectSubId);
1428  else
1430  }
1431 
1432  /*
1433  * for a sequence, in addition to dropping the heap, also
1434  * delete pg_sequence tuple
1435  */
1436  if (relKind == RELKIND_SEQUENCE)
1437  DeleteSequenceTuple(object->objectId);
1438  break;
1439  }
1440 
1441  case OCLASS_PROC:
1442  RemoveFunctionById(object->objectId);
1443  break;
1444 
1445  case OCLASS_TYPE:
1446  RemoveTypeById(object->objectId);
1447  break;
1448 
1449  case OCLASS_CONSTRAINT:
1450  RemoveConstraintById(object->objectId);
1451  break;
1452 
1453  case OCLASS_DEFAULT:
1455  break;
1456 
1457  case OCLASS_LARGEOBJECT:
1458  LargeObjectDrop(object->objectId);
1459  break;
1460 
1461  case OCLASS_OPERATOR:
1462  RemoveOperatorById(object->objectId);
1463  break;
1464 
1465  case OCLASS_REWRITE:
1467  break;
1468 
1469  case OCLASS_TRIGGER:
1470  RemoveTriggerById(object->objectId);
1471  break;
1472 
1473  case OCLASS_STATISTIC_EXT:
1474  RemoveStatisticsById(object->objectId);
1475  break;
1476 
1477  case OCLASS_TSCONFIG:
1479  break;
1480 
1481  case OCLASS_EXTENSION:
1482  RemoveExtensionById(object->objectId);
1483  break;
1484 
1485  case OCLASS_POLICY:
1486  RemovePolicyById(object->objectId);
1487  break;
1488 
1491  break;
1492 
1495  break;
1496 
1497  case OCLASS_PUBLICATION:
1499  break;
1500 
1501  case OCLASS_CAST:
1502  case OCLASS_COLLATION:
1503  case OCLASS_CONVERSION:
1504  case OCLASS_LANGUAGE:
1505  case OCLASS_OPCLASS:
1506  case OCLASS_OPFAMILY:
1507  case OCLASS_AM:
1508  case OCLASS_AMOP:
1509  case OCLASS_AMPROC:
1510  case OCLASS_SCHEMA:
1511  case OCLASS_TSPARSER:
1512  case OCLASS_TSDICT:
1513  case OCLASS_TSTEMPLATE:
1514  case OCLASS_FDW:
1515  case OCLASS_FOREIGN_SERVER:
1516  case OCLASS_USER_MAPPING:
1517  case OCLASS_DEFACL:
1518  case OCLASS_EVENT_TRIGGER:
1519  case OCLASS_TRANSFORM:
1521  DropObjectById(object);
1522  break;
1523 
1524  /*
1525  * These global object types are not supported here.
1526  */
1527  case OCLASS_ROLE:
1528  case OCLASS_DATABASE:
1529  case OCLASS_TBLSPACE:
1530  case OCLASS_SUBSCRIPTION:
1531  case OCLASS_PARAMETER_ACL:
1532  elog(ERROR, "global objects cannot be deleted by doDeletion");
1533  break;
1534 
1535  /*
1536  * There's intentionally no default: case here; we want the
1537  * compiler to warn if a new OCLASS hasn't been handled above.
1538  */
1539  }
1540 }
static void DropObjectById(const ObjectAddress *object)
Definition: dependency.c:1245
#define PERFORM_DELETION_CONCURRENT_LOCK
Definition: dependency.h:141
@ OCLASS_OPERATOR
Definition: dependency.h:100
@ OCLASS_PARAMETER_ACL
Definition: dependency.h:124
@ OCLASS_LARGEOBJECT
Definition: dependency.h:99
@ OCLASS_FDW
Definition: dependency.h:118
@ OCLASS_OPFAMILY
Definition: dependency.h:102
@ OCLASS_DEFACL
Definition: dependency.h:121
@ OCLASS_TSPARSER
Definition: dependency.h:110
@ OCLASS_TRIGGER
Definition: dependency.h:107
@ OCLASS_DEFAULT
Definition: dependency.h:97
@ OCLASS_TSTEMPLATE
Definition: dependency.h:112
@ OCLASS_AMPROC
Definition: dependency.h:105
@ OCLASS_TBLSPACE
Definition: dependency.h:117
@ OCLASS_TSCONFIG
Definition: dependency.h:113
@ OCLASS_TYPE
Definition: dependency.h:92
@ OCLASS_LANGUAGE
Definition: dependency.h:98
@ OCLASS_CAST
Definition: dependency.h:93
@ OCLASS_SUBSCRIPTION
Definition: dependency.h:129
@ OCLASS_PUBLICATION_NAMESPACE
Definition: dependency.h:127
@ OCLASS_EXTENSION
Definition: dependency.h:122
@ OCLASS_COLLATION
Definition: dependency.h:94
@ OCLASS_FOREIGN_SERVER
Definition: dependency.h:119
@ OCLASS_REWRITE
Definition: dependency.h:106
@ OCLASS_STATISTIC_EXT
Definition: dependency.h:109
@ OCLASS_PROC
Definition: dependency.h:91
@ OCLASS_OPCLASS
Definition: dependency.h:101
@ OCLASS_CONVERSION
Definition: dependency.h:96
@ OCLASS_DATABASE
Definition: dependency.h:116
@ OCLASS_ROLE_MEMBERSHIP
Definition: dependency.h:115
@ OCLASS_SCHEMA
Definition: dependency.h:108
@ OCLASS_EVENT_TRIGGER
Definition: dependency.h:123
@ OCLASS_CLASS
Definition: dependency.h:90
@ OCLASS_TRANSFORM
Definition: dependency.h:130
@ OCLASS_ROLE
Definition: dependency.h:114
@ OCLASS_CONSTRAINT
Definition: dependency.h:95
@ OCLASS_POLICY
Definition: dependency.h:125
@ OCLASS_USER_MAPPING
Definition: dependency.h:120
@ OCLASS_PUBLICATION_REL
Definition: dependency.h:128
@ OCLASS_AM
Definition: dependency.h:103
@ OCLASS_TSDICT
Definition: dependency.h:111
@ OCLASS_PUBLICATION
Definition: dependency.h:126
@ OCLASS_AMOP
Definition: dependency.h:104
#define ERROR
Definition: elog.h:39
void RemoveExtensionById(Oid extId)
Definition: extension.c:1953
void RemoveFunctionById(Oid funcOid)
void RemoveAttributeById(Oid relid, AttrNumber attnum)
Definition: heap.c:1646
void heap_drop_with_catalog(Oid relid)
Definition: heap.c:1747
void index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
Definition: index.c:2148
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1980
void RemoveOperatorById(Oid operOid)
Definition: operatorcmds.c:416
void RemoveAttrDefaultById(Oid attrdefId)
Definition: pg_attrdef.c:268
void RemoveConstraintById(Oid conId)
void LargeObjectDrop(Oid loid)
void RemovePolicyById(Oid policy_id)
Definition: policy.c:335
void RemovePublicationSchemaById(Oid psoid)
void RemovePublicationById(Oid pubid)
void RemovePublicationRelById(Oid proid)
void RemoveRewriteRuleById(Oid ruleOid)
Definition: rewriteRemove.c:39
void DeleteSequenceTuple(Oid relid)
Definition: sequence.c:562
void RemoveStatisticsById(Oid statsOid)
Definition: statscmds.c:734
void RemoveTriggerById(Oid trigOid)
Definition: trigger.c:1294
void RemoveTSConfigurationById(Oid cfgId)
Definition: tsearchcmds.c:1108
void RemoveTypeById(Oid typeOid)
Definition: typecmds.c:653

References Assert(), DeleteSequenceTuple(), DropObjectById(), elog(), ERROR, ObjectAddressStack::flags, get_rel_relkind(), getObjectClass(), heap_drop_with_catalog(), index_drop(), LargeObjectDrop(), ObjectAddressStack::object, ObjectAddress::objectId, ObjectAddress::objectSubId, OCLASS_AM, OCLASS_AMOP, OCLASS_AMPROC, OCLASS_CAST, OCLASS_CLASS, OCLASS_COLLATION, OCLASS_CONSTRAINT, OCLASS_CONVERSION, OCLASS_DATABASE, OCLASS_DEFACL, OCLASS_DEFAULT, OCLASS_EVENT_TRIGGER, OCLASS_EXTENSION, OCLASS_FDW, OCLASS_FOREIGN_SERVER, OCLASS_LANGUAGE, OCLASS_LARGEOBJECT, OCLASS_OPCLASS, OCLASS_OPERATOR, OCLASS_OPFAMILY, OCLASS_PARAMETER_ACL, OCLASS_POLICY, OCLASS_PROC, OCLASS_PUBLICATION, OCLASS_PUBLICATION_NAMESPACE, OCLASS_PUBLICATION_REL, OCLASS_REWRITE, OCLASS_ROLE, OCLASS_ROLE_MEMBERSHIP, OCLASS_SCHEMA, OCLASS_STATISTIC_EXT, OCLASS_SUBSCRIPTION, OCLASS_TBLSPACE, OCLASS_TRANSFORM, OCLASS_TRIGGER, OCLASS_TSCONFIG, OCLASS_TSDICT, OCLASS_TSPARSER, OCLASS_TSTEMPLATE, OCLASS_TYPE, OCLASS_USER_MAPPING, PERFORM_DELETION_CONCURRENT_LOCK, PERFORM_DELETION_CONCURRENTLY, RemoveAttrDefaultById(), RemoveAttributeById(), RemoveConstraintById(), RemoveExtensionById(), RemoveFunctionById(), RemoveOperatorById(), RemovePolicyById(), RemovePublicationById(), RemovePublicationRelById(), RemovePublicationSchemaById(), RemoveRewriteRuleById(), RemoveStatisticsById(), RemoveTriggerById(), RemoveTSConfigurationById(), and RemoveTypeById().

Referenced by deleteOneObject().

◆ DropObjectById()

static void DropObjectById ( const ObjectAddress object)
static

Definition at line 1245 of file dependency.c.

1246 {
1247  int cacheId;
1248  Relation rel;
1249  HeapTuple tup;
1250 
1251  cacheId = get_object_catcache_oid(object->classId);
1252 
1253  rel = table_open(object->classId, RowExclusiveLock);
1254 
1255  /*
1256  * Use the system cache for the oid column, if one exists.
1257  */
1258  if (cacheId >= 0)
1259  {
1260  tup = SearchSysCache1(cacheId, ObjectIdGetDatum(object->objectId));
1261  if (!HeapTupleIsValid(tup))
1262  elog(ERROR, "cache lookup failed for %s %u",
1263  get_object_class_descr(object->classId), object->objectId);
1264 
1265  CatalogTupleDelete(rel, &tup->t_self);
1266 
1267  ReleaseSysCache(tup);
1268  }
1269  else
1270  {
1271  ScanKeyData skey[1];
1272  SysScanDesc scan;
1273 
1274  ScanKeyInit(&skey[0],
1275  get_object_attnum_oid(object->classId),
1276  BTEqualStrategyNumber, F_OIDEQ,
1277  ObjectIdGetDatum(object->objectId));
1278 
1279  scan = systable_beginscan(rel, get_object_oid_index(object->classId), true,
1280  NULL, 1, skey);
1281 
1282  /* we expect exactly one match */
1283  tup = systable_getnext(scan);
1284  if (!HeapTupleIsValid(tup))
1285  elog(ERROR, "could not find tuple for %s %u",
1286  get_object_class_descr(object->classId), object->objectId);
1287 
1288  CatalogTupleDelete(rel, &tup->t_self);
1289 
1290  systable_endscan(scan);
1291  }
1292 
1294 }
AttrNumber get_object_attnum_oid(Oid class_id)
int get_object_catcache_oid(Oid class_id)
Oid get_object_oid_index(Oid class_id)
const char * get_object_class_descr(Oid class_id)
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:267
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:219

References BTEqualStrategyNumber, CatalogTupleDelete(), ObjectAddress::classId, elog(), ERROR, get_object_attnum_oid(), get_object_catcache_oid(), get_object_class_descr(), get_object_oid_index(), HeapTupleIsValid, ObjectAddressStack::object, ObjectAddress::objectId, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ eliminate_duplicate_dependencies()

static void eliminate_duplicate_dependencies ( ObjectAddresses addrs)
static

Definition at line 2435 of file dependency.c.

2436 {
2437  ObjectAddress *priorobj;
2438  int oldref,
2439  newrefs;
2440 
2441  /*
2442  * We can't sort if the array has "extra" data, because there's no way to
2443  * keep it in sync. Fortunately that combination of features is not
2444  * needed.
2445  */
2446  Assert(!addrs->extras);
2447 
2448  if (addrs->numrefs <= 1)
2449  return; /* nothing to do */
2450 
2451  /* Sort the refs so that duplicates are adjacent */
2452  qsort(addrs->refs, addrs->numrefs, sizeof(ObjectAddress),
2454 
2455  /* Remove dups */
2456  priorobj = addrs->refs;
2457  newrefs = 1;
2458  for (oldref = 1; oldref < addrs->numrefs; oldref++)
2459  {
2460  ObjectAddress *thisobj = addrs->refs + oldref;
2461 
2462  if (priorobj->classId == thisobj->classId &&
2463  priorobj->objectId == thisobj->objectId)
2464  {
2465  if (priorobj->objectSubId == thisobj->objectSubId)
2466  continue; /* identical, so drop thisobj */
2467 
2468  /*
2469  * If we have a whole-object reference and a reference to a part
2470  * of the same object, we don't need the whole-object reference
2471  * (for example, we don't need to reference both table foo and
2472  * column foo.bar). The whole-object reference will always appear
2473  * first in the sorted list.
2474  */
2475  if (priorobj->objectSubId == 0)
2476  {
2477  /* replace whole ref with partial */
2478  priorobj->objectSubId = thisobj->objectSubId;
2479  continue;
2480  }
2481  }
2482  /* Not identical, so add thisobj to output set */
2483  priorobj++;
2484  *priorobj = *thisobj;
2485  newrefs++;
2486  }
2487 
2488  addrs->numrefs = newrefs;
2489 }
static int object_address_comparator(const void *a, const void *b)
Definition: dependency.c:2495
#define qsort(a, b, c, d)
Definition: port.h:449

References Assert(), ObjectAddress::classId, ObjectAddresses::extras, ObjectAddresses::numrefs, object_address_comparator(), ObjectAddress::objectId, ObjectAddress::objectSubId, qsort, and ObjectAddresses::refs.

Referenced by record_object_address_dependencies(), recordDependencyOnExpr(), and recordDependencyOnSingleRelExpr().

◆ find_expr_references_walker()

static bool find_expr_references_walker ( Node node,
find_expr_references_context context 
)
static

Definition at line 1754 of file dependency.c.

1756 {
1757  if (node == NULL)
1758  return false;
1759  if (IsA(node, Var))
1760  {
1761  Var *var = (Var *) node;
1762  List *rtable;
1763  RangeTblEntry *rte;
1764 
1765  /* Find matching rtable entry, or complain if not found */
1766  if (var->varlevelsup >= list_length(context->rtables))
1767  elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
1768  rtable = (List *) list_nth(context->rtables, var->varlevelsup);
1769  if (var->varno <= 0 || var->varno > list_length(rtable))
1770  elog(ERROR, "invalid varno %d", var->varno);
1771  rte = rt_fetch(var->varno, rtable);
1772 
1773  /*
1774  * A whole-row Var references no specific columns, so adds no new
1775  * dependency. (We assume that there is a whole-table dependency
1776  * arising from each underlying rangetable entry. While we could
1777  * record such a dependency when finding a whole-row Var that
1778  * references a relation directly, it's quite unclear how to extend
1779  * that to whole-row Vars for JOINs, so it seems better to leave the
1780  * responsibility with the range table. Note that this poses some
1781  * risks for identifying dependencies of stand-alone expressions:
1782  * whole-table references may need to be created separately.)
1783  */
1784  if (var->varattno == InvalidAttrNumber)
1785  return false;
1786  if (rte->rtekind == RTE_RELATION)
1787  {
1788  /* If it's a plain relation, reference this column */
1790  context->addrs);
1791  }
1792  else if (rte->rtekind == RTE_FUNCTION)
1793  {
1794  /* Might need to add a dependency on a composite type's column */
1795  /* (done out of line, because it's a bit bulky) */
1796  process_function_rte_ref(rte, var->varattno, context);
1797  }
1798 
1799  /*
1800  * Vars referencing other RTE types require no additional work. In
1801  * particular, a join alias Var can be ignored, because it must
1802  * reference a merged USING column. The relevant join input columns
1803  * will also be referenced in the join qual, and any type coercion
1804  * functions involved in the alias expression will be dealt with when
1805  * we scan the RTE itself.
1806  */
1807  return false;
1808  }
1809  else if (IsA(node, Const))
1810  {
1811  Const *con = (Const *) node;
1812  Oid objoid;
1813 
1814  /* A constant must depend on the constant's datatype */
1816  context->addrs);
1817 
1818  /*
1819  * We must also depend on the constant's collation: it could be
1820  * different from the datatype's, if a CollateExpr was const-folded to
1821  * a simple constant. However we can save work in the most common
1822  * case where the collation is "default", since we know that's pinned.
1823  */
1824  if (OidIsValid(con->constcollid) &&
1825  con->constcollid != DEFAULT_COLLATION_OID)
1826  add_object_address(OCLASS_COLLATION, con->constcollid, 0,
1827  context->addrs);
1828 
1829  /*
1830  * If it's a regclass or similar literal referring to an existing
1831  * object, add a reference to that object. (Currently, only the
1832  * regclass and regconfig cases have any likely use, but we may as
1833  * well handle all the OID-alias datatypes consistently.)
1834  */
1835  if (!con->constisnull)
1836  {
1837  switch (con->consttype)
1838  {
1839  case REGPROCOID:
1840  case REGPROCEDUREOID:
1841  objoid = DatumGetObjectId(con->constvalue);
1842  if (SearchSysCacheExists1(PROCOID,
1843  ObjectIdGetDatum(objoid)))
1844  add_object_address(OCLASS_PROC, objoid, 0,
1845  context->addrs);
1846  break;
1847  case REGOPEROID:
1848  case REGOPERATOROID:
1849  objoid = DatumGetObjectId(con->constvalue);
1850  if (SearchSysCacheExists1(OPEROID,
1851  ObjectIdGetDatum(objoid)))
1853  context->addrs);
1854  break;
1855  case REGCLASSOID:
1856  objoid = DatumGetObjectId(con->constvalue);
1857  if (SearchSysCacheExists1(RELOID,
1858  ObjectIdGetDatum(objoid)))
1859  add_object_address(OCLASS_CLASS, objoid, 0,
1860  context->addrs);
1861  break;
1862  case REGTYPEOID:
1863  objoid = DatumGetObjectId(con->constvalue);
1864  if (SearchSysCacheExists1(TYPEOID,
1865  ObjectIdGetDatum(objoid)))
1866  add_object_address(OCLASS_TYPE, objoid, 0,
1867  context->addrs);
1868  break;
1869  case REGCOLLATIONOID:
1870  objoid = DatumGetObjectId(con->constvalue);
1871  if (SearchSysCacheExists1(COLLOID,
1872  ObjectIdGetDatum(objoid)))
1874  context->addrs);
1875  break;
1876  case REGCONFIGOID:
1877  objoid = DatumGetObjectId(con->constvalue);
1878  if (SearchSysCacheExists1(TSCONFIGOID,
1879  ObjectIdGetDatum(objoid)))
1881  context->addrs);
1882  break;
1883  case REGDICTIONARYOID:
1884  objoid = DatumGetObjectId(con->constvalue);
1885  if (SearchSysCacheExists1(TSDICTOID,
1886  ObjectIdGetDatum(objoid)))
1887  add_object_address(OCLASS_TSDICT, objoid, 0,
1888  context->addrs);
1889  break;
1890 
1891  case REGNAMESPACEOID:
1892  objoid = DatumGetObjectId(con->constvalue);
1893  if (SearchSysCacheExists1(NAMESPACEOID,
1894  ObjectIdGetDatum(objoid)))
1895  add_object_address(OCLASS_SCHEMA, objoid, 0,
1896  context->addrs);
1897  break;
1898 
1899  /*
1900  * Dependencies for regrole should be shared among all
1901  * databases, so explicitly inhibit to have dependencies.
1902  */
1903  case REGROLEOID:
1904  ereport(ERROR,
1905  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1906  errmsg("constant of the type %s cannot be used here",
1907  "regrole")));
1908  break;
1909  }
1910  }
1911  return false;
1912  }
1913  else if (IsA(node, Param))
1914  {
1915  Param *param = (Param *) node;
1916 
1917  /* A parameter must depend on the parameter's datatype */
1919  context->addrs);
1920  /* and its collation, just as for Consts */
1921  if (OidIsValid(param->paramcollid) &&
1922  param->paramcollid != DEFAULT_COLLATION_OID)
1923  add_object_address(OCLASS_COLLATION, param->paramcollid, 0,
1924  context->addrs);
1925  }
1926  else if (IsA(node, FuncExpr))
1927  {
1928  FuncExpr *funcexpr = (FuncExpr *) node;
1929 
1930  add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
1931  context->addrs);
1932  /* fall through to examine arguments */
1933  }
1934  else if (IsA(node, OpExpr))
1935  {
1936  OpExpr *opexpr = (OpExpr *) node;
1937 
1939  context->addrs);
1940  /* fall through to examine arguments */
1941  }
1942  else if (IsA(node, DistinctExpr))
1943  {
1944  DistinctExpr *distinctexpr = (DistinctExpr *) node;
1945 
1946  add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
1947  context->addrs);
1948  /* fall through to examine arguments */
1949  }
1950  else if (IsA(node, NullIfExpr))
1951  {
1952  NullIfExpr *nullifexpr = (NullIfExpr *) node;
1953 
1954  add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
1955  context->addrs);
1956  /* fall through to examine arguments */
1957  }
1958  else if (IsA(node, ScalarArrayOpExpr))
1959  {
1960  ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
1961 
1963  context->addrs);
1964  /* fall through to examine arguments */
1965  }
1966  else if (IsA(node, Aggref))
1967  {
1968  Aggref *aggref = (Aggref *) node;
1969 
1971  context->addrs);
1972  /* fall through to examine arguments */
1973  }
1974  else if (IsA(node, WindowFunc))
1975  {
1976  WindowFunc *wfunc = (WindowFunc *) node;
1977 
1979  context->addrs);
1980  /* fall through to examine arguments */
1981  }
1982  else if (IsA(node, SubscriptingRef))
1983  {
1984  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1985 
1986  /*
1987  * The refexpr should provide adequate dependency on refcontainertype,
1988  * and that type in turn depends on refelemtype. However, a custom
1989  * subscripting handler might set refrestype to something different
1990  * from either of those, in which case we'd better record it.
1991  */
1992  if (sbsref->refrestype != sbsref->refcontainertype &&
1993  sbsref->refrestype != sbsref->refelemtype)
1994  add_object_address(OCLASS_TYPE, sbsref->refrestype, 0,
1995  context->addrs);
1996  /* fall through to examine arguments */
1997  }
1998  else if (IsA(node, SubPlan))
1999  {
2000  /* Extra work needed here if we ever need this case */
2001  elog(ERROR, "already-planned subqueries not supported");
2002  }
2003  else if (IsA(node, FieldSelect))
2004  {
2005  FieldSelect *fselect = (FieldSelect *) node;
2006  Oid argtype = getBaseType(exprType((Node *) fselect->arg));
2007  Oid reltype = get_typ_typrelid(argtype);
2008 
2009  /*
2010  * We need a dependency on the specific column named in FieldSelect,
2011  * assuming we can identify the pg_class OID for it. (Probably we
2012  * always can at the moment, but in future it might be possible for
2013  * argtype to be RECORDOID.) If we can make a column dependency then
2014  * we shouldn't need a dependency on the column's type; but if we
2015  * can't, make a dependency on the type, as it might not appear
2016  * anywhere else in the expression.
2017  */
2018  if (OidIsValid(reltype))
2019  add_object_address(OCLASS_CLASS, reltype, fselect->fieldnum,
2020  context->addrs);
2021  else
2022  add_object_address(OCLASS_TYPE, fselect->resulttype, 0,
2023  context->addrs);
2024  /* the collation might not be referenced anywhere else, either */
2025  if (OidIsValid(fselect->resultcollid) &&
2026  fselect->resultcollid != DEFAULT_COLLATION_OID)
2027  add_object_address(OCLASS_COLLATION, fselect->resultcollid, 0,
2028  context->addrs);
2029  }
2030  else if (IsA(node, FieldStore))
2031  {
2032  FieldStore *fstore = (FieldStore *) node;
2033  Oid reltype = get_typ_typrelid(fstore->resulttype);
2034 
2035  /* similar considerations to FieldSelect, but multiple column(s) */
2036  if (OidIsValid(reltype))
2037  {
2038  ListCell *l;
2039 
2040  foreach(l, fstore->fieldnums)
2042  context->addrs);
2043  }
2044  else
2045  add_object_address(OCLASS_TYPE, fstore->resulttype, 0,
2046  context->addrs);
2047  }
2048  else if (IsA(node, RelabelType))
2049  {
2050  RelabelType *relab = (RelabelType *) node;
2051 
2052  /* since there is no function dependency, need to depend on type */
2054  context->addrs);
2055  /* the collation might not be referenced anywhere else, either */
2056  if (OidIsValid(relab->resultcollid) &&
2057  relab->resultcollid != DEFAULT_COLLATION_OID)
2058  add_object_address(OCLASS_COLLATION, relab->resultcollid, 0,
2059  context->addrs);
2060  }
2061  else if (IsA(node, CoerceViaIO))
2062  {
2063  CoerceViaIO *iocoerce = (CoerceViaIO *) node;
2064 
2065  /* since there is no exposed function, need to depend on type */
2067  context->addrs);
2068  /* the collation might not be referenced anywhere else, either */
2069  if (OidIsValid(iocoerce->resultcollid) &&
2070  iocoerce->resultcollid != DEFAULT_COLLATION_OID)
2071  add_object_address(OCLASS_COLLATION, iocoerce->resultcollid, 0,
2072  context->addrs);
2073  }
2074  else if (IsA(node, ArrayCoerceExpr))
2075  {
2076  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
2077 
2078  /* as above, depend on type */
2080  context->addrs);
2081  /* the collation might not be referenced anywhere else, either */
2082  if (OidIsValid(acoerce->resultcollid) &&
2083  acoerce->resultcollid != DEFAULT_COLLATION_OID)
2084  add_object_address(OCLASS_COLLATION, acoerce->resultcollid, 0,
2085  context->addrs);
2086  /* fall through to examine arguments */
2087  }
2088  else if (IsA(node, ConvertRowtypeExpr))
2089  {
2090  ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
2091 
2092  /* since there is no function dependency, need to depend on type */
2094  context->addrs);
2095  }
2096  else if (IsA(node, CollateExpr))
2097  {
2098  CollateExpr *coll = (CollateExpr *) node;
2099 
2101  context->addrs);
2102  }
2103  else if (IsA(node, RowExpr))
2104  {
2105  RowExpr *rowexpr = (RowExpr *) node;
2106 
2107  add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0,
2108  context->addrs);
2109  }
2110  else if (IsA(node, RowCompareExpr))
2111  {
2112  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
2113  ListCell *l;
2114 
2115  foreach(l, rcexpr->opnos)
2116  {
2118  context->addrs);
2119  }
2120  foreach(l, rcexpr->opfamilies)
2121  {
2123  context->addrs);
2124  }
2125  /* fall through to examine arguments */
2126  }
2127  else if (IsA(node, CoerceToDomain))
2128  {
2129  CoerceToDomain *cd = (CoerceToDomain *) node;
2130 
2132  context->addrs);
2133  }
2134  else if (IsA(node, NextValueExpr))
2135  {
2136  NextValueExpr *nve = (NextValueExpr *) node;
2137 
2139  context->addrs);
2140  }
2141  else if (IsA(node, OnConflictExpr))
2142  {
2143  OnConflictExpr *onconflict = (OnConflictExpr *) node;
2144 
2145  if (OidIsValid(onconflict->constraint))
2147  context->addrs);
2148  /* fall through to examine arguments */
2149  }
2150  else if (IsA(node, SortGroupClause))
2151  {
2152  SortGroupClause *sgc = (SortGroupClause *) node;
2153 
2155  context->addrs);
2156  if (OidIsValid(sgc->sortop))
2158  context->addrs);
2159  return false;
2160  }
2161  else if (IsA(node, WindowClause))
2162  {
2163  WindowClause *wc = (WindowClause *) node;
2164 
2165  if (OidIsValid(wc->startInRangeFunc))
2166  add_object_address(OCLASS_PROC, wc->startInRangeFunc, 0,
2167  context->addrs);
2168  if (OidIsValid(wc->endInRangeFunc))
2169  add_object_address(OCLASS_PROC, wc->endInRangeFunc, 0,
2170  context->addrs);
2171  if (OidIsValid(wc->inRangeColl) &&
2172  wc->inRangeColl != DEFAULT_COLLATION_OID)
2173  add_object_address(OCLASS_COLLATION, wc->inRangeColl, 0,
2174  context->addrs);
2175  /* fall through to examine substructure */
2176  }
2177  else if (IsA(node, CTECycleClause))
2178  {
2179  CTECycleClause *cc = (CTECycleClause *) node;
2180 
2181  if (OidIsValid(cc->cycle_mark_type))
2183  context->addrs);
2186  context->addrs);
2187  if (OidIsValid(cc->cycle_mark_neop))
2189  context->addrs);
2190  /* fall through to examine substructure */
2191  }
2192  else if (IsA(node, Query))
2193  {
2194  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
2195  Query *query = (Query *) node;
2196  ListCell *lc;
2197  bool result;
2198 
2199  /*
2200  * Add whole-relation refs for each plain relation mentioned in the
2201  * subquery's rtable, and ensure we add refs for any type-coercion
2202  * functions used in join alias lists.
2203  *
2204  * Note: query_tree_walker takes care of recursing into RTE_FUNCTION
2205  * RTEs, subqueries, etc, so no need to do that here. But we must
2206  * tell it not to visit join alias lists, or we'll add refs for join
2207  * input columns whether or not they are actually used in our query.
2208  *
2209  * Note: we don't need to worry about collations mentioned in
2210  * RTE_VALUES or RTE_CTE RTEs, because those must just duplicate
2211  * collations referenced in other parts of the Query. We do have to
2212  * worry about collations mentioned in RTE_FUNCTION, but we take care
2213  * of those when we recurse to the RangeTblFunction node(s).
2214  */
2215  foreach(lc, query->rtable)
2216  {
2217  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2218 
2219  switch (rte->rtekind)
2220  {
2221  case RTE_RELATION:
2223  context->addrs);
2224  break;
2225  case RTE_JOIN:
2226 
2227  /*
2228  * Examine joinaliasvars entries only for merged JOIN
2229  * USING columns. Only those entries could contain
2230  * type-coercion functions. Also, their join input
2231  * columns must be referenced in the join quals, so this
2232  * won't accidentally add refs to otherwise-unused join
2233  * input columns. (We want to ref the type coercion
2234  * functions even if the merged column isn't explicitly
2235  * used anywhere, to protect possible expansion of the
2236  * join RTE as a whole-row var, and because it seems like
2237  * a bad idea to allow dropping a function that's present
2238  * in our query tree, whether or not it could get called.)
2239  */
2240  context->rtables = lcons(query->rtable, context->rtables);
2241  for (int i = 0; i < rte->joinmergedcols; i++)
2242  {
2243  Node *aliasvar = list_nth(rte->joinaliasvars, i);
2244 
2245  if (!IsA(aliasvar, Var))
2246  find_expr_references_walker(aliasvar, context);
2247  }
2248  context->rtables = list_delete_first(context->rtables);
2249  break;
2250  default:
2251  break;
2252  }
2253  }
2254 
2255  /*
2256  * If the query is an INSERT or UPDATE, we should create a dependency
2257  * on each target column, to prevent the specific target column from
2258  * being dropped. Although we will visit the TargetEntry nodes again
2259  * during query_tree_walker, we won't have enough context to do this
2260  * conveniently, so do it here.
2261  */
2262  if (query->commandType == CMD_INSERT ||
2263  query->commandType == CMD_UPDATE)
2264  {
2265  RangeTblEntry *rte;
2266 
2267  if (query->resultRelation <= 0 ||
2268  query->resultRelation > list_length(query->rtable))
2269  elog(ERROR, "invalid resultRelation %d",
2270  query->resultRelation);
2271  rte = rt_fetch(query->resultRelation, query->rtable);
2272  if (rte->rtekind == RTE_RELATION)
2273  {
2274  foreach(lc, query->targetList)
2275  {
2276  TargetEntry *tle = (TargetEntry *) lfirst(lc);
2277 
2278  if (tle->resjunk)
2279  continue; /* ignore junk tlist items */
2281  context->addrs);
2282  }
2283  }
2284  }
2285 
2286  /*
2287  * Add dependencies on constraints listed in query's constraintDeps
2288  */
2289  foreach(lc, query->constraintDeps)
2290  {
2292  context->addrs);
2293  }
2294 
2295  /* Examine substructure of query */
2296  context->rtables = lcons(query->rtable, context->rtables);
2297  result = query_tree_walker(query,
2299  (void *) context,
2302  context->rtables = list_delete_first(context->rtables);
2303  return result;
2304  }
2305  else if (IsA(node, SetOperationStmt))
2306  {
2307  SetOperationStmt *setop = (SetOperationStmt *) node;
2308 
2309  /* we need to look at the groupClauses for operator references */
2310  find_expr_references_walker((Node *) setop->groupClauses, context);
2311  /* fall through to examine child nodes */
2312  }
2313  else if (IsA(node, RangeTblFunction))
2314  {
2315  RangeTblFunction *rtfunc = (RangeTblFunction *) node;
2316  ListCell *ct;
2317 
2318  /*
2319  * Add refs for any datatypes and collations used in a column
2320  * definition list for a RECORD function. (For other cases, it should
2321  * be enough to depend on the function itself.)
2322  */
2323  foreach(ct, rtfunc->funccoltypes)
2324  {
2326  context->addrs);
2327  }
2328  foreach(ct, rtfunc->funccolcollations)
2329  {
2330  Oid collid = lfirst_oid(ct);
2331 
2332  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
2334  context->addrs);
2335  }
2336  }
2337  else if (IsA(node, TableFunc))
2338  {
2339  TableFunc *tf = (TableFunc *) node;
2340  ListCell *ct;
2341 
2342  /*
2343  * Add refs for the datatypes and collations used in the TableFunc.
2344  */
2345  foreach(ct, tf->coltypes)
2346  {
2348  context->addrs);
2349  }
2350  foreach(ct, tf->colcollations)
2351  {
2352  Oid collid = lfirst_oid(ct);
2353 
2354  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
2356  context->addrs);
2357  }
2358  }
2359  else if (IsA(node, TableSampleClause))
2360  {
2361  TableSampleClause *tsc = (TableSampleClause *) node;
2362 
2364  context->addrs);
2365  /* fall through to examine arguments */
2366  }
2367 
2369  (void *) context);
2370 }
#define InvalidAttrNumber
Definition: attnum.h:23
#define OidIsValid(objectId)
Definition: c.h:764
Oid collid
static bool find_expr_references_walker(Node *node, find_expr_references_context *context)
Definition: dependency.c:1754
static void process_function_rte_ref(RangeTblEntry *rte, AttrNumber attnum, find_expr_references_context *context)
Definition: dependency.c:2377
static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId, ObjectAddresses *addrs)
Definition: dependency.c:2561
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define ereport(elevel,...)
Definition: elog.h:149
List * list_delete_first(List *list)
Definition: list.c:943
List * lcons(void *datum, List *list)
Definition: list.c:495
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2686
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2476
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:156
#define QTW_EXAMINE_SORTGROUP
Definition: nodeFuncs.h:30
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
#define QTW_IGNORE_JOINALIASES
Definition: nodeFuncs.h:25
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
@ CMD_INSERT
Definition: nodes.h:257
@ CMD_UPDATE
Definition: nodes.h:256
@ RTE_JOIN
Definition: parsenodes.h:1008
@ RTE_FUNCTION
Definition: parsenodes.h:1009
@ RTE_RELATION
Definition: parsenodes.h:1006
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define lfirst_int(lc)
Definition: pg_list.h:173
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define lfirst_oid(lc)
Definition: pg_list.h:174
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
unsigned int Oid
Definition: postgres_ext.h:31
Oid aggfnoid
Definition: primnodes.h:430
Oid cycle_mark_collation
Definition: parsenodes.h:1612
Oid resulttype
Definition: primnodes.h:1143
Oid consttype
Definition: primnodes.h:298
AttrNumber fieldnum
Definition: primnodes.h:1064
Expr * arg
Definition: primnodes.h:1063
Oid funcid
Definition: primnodes.h:685
Definition: pg_list.h:54
Definition: nodes.h:129
Oid opno
Definition: primnodes.h:753
Oid paramtype
Definition: primnodes.h:364
List * rtable
Definition: parsenodes.h:167
CmdType commandType
Definition: parsenodes.h:120
List * targetList
Definition: parsenodes.h:181
List * joinaliasvars
Definition: parsenodes.h:1121
RTEKind rtekind
Definition: parsenodes.h:1025
Oid resulttype
Definition: primnodes.h:1120
AttrNumber resno
Definition: primnodes.h:1924
Definition: primnodes.h:234
AttrNumber varattno
Definition: primnodes.h:246
int varno
Definition: primnodes.h:241
Index varlevelsup
Definition: primnodes.h:266
Oid winfnoid
Definition: primnodes.h:553
ObjectAddresses * addrs
Definition: dependency.c:143
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:95

References add_object_address(), find_expr_references_context::addrs, Aggref::aggfnoid, FieldSelect::arg, CMD_INSERT, CMD_UPDATE, collid, CollateExpr::collOid, Query::commandType, OnConflictExpr::constraint, Const::consttype, CTECycleClause::cycle_mark_collation, CTECycleClause::cycle_mark_neop, CTECycleClause::cycle_mark_type, DatumGetObjectId(), elog(), SortGroupClause::eqop, ereport, errcode(), errmsg(), ERROR, expression_tree_walker, exprType(), FieldSelect::fieldnum, FuncExpr::funcid, get_typ_typrelid(), getBaseType(), i, InvalidAttrNumber, IsA, RangeTblEntry::joinaliasvars, RangeTblEntry::joinmergedcols, lcons(), lfirst, lfirst_int, lfirst_oid, list_delete_first(), list_length(), list_nth(), ObjectIdGetDatum(), OCLASS_CLASS, OCLASS_COLLATION, OCLASS_CONSTRAINT, OCLASS_OPERATOR, OCLASS_OPFAMILY, OCLASS_PROC, OCLASS_SCHEMA, OCLASS_TSCONFIG, OCLASS_TSDICT, OCLASS_TYPE, OidIsValid, OpExpr::opno, ScalarArrayOpExpr::opno, Param::paramtype, process_function_rte_ref(), QTW_EXAMINE_SORTGROUP, QTW_IGNORE_JOINALIASES, query_tree_walker, RangeTblEntry::relid, TargetEntry::resno, RelabelType::resulttype, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ConvertRowtypeExpr::resulttype, CoerceToDomain::resulttype, rt_fetch, Query::rtable, find_expr_references_context::rtables, RTE_FUNCTION, RTE_JOIN, RTE_RELATION, RangeTblEntry::rtekind, SearchSysCacheExists1, NextValueExpr::seqid, SortGroupClause::sortop, Query::targetList, TableSampleClause::tsmhandler, Var::varattno, Var::varlevelsup, Var::varno, and WindowFunc::winfnoid.

Referenced by recordDependencyOnExpr(), and recordDependencyOnSingleRelExpr().

◆ findDependentObjects()

static void findDependentObjects ( const ObjectAddress object,
int  objflags,
int  flags,
ObjectAddressStack stack,
ObjectAddresses targetObjects,
const ObjectAddresses pendingObjects,
Relation depRel 
)
static

Definition at line 488 of file dependency.c.

495 {
496  ScanKeyData key[3];
497  int nkeys;
498  SysScanDesc scan;
499  HeapTuple tup;
500  ObjectAddress otherObject;
501  ObjectAddress owningObject;
502  ObjectAddress partitionObject;
503  ObjectAddressAndFlags *dependentObjects;
504  int numDependentObjects;
505  int maxDependentObjects;
506  ObjectAddressStack mystack;
507  ObjectAddressExtra extra;
508 
509  /*
510  * If the target object is already being visited in an outer recursion
511  * level, just report the current objflags back to that level and exit.
512  * This is needed to avoid infinite recursion in the face of circular
513  * dependencies.
514  *
515  * The stack check alone would result in dependency loops being broken at
516  * an arbitrary point, ie, the first member object of the loop to be
517  * visited is the last one to be deleted. This is obviously unworkable.
518  * However, the check for internal dependency below guarantees that we
519  * will not break a loop at an internal dependency: if we enter the loop
520  * at an "owned" object we will switch and start at the "owning" object
521  * instead. We could probably hack something up to avoid breaking at an
522  * auto dependency, too, if we had to. However there are no known cases
523  * where that would be necessary.
524  */
525  if (stack_address_present_add_flags(object, objflags, stack))
526  return;
527 
528  /*
529  * since this function recurses, it could be driven to stack overflow,
530  * because of the deep dependency tree, not only due to dependency loops.
531  */
533 
534  /*
535  * It's also possible that the target object has already been completely
536  * processed and put into targetObjects. If so, again we just add the
537  * specified objflags to its entry and return.
538  *
539  * (Note: in these early-exit cases we could release the caller-taken
540  * lock, since the object is presumably now locked multiple times; but it
541  * seems not worth the cycles.)
542  */
543  if (object_address_present_add_flags(object, objflags, targetObjects))
544  return;
545 
546  /*
547  * If the target object is pinned, we can just error out immediately; it
548  * won't have any objects recorded as depending on it.
549  */
550  if (IsPinnedObject(object->classId, object->objectId))
551  ereport(ERROR,
552  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
553  errmsg("cannot drop %s because it is required by the database system",
554  getObjectDescription(object, false))));
555 
556  /*
557  * The target object might be internally dependent on some other object
558  * (its "owner"), and/or be a member of an extension (also considered its
559  * owner). If so, and if we aren't recursing from the owning object, we
560  * have to transform this deletion request into a deletion request of the
561  * owning object. (We'll eventually recurse back to this object, but the
562  * owning object has to be visited first so it will be deleted after.) The
563  * way to find out about this is to scan the pg_depend entries that show
564  * what this object depends on.
565  */
566  ScanKeyInit(&key[0],
567  Anum_pg_depend_classid,
568  BTEqualStrategyNumber, F_OIDEQ,
569  ObjectIdGetDatum(object->classId));
570  ScanKeyInit(&key[1],
571  Anum_pg_depend_objid,
572  BTEqualStrategyNumber, F_OIDEQ,
573  ObjectIdGetDatum(object->objectId));
574  if (object->objectSubId != 0)
575  {
576  /* Consider only dependencies of this sub-object */
577  ScanKeyInit(&key[2],
578  Anum_pg_depend_objsubid,
579  BTEqualStrategyNumber, F_INT4EQ,
580  Int32GetDatum(object->objectSubId));
581  nkeys = 3;
582  }
583  else
584  {
585  /* Consider dependencies of this object and any sub-objects it has */
586  nkeys = 2;
587  }
588 
589  scan = systable_beginscan(*depRel, DependDependerIndexId, true,
590  NULL, nkeys, key);
591 
592  /* initialize variables that loop may fill */
593  memset(&owningObject, 0, sizeof(owningObject));
594  memset(&partitionObject, 0, sizeof(partitionObject));
595 
596  while (HeapTupleIsValid(tup = systable_getnext(scan)))
597  {
598  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
599 
600  otherObject.classId = foundDep->refclassid;
601  otherObject.objectId = foundDep->refobjid;
602  otherObject.objectSubId = foundDep->refobjsubid;
603 
604  /*
605  * When scanning dependencies of a whole object, we may find rows
606  * linking sub-objects of the object to the object itself. (Normally,
607  * such a dependency is implicit, but we must make explicit ones in
608  * some cases involving partitioning.) We must ignore such rows to
609  * avoid infinite recursion.
610  */
611  if (otherObject.classId == object->classId &&
612  otherObject.objectId == object->objectId &&
613  object->objectSubId == 0)
614  continue;
615 
616  switch (foundDep->deptype)
617  {
618  case DEPENDENCY_NORMAL:
619  case DEPENDENCY_AUTO:
621  /* no problem */
622  break;
623 
625 
626  /*
627  * If told to, ignore EXTENSION dependencies altogether. This
628  * flag is normally used to prevent dropping extensions during
629  * temporary-object cleanup, even if a temp object was created
630  * during an extension script.
631  */
633  break;
634 
635  /*
636  * If the other object is the extension currently being
637  * created/altered, ignore this dependency and continue with
638  * the deletion. This allows dropping of an extension's
639  * objects within the extension's scripts, as well as corner
640  * cases such as dropping a transient object created within
641  * such a script.
642  */
643  if (creating_extension &&
644  otherObject.classId == ExtensionRelationId &&
645  otherObject.objectId == CurrentExtensionObject)
646  break;
647 
648  /* Otherwise, treat this like an internal dependency */
649  /* FALL THRU */
650 
651  case DEPENDENCY_INTERNAL:
652 
653  /*
654  * This object is part of the internal implementation of
655  * another object, or is part of the extension that is the
656  * other object. We have three cases:
657  *
658  * 1. At the outermost recursion level, we must disallow the
659  * DROP. However, if the owning object is listed in
660  * pendingObjects, just release the caller's lock and return;
661  * we'll eventually complete the DROP when we reach that entry
662  * in the pending list.
663  *
664  * Note: the above statement is true only if this pg_depend
665  * entry still exists by then; in principle, therefore, we
666  * could miss deleting an item the user told us to delete.
667  * However, no inconsistency can result: since we're at outer
668  * level, there is no object depending on this one.
669  */
670  if (stack == NULL)
671  {
672  if (pendingObjects &&
673  object_address_present(&otherObject, pendingObjects))
674  {
675  systable_endscan(scan);
676  /* need to release caller's lock; see notes below */
677  ReleaseDeletionLock(object);
678  return;
679  }
680 
681  /*
682  * We postpone actually issuing the error message until
683  * after this loop, so that we can make the behavior
684  * independent of the ordering of pg_depend entries, at
685  * least if there's not more than one INTERNAL and one
686  * EXTENSION dependency. (If there's more, we'll complain
687  * about a random one of them.) Prefer to complain about
688  * EXTENSION, since that's generally a more important
689  * dependency.
690  */
691  if (!OidIsValid(owningObject.classId) ||
692  foundDep->deptype == DEPENDENCY_EXTENSION)
693  owningObject = otherObject;
694  break;
695  }
696 
697  /*
698  * 2. When recursing from the other end of this dependency,
699  * it's okay to continue with the deletion. This holds when
700  * recursing from a whole object that includes the nominal
701  * other end as a component, too. Since there can be more
702  * than one "owning" object, we have to allow matches that are
703  * more than one level down in the stack.
704  */
705  if (stack_address_present_add_flags(&otherObject, 0, stack))
706  break;
707 
708  /*
709  * 3. Not all the owning objects have been visited, so
710  * transform this deletion request into a delete of this
711  * owning object.
712  *
713  * First, release caller's lock on this object and get
714  * deletion lock on the owning object. (We must release
715  * caller's lock to avoid deadlock against a concurrent
716  * deletion of the owning object.)
717  */
718  ReleaseDeletionLock(object);
719  AcquireDeletionLock(&otherObject, 0);
720 
721  /*
722  * The owning object might have been deleted while we waited
723  * to lock it; if so, neither it nor the current object are
724  * interesting anymore. We test this by checking the
725  * pg_depend entry (see notes below).
726  */
727  if (!systable_recheck_tuple(scan, tup))
728  {
729  systable_endscan(scan);
730  ReleaseDeletionLock(&otherObject);
731  return;
732  }
733 
734  /*
735  * One way or the other, we're done with the scan; might as
736  * well close it down before recursing, to reduce peak
737  * resource consumption.
738  */
739  systable_endscan(scan);
740 
741  /*
742  * Okay, recurse to the owning object instead of proceeding.
743  *
744  * We do not need to stack the current object; we want the
745  * traversal order to be as if the original reference had
746  * linked to the owning object instead of this one.
747  *
748  * The dependency type is a "reverse" dependency: we need to
749  * delete the owning object if this one is to be deleted, but
750  * this linkage is never a reason for an automatic deletion.
751  */
752  findDependentObjects(&otherObject,
754  flags,
755  stack,
756  targetObjects,
757  pendingObjects,
758  depRel);
759 
760  /*
761  * The current target object should have been added to
762  * targetObjects while processing the owning object; but it
763  * probably got only the flag bits associated with the
764  * dependency we're looking at. We need to add the objflags
765  * that were passed to this recursion level, too, else we may
766  * get a bogus failure in reportDependentObjects (if, for
767  * example, we were called due to a partition dependency).
768  *
769  * If somehow the current object didn't get scheduled for
770  * deletion, bleat. (That would imply that somebody deleted
771  * this dependency record before the recursion got to it.)
772  * Another idea would be to reacquire lock on the current
773  * object and resume trying to delete it, but it seems not
774  * worth dealing with the race conditions inherent in that.
775  */
776  if (!object_address_present_add_flags(object, objflags,
777  targetObjects))
778  elog(ERROR, "deletion of owning object %s failed to delete %s",
779  getObjectDescription(&otherObject, false),
780  getObjectDescription(object, false));
781 
782  /* And we're done here. */
783  return;
784 
786 
787  /*
788  * Remember that this object has a partition-type dependency.
789  * After the dependency scan, we'll complain if we didn't find
790  * a reason to delete one of its partition dependencies.
791  */
792  objflags |= DEPFLAG_IS_PART;
793 
794  /*
795  * Also remember the primary partition owner, for error
796  * messages. If there are multiple primary owners (which
797  * there should not be), we'll report a random one of them.
798  */
799  partitionObject = otherObject;
800  break;
801 
803 
804  /*
805  * Only use secondary partition owners in error messages if we
806  * find no primary owner (which probably shouldn't happen).
807  */
808  if (!(objflags & DEPFLAG_IS_PART))
809  partitionObject = otherObject;
810 
811  /*
812  * Remember that this object has a partition-type dependency.
813  * After the dependency scan, we'll complain if we didn't find
814  * a reason to delete one of its partition dependencies.
815  */
816  objflags |= DEPFLAG_IS_PART;
817  break;
818 
819  default:
820  elog(ERROR, "unrecognized dependency type '%c' for %s",
821  foundDep->deptype, getObjectDescription(object, false));
822  break;
823  }
824  }
825 
826  systable_endscan(scan);
827 
828  /*
829  * If we found an INTERNAL or EXTENSION dependency when we're at outer
830  * level, complain about it now. If we also found a PARTITION dependency,
831  * we prefer to report the PARTITION dependency. This is arbitrary but
832  * seems to be more useful in practice.
833  */
834  if (OidIsValid(owningObject.classId))
835  {
836  char *otherObjDesc;
837 
838  if (OidIsValid(partitionObject.classId))
839  otherObjDesc = getObjectDescription(&partitionObject, false);
840  else
841  otherObjDesc = getObjectDescription(&owningObject, false);
842 
843  ereport(ERROR,
844  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
845  errmsg("cannot drop %s because %s requires it",
846  getObjectDescription(object, false), otherObjDesc),
847  errhint("You can drop %s instead.", otherObjDesc)));
848  }
849 
850  /*
851  * Next, identify all objects that directly depend on the current object.
852  * To ensure predictable deletion order, we collect them up in
853  * dependentObjects and sort the list before actually recursing. (The
854  * deletion order would be valid in any case, but doing this ensures
855  * consistent output from DROP CASCADE commands, which is helpful for
856  * regression testing.)
857  */
858  maxDependentObjects = 128; /* arbitrary initial allocation */
859  dependentObjects = (ObjectAddressAndFlags *)
860  palloc(maxDependentObjects * sizeof(ObjectAddressAndFlags));
861  numDependentObjects = 0;
862 
863  ScanKeyInit(&key[0],
864  Anum_pg_depend_refclassid,
865  BTEqualStrategyNumber, F_OIDEQ,
866  ObjectIdGetDatum(object->classId));
867  ScanKeyInit(&key[1],
868  Anum_pg_depend_refobjid,
869  BTEqualStrategyNumber, F_OIDEQ,
870  ObjectIdGetDatum(object->objectId));
871  if (object->objectSubId != 0)
872  {
873  ScanKeyInit(&key[2],
874  Anum_pg_depend_refobjsubid,
875  BTEqualStrategyNumber, F_INT4EQ,
876  Int32GetDatum(object->objectSubId));
877  nkeys = 3;
878  }
879  else
880  nkeys = 2;
881 
882  scan = systable_beginscan(*depRel, DependReferenceIndexId, true,
883  NULL, nkeys, key);
884 
885  while (HeapTupleIsValid(tup = systable_getnext(scan)))
886  {
887  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
888  int subflags;
889 
890  otherObject.classId = foundDep->classid;
891  otherObject.objectId = foundDep->objid;
892  otherObject.objectSubId = foundDep->objsubid;
893 
894  /*
895  * If what we found is a sub-object of the current object, just ignore
896  * it. (Normally, such a dependency is implicit, but we must make
897  * explicit ones in some cases involving partitioning.)
898  */
899  if (otherObject.classId == object->classId &&
900  otherObject.objectId == object->objectId &&
901  object->objectSubId == 0)
902  continue;
903 
904  /*
905  * Must lock the dependent object before recursing to it.
906  */
907  AcquireDeletionLock(&otherObject, 0);
908 
909  /*
910  * The dependent object might have been deleted while we waited to
911  * lock it; if so, we don't need to do anything more with it. We can
912  * test this cheaply and independently of the object's type by seeing
913  * if the pg_depend tuple we are looking at is still live. (If the
914  * object got deleted, the tuple would have been deleted too.)
915  */
916  if (!systable_recheck_tuple(scan, tup))
917  {
918  /* release the now-useless lock */
919  ReleaseDeletionLock(&otherObject);
920  /* and continue scanning for dependencies */
921  continue;
922  }
923 
924  /*
925  * We do need to delete it, so identify objflags to be passed down,
926  * which depend on the dependency type.
927  */
928  switch (foundDep->deptype)
929  {
930  case DEPENDENCY_NORMAL:
931  subflags = DEPFLAG_NORMAL;
932  break;
933  case DEPENDENCY_AUTO:
935  subflags = DEPFLAG_AUTO;
936  break;
937  case DEPENDENCY_INTERNAL:
938  subflags = DEPFLAG_INTERNAL;
939  break;
942  subflags = DEPFLAG_PARTITION;
943  break;
945  subflags = DEPFLAG_EXTENSION;
946  break;
947  default:
948  elog(ERROR, "unrecognized dependency type '%c' for %s",
949  foundDep->deptype, getObjectDescription(object, false));
950  subflags = 0; /* keep compiler quiet */
951  break;
952  }
953 
954  /* And add it to the pending-objects list */
955  if (numDependentObjects >= maxDependentObjects)
956  {
957  /* enlarge array if needed */
958  maxDependentObjects *= 2;
959  dependentObjects = (ObjectAddressAndFlags *)
960  repalloc(dependentObjects,
961  maxDependentObjects * sizeof(ObjectAddressAndFlags));
962  }
963 
964  dependentObjects[numDependentObjects].obj = otherObject;
965  dependentObjects[numDependentObjects].subflags = subflags;
966  numDependentObjects++;
967  }
968 
969  systable_endscan(scan);
970 
971  /*
972  * Now we can sort the dependent objects into a stable visitation order.
973  * It's safe to use object_address_comparator here since the obj field is
974  * first within ObjectAddressAndFlags.
975  */
976  if (numDependentObjects > 1)
977  qsort(dependentObjects, numDependentObjects,
978  sizeof(ObjectAddressAndFlags),
980 
981  /*
982  * Now recurse to the dependent objects. We must visit them first since
983  * they have to be deleted before the current object.
984  */
985  mystack.object = object; /* set up a new stack level */
986  mystack.flags = objflags;
987  mystack.next = stack;
988 
989  for (int i = 0; i < numDependentObjects; i++)
990  {
991  ObjectAddressAndFlags *depObj = dependentObjects + i;
992 
993  findDependentObjects(&depObj->obj,
994  depObj->subflags,
995  flags,
996  &mystack,
997  targetObjects,
998  pendingObjects,
999  depRel);
1000  }
1001 
1002  pfree(dependentObjects);
1003 
1004  /*
1005  * Finally, we can add the target object to targetObjects. Be careful to
1006  * include any flags that were passed back down to us from inner recursion
1007  * levels. Record the "dependee" as being either the most important
1008  * partition owner if there is one, else the object we recursed from, if
1009  * any. (The logic in reportDependentObjects() is such that it can only
1010  * need one of those objects.)
1011  */
1012  extra.flags = mystack.flags;
1013  if (extra.flags & DEPFLAG_IS_PART)
1014  extra.dependee = partitionObject;
1015  else if (stack)
1016  extra.dependee = *stack->object;
1017  else
1018  memset(&extra.dependee, 0, sizeof(extra.dependee));
1019  add_exact_object_address_extra(object, &extra, targetObjects);
1020 }
bool IsPinnedObject(Oid classId, Oid objectId)
Definition: catalog.c:315
static bool object_address_present_add_flags(const ObjectAddress *object, int flags, ObjectAddresses *addrs)
Definition: dependency.c:2674
#define DEPFLAG_PARTITION
Definition: dependency.c:107
static void add_exact_object_address_extra(const ObjectAddress *object, const ObjectAddressExtra *extra, ObjectAddresses *addrs)
Definition: dependency.c:2613
static bool stack_address_present_add_flags(const ObjectAddress *object, int flags, ObjectAddressStack *stack)
Definition: dependency.c:2747
#define DEPFLAG_IS_PART
Definition: dependency.c:110
void AcquireDeletionLock(const ObjectAddress *object, int flags)
Definition: dependency.c:1552
void ReleaseDeletionLock(const ObjectAddress *object)
Definition: dependency.c:1584
#define DEPFLAG_AUTO
Definition: dependency.c:105
static void findDependentObjects(const ObjectAddress *object, int objflags, int flags, ObjectAddressStack *stack, ObjectAddresses *targetObjects, const ObjectAddresses *pendingObjects, Relation *depRel)
Definition: dependency.c:488
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2648
#define DEPFLAG_EXTENSION
Definition: dependency.c:108
#define DEPFLAG_INTERNAL
Definition: dependency.c:106
#define PERFORM_DELETION_SKIP_EXTENSIONS
Definition: dependency.h:140
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_AUTO_EXTENSION
Definition: dependency.h:39
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
@ DEPENDENCY_EXTENSION
Definition: dependency.h:38
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errhint(const char *fmt,...)
Definition: elog.c:1322
bool creating_extension
Definition: extension.c:73
Oid CurrentExtensionObject
Definition: extension.c:74
bool systable_recheck_tuple(SysScanDesc sysscan, HeapTuple tup)
Definition: genam.c:565
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void pfree(void *pointer)
Definition: mcxt.c:1431
char * getObjectDescription(const ObjectAddress *object, bool missing_ok)
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
void check_stack_depth(void)
Definition: postgres.c:3523
ObjectAddress obj
Definition: dependency.c:136
ObjectAddress dependee
Definition: dependency.c:99
const ObjectAddress * object
Definition: dependency.c:128
struct ObjectAddressStack * next
Definition: dependency.c:130

References AcquireDeletionLock(), add_exact_object_address_extra(), BTEqualStrategyNumber, check_stack_depth(), ObjectAddress::classId, creating_extension, CurrentExtensionObject, ObjectAddressExtra::dependee, DEPENDENCY_AUTO, DEPENDENCY_AUTO_EXTENSION, DEPENDENCY_EXTENSION, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, DEPFLAG_AUTO, DEPFLAG_EXTENSION, DEPFLAG_INTERNAL, DEPFLAG_IS_PART, DEPFLAG_NORMAL, DEPFLAG_PARTITION, DEPFLAG_REVERSE, elog(), ereport, errcode(), errhint(), errmsg(), ERROR, ObjectAddressExtra::flags, ObjectAddressStack::flags, getObjectDescription(), GETSTRUCT, HeapTupleIsValid, i, Int32GetDatum(), IsPinnedObject(), sort-test::key, ObjectAddressStack::next, ObjectAddressAndFlags::obj, ObjectAddressStack::object, object_address_comparator(), object_address_present(), object_address_present_add_flags(), ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, palloc(), PERFORM_DELETION_SKIP_EXTENSIONS, pfree(), qsort, ReleaseDeletionLock(), repalloc(), ScanKeyInit(), stack_address_present_add_flags(), ObjectAddressAndFlags::subflags, systable_beginscan(), systable_endscan(), systable_getnext(), and systable_recheck_tuple().

Referenced by performDeletion(), and performMultipleDeletions().

◆ free_object_addresses()

◆ getObjectClass()

ObjectClass getObjectClass ( const ObjectAddress object)

Definition at line 2843 of file dependency.c.

2844 {
2845  /* only pg_class entries can have nonzero objectSubId */
2846  if (object->classId != RelationRelationId &&
2847  object->objectSubId != 0)
2848  elog(ERROR, "invalid non-zero objectSubId for object class %u",
2849  object->classId);
2850 
2851  switch (object->classId)
2852  {
2853  case RelationRelationId:
2854  /* caller must check objectSubId */
2855  return OCLASS_CLASS;
2856 
2857  case ProcedureRelationId:
2858  return OCLASS_PROC;
2859 
2860  case TypeRelationId:
2861  return OCLASS_TYPE;
2862 
2863  case CastRelationId:
2864  return OCLASS_CAST;
2865 
2866  case CollationRelationId:
2867  return OCLASS_COLLATION;
2868 
2869  case ConstraintRelationId:
2870  return OCLASS_CONSTRAINT;
2871 
2872  case ConversionRelationId:
2873  return OCLASS_CONVERSION;
2874 
2875  case AttrDefaultRelationId:
2876  return OCLASS_DEFAULT;
2877 
2878  case LanguageRelationId:
2879  return OCLASS_LANGUAGE;
2880 
2881  case LargeObjectRelationId:
2882  return OCLASS_LARGEOBJECT;
2883 
2884  case OperatorRelationId:
2885  return OCLASS_OPERATOR;
2886 
2887  case OperatorClassRelationId:
2888  return OCLASS_OPCLASS;
2889 
2890  case OperatorFamilyRelationId:
2891  return OCLASS_OPFAMILY;
2892 
2893  case AccessMethodRelationId:
2894  return OCLASS_AM;
2895 
2896  case AccessMethodOperatorRelationId:
2897  return OCLASS_AMOP;
2898 
2899  case AccessMethodProcedureRelationId:
2900  return OCLASS_AMPROC;
2901 
2902  case RewriteRelationId:
2903  return OCLASS_REWRITE;
2904 
2905  case TriggerRelationId:
2906  return OCLASS_TRIGGER;
2907 
2908  case NamespaceRelationId:
2909  return OCLASS_SCHEMA;
2910 
2911  case StatisticExtRelationId:
2912  return OCLASS_STATISTIC_EXT;
2913 
2914  case TSParserRelationId:
2915  return OCLASS_TSPARSER;
2916 
2917  case TSDictionaryRelationId:
2918  return OCLASS_TSDICT;
2919 
2920  case TSTemplateRelationId:
2921  return OCLASS_TSTEMPLATE;
2922 
2923  case TSConfigRelationId:
2924  return OCLASS_TSCONFIG;
2925 
2926  case AuthIdRelationId:
2927  return OCLASS_ROLE;
2928 
2929  case AuthMemRelationId:
2930  return OCLASS_ROLE_MEMBERSHIP;
2931 
2932  case DatabaseRelationId:
2933  return OCLASS_DATABASE;
2934 
2935  case TableSpaceRelationId:
2936  return OCLASS_TBLSPACE;
2937 
2938  case ForeignDataWrapperRelationId:
2939  return OCLASS_FDW;
2940 
2941  case ForeignServerRelationId:
2942  return OCLASS_FOREIGN_SERVER;
2943 
2944  case UserMappingRelationId:
2945  return OCLASS_USER_MAPPING;
2946 
2947  case DefaultAclRelationId:
2948  return OCLASS_DEFACL;
2949 
2950  case ExtensionRelationId:
2951  return OCLASS_EXTENSION;
2952 
2953  case EventTriggerRelationId:
2954  return OCLASS_EVENT_TRIGGER;
2955 
2956  case ParameterAclRelationId:
2957  return OCLASS_PARAMETER_ACL;
2958 
2959  case PolicyRelationId:
2960  return OCLASS_POLICY;
2961 
2962  case PublicationNamespaceRelationId:
2964 
2965  case PublicationRelationId:
2966  return OCLASS_PUBLICATION;
2967 
2968  case PublicationRelRelationId:
2969  return OCLASS_PUBLICATION_REL;
2970 
2971  case SubscriptionRelationId:
2972  return OCLASS_SUBSCRIPTION;
2973 
2974  case TransformRelationId:
2975  return OCLASS_TRANSFORM;
2976  }
2977 
2978  /* shouldn't get here */
2979  elog(ERROR, "unrecognized object class: %u", object->classId);
2980  return OCLASS_CLASS; /* keep compiler quiet */
2981 }

References ObjectAddress::classId, elog(), ERROR, ObjectAddressStack::object, ObjectAddress::objectSubId, OCLASS_AM, OCLASS_AMOP, OCLASS_AMPROC, OCLASS_CAST, OCLASS_CLASS, OCLASS_COLLATION, OCLASS_CONSTRAINT, OCLASS_CONVERSION, OCLASS_DATABASE, OCLASS_DEFACL, OCLASS_DEFAULT, OCLASS_EVENT_TRIGGER, OCLASS_EXTENSION, OCLASS_FDW, OCLASS_FOREIGN_SERVER, OCLASS_LANGUAGE, OCLASS_LARGEOBJECT, OCLASS_OPCLASS, OCLASS_OPERATOR, OCLASS_OPFAMILY, OCLASS_PARAMETER_ACL, OCLASS_POLICY, OCLASS_PROC, OCLASS_PUBLICATION, OCLASS_PUBLICATION_NAMESPACE, OCLASS_PUBLICATION_REL, OCLASS_REWRITE, OCLASS_ROLE, OCLASS_ROLE_MEMBERSHIP, OCLASS_SCHEMA, OCLASS_STATISTIC_EXT, OCLASS_SUBSCRIPTION, OCLASS_TBLSPACE, OCLASS_TRANSFORM, OCLASS_TRIGGER, OCLASS_TSCONFIG, OCLASS_TSDICT, OCLASS_TSPARSER, OCLASS_TSTEMPLATE, OCLASS_TYPE, and OCLASS_USER_MAPPING.

Referenced by AlterObjectNamespace_oid(), deleteObjectsInList(), doDeletion(), EventTriggerSQLDropAddObject(), getObjectDescription(), getObjectIdentityParts(), getObjectTypeDescription(), and RememberAllDependentForRebuilding().

◆ new_object_addresses()

◆ object_address_comparator()

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

Definition at line 2495 of file dependency.c.

2496 {
2497  const ObjectAddress *obja = (const ObjectAddress *) a;
2498  const ObjectAddress *objb = (const ObjectAddress *) b;
2499 
2500  /*
2501  * Primary sort key is OID descending. Most of the time, this will result
2502  * in putting newer objects before older ones, which is likely to be the
2503  * right order to delete in.
2504  */
2505  if (obja->objectId > objb->objectId)
2506  return -1;
2507  if (obja->objectId < objb->objectId)
2508  return 1;
2509 
2510  /*
2511  * Next sort on catalog ID, in case identical OIDs appear in different
2512  * catalogs. Sort direction is pretty arbitrary here.
2513  */
2514  if (obja->classId < objb->classId)
2515  return -1;
2516  if (obja->classId > objb->classId)
2517  return 1;
2518 
2519  /*
2520  * Last, sort on object subId.
2521  *
2522  * We sort the subId as an unsigned int so that 0 (the whole object) will
2523  * come first. This is essential for eliminate_duplicate_dependencies,
2524  * and is also the best order for findDependentObjects.
2525  */
2526  if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId)
2527  return -1;
2528  if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId)
2529  return 1;
2530  return 0;
2531 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, b, ObjectAddress::classId, ObjectAddress::objectId, and ObjectAddress::objectSubId.

Referenced by eliminate_duplicate_dependencies(), findDependentObjects(), and sort_object_addresses().

◆ object_address_present()

bool object_address_present ( const ObjectAddress object,
const ObjectAddresses addrs 
)

Definition at line 2648 of file dependency.c.

2650 {
2651  int i;
2652 
2653  for (i = addrs->numrefs - 1; i >= 0; i--)
2654  {
2655  const ObjectAddress *thisobj = addrs->refs + i;
2656 
2657  if (object->classId == thisobj->classId &&
2658  object->objectId == thisobj->objectId)
2659  {
2660  if (object->objectSubId == thisobj->objectSubId ||
2661  thisobj->objectSubId == 0)
2662  return true;
2663  }
2664  }
2665 
2666  return false;
2667 }

References ObjectAddress::classId, i, ObjectAddresses::numrefs, ObjectAddressStack::object, ObjectAddress::objectId, ObjectAddress::objectSubId, and ObjectAddresses::refs.

Referenced by AlterConstraintNamespaces(), AlterIndexNamespaces(), AlterRelationNamespaceInternal(), AlterTypeNamespaceInternal(), findDependentObjects(), and PreCommit_on_commit_actions().

◆ object_address_present_add_flags()

static bool object_address_present_add_flags ( const ObjectAddress object,
int  flags,
ObjectAddresses addrs 
)
static

Definition at line 2674 of file dependency.c.

2677 {
2678  bool result = false;
2679  int i;
2680 
2681  for (i = addrs->numrefs - 1; i >= 0; i--)
2682  {
2683  ObjectAddress *thisobj = addrs->refs + i;
2684 
2685  if (object->classId == thisobj->classId &&
2686  object->objectId == thisobj->objectId)
2687  {
2688  if (object->objectSubId == thisobj->objectSubId)
2689  {
2690  ObjectAddressExtra *thisextra = addrs->extras + i;
2691 
2692  thisextra->flags |= flags;
2693  result = true;
2694  }
2695  else if (thisobj->objectSubId == 0)
2696  {
2697  /*
2698  * We get here if we find a need to delete a column after
2699  * having already decided to drop its whole table. Obviously
2700  * we no longer need to drop the subobject, so report that we
2701  * found the subobject in the array. But don't plaster its
2702  * flags on the whole object.
2703  */
2704  result = true;
2705  }
2706  else if (object->objectSubId == 0)
2707  {
2708  /*
2709  * We get here if we find a need to delete a whole table after
2710  * having already decided to drop one of its columns. We
2711  * can't report that the whole object is in the array, but we
2712  * should mark the subobject with the whole object's flags.
2713  *
2714  * It might seem attractive to physically delete the column's
2715  * array entry, or at least mark it as no longer needing
2716  * separate deletion. But that could lead to, e.g., dropping
2717  * the column's datatype before we drop the table, which does
2718  * not seem like a good idea. This is a very rare situation
2719  * in practice, so we just take the hit of doing a separate
2720  * DROP COLUMN action even though we know we're gonna delete
2721  * the table later.
2722  *
2723  * What we can do, though, is mark this as a subobject so that
2724  * we don't report it separately, which is confusing because
2725  * it's unpredictable whether it happens or not. But do so
2726  * only if flags != 0 (flags == 0 is a read-only probe).
2727  *
2728  * Because there could be other subobjects of this object in
2729  * the array, this case means we always have to loop through
2730  * the whole array; we cannot exit early on a match.
2731  */
2732  ObjectAddressExtra *thisextra = addrs->extras + i;
2733 
2734  if (flags)
2735  thisextra->flags |= (flags | DEPFLAG_SUBOBJECT);
2736  }
2737  }
2738  }
2739 
2740  return result;
2741 }
#define DEPFLAG_SUBOBJECT
Definition: dependency.c:111

References ObjectAddress::classId, DEPFLAG_SUBOBJECT, ObjectAddresses::extras, ObjectAddressExtra::flags, ObjectAddressStack::flags, i, ObjectAddresses::numrefs, ObjectAddressStack::object, ObjectAddress::objectId, ObjectAddress::objectSubId, and ObjectAddresses::refs.

Referenced by findDependentObjects().

◆ performDeletion()

void performDeletion ( const ObjectAddress object,
DropBehavior  behavior,
int  flags 
)

Definition at line 329 of file dependency.c.

331 {
332  Relation depRel;
333  ObjectAddresses *targetObjects;
334 
335  /*
336  * We save some cycles by opening pg_depend just once and passing the
337  * Relation pointer down to all the recursive deletion steps.
338  */
339  depRel = table_open(DependRelationId, RowExclusiveLock);
340 
341  /*
342  * Acquire deletion lock on the target object. (Ideally the caller has
343  * done this already, but many places are sloppy about it.)
344  */
345  AcquireDeletionLock(object, 0);
346 
347  /*
348  * Construct a list of objects to delete (ie, the given object plus
349  * everything directly or indirectly dependent on it).
350  */
351  targetObjects = new_object_addresses();
352 
353  findDependentObjects(object,
355  flags,
356  NULL, /* empty stack */
357  targetObjects,
358  NULL, /* no pendingObjects */
359  &depRel);
360 
361  /*
362  * Check if deletion is allowed, and report about cascaded deletes.
363  */
364  reportDependentObjects(targetObjects,
365  behavior,
366  flags,
367  object);
368 
369  /* do the deed */
370  deleteObjectsInList(targetObjects, &depRel, flags);
371 
372  /* And clean up */
373  free_object_addresses(targetObjects);
374 
375  table_close(depRel, RowExclusiveLock);
376 }
static void reportDependentObjects(const ObjectAddresses *targetObjects, DropBehavior behavior, int flags, const ObjectAddress *origObject)
Definition: dependency.c:1036
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2539
static void deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel, int flags)
Definition: dependency.c:241
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2828

References AcquireDeletionLock(), deleteObjectsInList(), DEPFLAG_ORIGINAL, findDependentObjects(), ObjectAddressStack::flags, free_object_addresses(), new_object_addresses(), reportDependentObjects(), RowExclusiveLock, table_close(), and table_open().

Referenced by AlterDomainDropConstraint(), ATExecDropIdentity(), DetachPartitionFinalize(), do_autovacuum(), dropconstraint_internal(), dropOperators(), dropProcedures(), finish_heap_swap(), inv_drop(), PublicationDropSchemas(), PublicationDropTables(), RemoveAttrDefault(), RemoveTempRelations(), RemoveUserMapping(), SetDefaultACL(), and tryAttachPartitionForeignKey().

◆ performMultipleDeletions()

void performMultipleDeletions ( const ObjectAddresses objects,
DropBehavior  behavior,
int  flags 
)

Definition at line 388 of file dependency.c.

390 {
391  Relation depRel;
392  ObjectAddresses *targetObjects;
393  int i;
394 
395  /* No work if no objects... */
396  if (objects->numrefs <= 0)
397  return;
398 
399  /*
400  * We save some cycles by opening pg_depend just once and passing the
401  * Relation pointer down to all the recursive deletion steps.
402  */
403  depRel = table_open(DependRelationId, RowExclusiveLock);
404 
405  /*
406  * Construct a list of objects to delete (ie, the given objects plus
407  * everything directly or indirectly dependent on them). Note that
408  * because we pass the whole objects list as pendingObjects context, we
409  * won't get a failure from trying to delete an object that is internally
410  * dependent on another one in the list; we'll just skip that object and
411  * delete it when we reach its owner.
412  */
413  targetObjects = new_object_addresses();
414 
415  for (i = 0; i < objects->numrefs; i++)
416  {
417  const ObjectAddress *thisobj = objects->refs + i;
418 
419  /*
420  * Acquire deletion lock on each target object. (Ideally the caller
421  * has done this already, but many places are sloppy about it.)
422  */
423  AcquireDeletionLock(thisobj, flags);
424 
425  findDependentObjects(thisobj,
427  flags,
428  NULL, /* empty stack */
429  targetObjects,
430  objects,
431  &depRel);
432  }
433 
434  /*
435  * Check if deletion is allowed, and report about cascaded deletes.
436  *
437  * If there's exactly one object being deleted, report it the same way as
438  * in performDeletion(), else we have to be vaguer.
439  */
440  reportDependentObjects(targetObjects,
441  behavior,
442  flags,
443  (objects->numrefs == 1 ? objects->refs : NULL));
444 
445  /* do the deed */
446  deleteObjectsInList(targetObjects, &depRel, flags);
447 
448  /* And clean up */
449  free_object_addresses(targetObjects);
450 
451  table_close(depRel, RowExclusiveLock);
452 }

References AcquireDeletionLock(), deleteObjectsInList(), DEPFLAG_ORIGINAL, findDependentObjects(), ObjectAddressStack::flags, free_object_addresses(), i, new_object_addresses(), ObjectAddresses::numrefs, ObjectAddresses::refs, reportDependentObjects(), RowExclusiveLock, table_close(), and table_open().

Referenced by ATExecDropColumn(), DropClonedTriggersFromPartition(), PreCommit_on_commit_actions(), ReindexRelationConcurrently(), RemoveObjects(), RemoveRelations(), and shdepDropOwned().

◆ process_function_rte_ref()

static void process_function_rte_ref ( RangeTblEntry rte,
AttrNumber  attnum,
find_expr_references_context context 
)
static

Definition at line 2377 of file dependency.c.

2379 {
2380  int atts_done = 0;
2381  ListCell *lc;
2382 
2383  /*
2384  * Identify which RangeTblFunction produces this attnum, and see if it
2385  * returns a composite type. If so, we'd better make a dependency on the
2386  * referenced column of the composite type (or actually, of its associated
2387  * relation).
2388  */
2389  foreach(lc, rte->functions)
2390  {
2391  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
2392 
2393  if (attnum > atts_done &&
2394  attnum <= atts_done + rtfunc->funccolcount)
2395  {
2396  TupleDesc tupdesc;
2397 
2398  tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr, true);
2399  if (tupdesc && tupdesc->tdtypeid != RECORDOID)
2400  {
2401  /*
2402  * Named composite type, so individual columns could get
2403  * dropped. Make a dependency on this specific column.
2404  */
2405  Oid reltype = get_typ_typrelid(tupdesc->tdtypeid);
2406 
2407  Assert(attnum - atts_done <= tupdesc->natts);
2408  if (OidIsValid(reltype)) /* can this fail? */
2410  attnum - atts_done,
2411  context->addrs);
2412  return;
2413  }
2414  /* Nothing to do; function's result type is handled elsewhere */
2415  return;
2416  }
2417  atts_done += rtfunc->funccolcount;
2418  }
2419 
2420  /* If we get here, must be looking for the ordinality column */
2421  if (rte->funcordinality && attnum == atts_done + 1)
2422  return;
2423 
2424  /* this probably can't happen ... */
2425  ereport(ERROR,
2426  (errcode(ERRCODE_UNDEFINED_COLUMN),
2427  errmsg("column %d of relation \"%s\" does not exist",
2428  attnum, rte->eref->aliasname)));
2429 }
TupleDesc get_expr_result_tupdesc(Node *expr, bool noError)
Definition: funcapi.c:543
int16 attnum
Definition: pg_attribute.h:74
char * aliasname
Definition: primnodes.h:50
bool funcordinality
Definition: parsenodes.h:1141
Alias * eref
Definition: parsenodes.h:1192
List * functions
Definition: parsenodes.h:1140
Oid tdtypeid
Definition: tupdesc.h:82

References add_object_address(), find_expr_references_context::addrs, Alias::aliasname, Assert(), attnum, RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, RangeTblFunction::funcexpr, RangeTblEntry::funcordinality, RangeTblEntry::functions, get_expr_result_tupdesc(), get_typ_typrelid(), lfirst, OCLASS_CLASS, OidIsValid, and TupleDescData::tdtypeid.

Referenced by find_expr_references_walker().

◆ record_object_address_dependencies()

void record_object_address_dependencies ( const ObjectAddress depender,
ObjectAddresses referenced,
DependencyType  behavior 
)

Definition at line 2797 of file dependency.c.

2800 {
2802  recordMultipleDependencies(depender,
2803  referenced->refs, referenced->numrefs,
2804  behavior);
2805 }
static void eliminate_duplicate_dependencies(ObjectAddresses *addrs)
Definition: dependency.c:2435
void recordMultipleDependencies(const ObjectAddress *depender, const ObjectAddress *referenced, int nreferenced, DependencyType behavior)
Definition: pg_depend.c:56

References eliminate_duplicate_dependencies(), ObjectAddresses::numrefs, recordMultipleDependencies(), and ObjectAddresses::refs.

Referenced by AggregateCreate(), CastCreate(), CreateConstraintEntry(), CreateProceduralLanguage(), CreateTransform(), GenerateTypeDependencies(), heap_create_with_catalog(), index_create(), InsertExtensionTuple(), makeConfigurationDependencies(), makeDictionaryDependencies(), makeOperatorDependencies(), makeParserDependencies(), makeTSTemplateDependencies(), ProcedureCreate(), RangeCreate(), and StorePartitionKey().

◆ recordDependencyOnExpr()

void recordDependencyOnExpr ( const ObjectAddress depender,
Node expr,
List rtable,
DependencyType  behavior 
)

Definition at line 1609 of file dependency.c.

1612 {
1614 
1615  context.addrs = new_object_addresses();
1616 
1617  /* Set up interpretation for Vars at varlevelsup = 0 */
1618  context.rtables = list_make1(rtable);
1619 
1620  /* Scan the expression tree for referenceable objects */
1621  find_expr_references_walker(expr, &context);
1622 
1623  /* Remove any duplicates */
1625 
1626  /* And record 'em */
1627  recordMultipleDependencies(depender,
1628  context.addrs->refs, context.addrs->numrefs,
1629  behavior);
1630 
1631  free_object_addresses(context.addrs);
1632 }
#define list_make1(x1)
Definition: pg_list.h:212

References find_expr_references_context::addrs, eliminate_duplicate_dependencies(), find_expr_references_walker(), free_object_addresses(), list_make1, new_object_addresses(), ObjectAddresses::numrefs, recordMultipleDependencies(), ObjectAddresses::refs, and find_expr_references_context::rtables.

Referenced by AlterPolicy(), CreatePolicy(), CreateTriggerFiringOn(), GenerateTypeDependencies(), InsertRule(), and ProcedureCreate().

◆ recordDependencyOnSingleRelExpr()

void recordDependencyOnSingleRelExpr ( const ObjectAddress depender,
Node expr,
Oid  relId,
DependencyType  behavior,
DependencyType  self_behavior,
bool  reverse_self 
)

Definition at line 1652 of file dependency.c.

1657 {
1659  RangeTblEntry rte = {0};
1660 
1661  context.addrs = new_object_addresses();
1662 
1663  /* We gin up a rather bogus rangetable list to handle Vars */
1664  rte.type = T_RangeTblEntry;
1665  rte.rtekind = RTE_RELATION;
1666  rte.relid = relId;
1667  rte.relkind = RELKIND_RELATION; /* no need for exactness here */
1669 
1670  context.rtables = list_make1(list_make1(&rte));
1671 
1672  /* Scan the expression tree for referenceable objects */
1673  find_expr_references_walker(expr, &context);
1674 
1675  /* Remove any duplicates */
1677 
1678  /* Separate self-dependencies if necessary */
1679  if ((behavior != self_behavior || reverse_self) &&
1680  context.addrs->numrefs > 0)
1681  {
1682  ObjectAddresses *self_addrs;
1683  ObjectAddress *outobj;
1684  int oldref,
1685  outrefs;
1686 
1687  self_addrs = new_object_addresses();
1688 
1689  outobj = context.addrs->refs;
1690  outrefs = 0;
1691  for (oldref = 0; oldref < context.addrs->numrefs; oldref++)
1692  {
1693  ObjectAddress *thisobj = context.addrs->refs + oldref;
1694 
1695  if (thisobj->classId == RelationRelationId &&
1696  thisobj->objectId == relId)
1697  {
1698  /* Move this ref into self_addrs */
1699  add_exact_object_address(thisobj, self_addrs);
1700  }
1701  else
1702  {
1703  /* Keep it in context.addrs */
1704  *outobj = *thisobj;
1705  outobj++;
1706  outrefs++;
1707  }
1708  }
1709  context.addrs->numrefs = outrefs;
1710 
1711  /* Record the self-dependencies with the appropriate direction */
1712  if (!reverse_self)
1713  recordMultipleDependencies(depender,
1714  self_addrs->refs, self_addrs->numrefs,
1715  self_behavior);
1716  else
1717  {
1718  /* Can't use recordMultipleDependencies, so do it the hard way */
1719  int selfref;
1720 
1721  for (selfref = 0; selfref < self_addrs->numrefs; selfref++)
1722  {
1723  ObjectAddress *thisobj = self_addrs->refs + selfref;
1724 
1725  recordDependencyOn(thisobj, depender, self_behavior);
1726  }
1727  }
1728 
1729  free_object_addresses(self_addrs);
1730  }
1731 
1732  /* Record the external dependencies */
1733  recordMultipleDependencies(depender,
1734  context.addrs->refs, context.addrs->numrefs,
1735  behavior);
1736 
1737  free_object_addresses(context.addrs);
1738 }
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2588
#define AccessShareLock
Definition: lockdefs.h:36
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44

References AccessShareLock, add_exact_object_address(), find_expr_references_context::addrs, ObjectAddress::classId, eliminate_duplicate_dependencies(), find_expr_references_walker(), free_object_addresses(), list_make1, new_object_addresses(), ObjectAddresses::numrefs, ObjectAddress::objectId, recordDependencyOn(), recordMultipleDependencies(), ObjectAddresses::refs, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::rellockmode, find_expr_references_context::rtables, RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by CreateConstraintEntry(), CreateStatistics(), index_create(), publication_add_relation(), StoreAttrDefault(), and StorePartitionKey().

◆ ReleaseDeletionLock()

void ReleaseDeletionLock ( const ObjectAddress object)

Definition at line 1584 of file dependency.c.

1585 {
1586  if (object->classId == RelationRelationId)
1588  else
1589  /* assume we should lock the whole object not a sub-object */
1590  UnlockDatabaseObject(object->classId, object->objectId, 0,
1592 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:228
void UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1026

References AccessExclusiveLock, ObjectAddress::classId, ObjectAddressStack::object, ObjectAddress::objectId, UnlockDatabaseObject(), and UnlockRelationOid().

Referenced by findDependentObjects(), and shdepDropOwned().

◆ reportDependentObjects()

static void reportDependentObjects ( const ObjectAddresses targetObjects,
DropBehavior  behavior,
int  flags,
const ObjectAddress origObject 
)
static

Definition at line 1036 of file dependency.c.

1040 {
1041  int msglevel = (flags & PERFORM_DELETION_QUIETLY) ? DEBUG2 : NOTICE;
1042  bool ok = true;
1043  StringInfoData clientdetail;
1044  StringInfoData logdetail;
1045  int numReportedClient = 0;
1046  int numNotReportedClient = 0;
1047  int i;
1048 
1049  /*
1050  * If we need to delete any partition-dependent objects, make sure that
1051  * we're deleting at least one of their partition dependencies, too. That
1052  * can be detected by checking that we reached them by a PARTITION
1053  * dependency at some point.
1054  *
1055  * We just report the first such object, as in most cases the only way to
1056  * trigger this complaint is to explicitly try to delete one partition of
1057  * a partitioned object.
1058  */
1059  for (i = 0; i < targetObjects->numrefs; i++)
1060  {
1061  const ObjectAddressExtra *extra = &targetObjects->extras[i];
1062 
1063  if ((extra->flags & DEPFLAG_IS_PART) &&
1064  !(extra->flags & DEPFLAG_PARTITION))
1065  {
1066  const ObjectAddress *object = &targetObjects->refs[i];
1067  char *otherObjDesc = getObjectDescription(&extra->dependee,
1068  false);
1069 
1070  ereport(ERROR,
1071  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1072  errmsg("cannot drop %s because %s requires it",
1073  getObjectDescription(object, false), otherObjDesc),
1074  errhint("You can drop %s instead.", otherObjDesc)));
1075  }
1076  }
1077 
1078  /*
1079  * If no error is to be thrown, and the msglevel is too low to be shown to
1080  * either client or server log, there's no need to do any of the rest of
1081  * the work.
1082  */
1083  if (behavior == DROP_CASCADE &&
1084  !message_level_is_interesting(msglevel))
1085  return;
1086 
1087  /*
1088  * We limit the number of dependencies reported to the client to
1089  * MAX_REPORTED_DEPS, since client software may not deal well with
1090  * enormous error strings. The server log always gets a full report.
1091  */
1092 #define MAX_REPORTED_DEPS 100
1093 
1094  initStringInfo(&clientdetail);
1095  initStringInfo(&logdetail);
1096 
1097  /*
1098  * We process the list back to front (ie, in dependency order not deletion
1099  * order), since this makes for a more understandable display.
1100  */
1101  for (i = targetObjects->numrefs - 1; i >= 0; i--)
1102  {
1103  const ObjectAddress *obj = &targetObjects->refs[i];
1104  const ObjectAddressExtra *extra = &targetObjects->extras[i];
1105  char *objDesc;
1106 
1107  /* Ignore the original deletion target(s) */
1108  if (extra->flags & DEPFLAG_ORIGINAL)
1109  continue;
1110 
1111  /* Also ignore sub-objects; we'll report the whole object elsewhere */
1112  if (extra->flags & DEPFLAG_SUBOBJECT)
1113  continue;
1114 
1115  objDesc = getObjectDescription(obj, false);
1116 
1117  /* An object being dropped concurrently doesn't need to be reported */
1118  if (objDesc == NULL)
1119  continue;
1120 
1121  /*
1122  * If, at any stage of the recursive search, we reached the object via
1123  * an AUTO, INTERNAL, PARTITION, or EXTENSION dependency, then it's
1124  * okay to delete it even in RESTRICT mode.
1125  */
1126  if (extra->flags & (DEPFLAG_AUTO |
1130  {
1131  /*
1132  * auto-cascades are reported at DEBUG2, not msglevel. We don't
1133  * try to combine them with the regular message because the
1134  * results are too confusing when client_min_messages and
1135  * log_min_messages are different.
1136  */
1137  ereport(DEBUG2,
1138  (errmsg_internal("drop auto-cascades to %s",
1139  objDesc)));
1140  }
1141  else if (behavior == DROP_RESTRICT)
1142  {
1143  char *otherDesc = getObjectDescription(&extra->dependee,
1144  false);
1145 
1146  if (otherDesc)
1147  {
1148  if (numReportedClient < MAX_REPORTED_DEPS)
1149  {
1150  /* separate entries with a newline */
1151  if (clientdetail.len != 0)
1152  appendStringInfoChar(&clientdetail, '\n');
1153  appendStringInfo(&clientdetail, _("%s depends on %s"),
1154  objDesc, otherDesc);
1155  numReportedClient++;
1156  }
1157  else
1158  numNotReportedClient++;
1159  /* separate entries with a newline */
1160  if (logdetail.len != 0)
1161  appendStringInfoChar(&logdetail, '\n');
1162  appendStringInfo(&logdetail, _("%s depends on %s"),
1163  objDesc, otherDesc);
1164  pfree(otherDesc);
1165  }
1166  else
1167  numNotReportedClient++;
1168  ok = false;
1169  }
1170  else
1171  {
1172  if (numReportedClient < MAX_REPORTED_DEPS)
1173  {
1174  /* separate entries with a newline */
1175  if (clientdetail.len != 0)
1176  appendStringInfoChar(&clientdetail, '\n');
1177  appendStringInfo(&clientdetail, _("drop cascades to %s"),
1178  objDesc);
1179  numReportedClient++;
1180  }
1181  else
1182  numNotReportedClient++;
1183  /* separate entries with a newline */
1184  if (logdetail.len != 0)
1185  appendStringInfoChar(&logdetail, '\n');
1186  appendStringInfo(&logdetail, _("drop cascades to %s"),
1187  objDesc);
1188  }
1189 
1190  pfree(objDesc);
1191  }
1192 
1193  if (numNotReportedClient > 0)
1194  appendStringInfo(&clientdetail, ngettext("\nand %d other object "
1195  "(see server log for list)",
1196  "\nand %d other objects "
1197  "(see server log for list)",
1198  numNotReportedClient),
1199  numNotReportedClient);
1200 
1201  if (!ok)
1202  {
1203  if (origObject)
1204  ereport(ERROR,
1205  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1206  errmsg("cannot drop %s because other objects depend on it",
1207  getObjectDescription(origObject, false)),
1208  errdetail_internal("%s", clientdetail.data),
1209  errdetail_log("%s", logdetail.data),
1210  errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
1211  else
1212  ereport(ERROR,
1213  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1214  errmsg("cannot drop desired object(s) because other objects depend on them"),
1215  errdetail_internal("%s", clientdetail.data),
1216  errdetail_log("%s", logdetail.data),
1217  errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
1218  }
1219  else if (numReportedClient > 1)
1220  {
1221  ereport(msglevel,
1222  (errmsg_plural("drop cascades to %d other object",
1223  "drop cascades to %d other objects",
1224  numReportedClient + numNotReportedClient,
1225  numReportedClient + numNotReportedClient),
1226  errdetail_internal("%s", clientdetail.data),
1227  errdetail_log("%s", logdetail.data)));
1228  }
1229  else if (numReportedClient == 1)
1230  {
1231  /* we just use the single item as-is */
1232  ereport(msglevel,
1233  (errmsg_internal("%s", clientdetail.data)));
1234  }
1235 
1236  pfree(clientdetail.data);
1237  pfree(logdetail.data);
1238 }
#define ngettext(s, p, n)
Definition: c.h:1170
#define MAX_REPORTED_DEPS
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:138
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1185
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1162
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1235
bool message_level_is_interesting(int elevel)
Definition: elog.c:277
int errdetail_log(const char *fmt,...)
Definition: elog.c:1256
#define _(x)
Definition: elog.c:91
#define DEBUG2
Definition: elog.h:29
#define NOTICE
Definition: elog.h:35
@ DROP_CASCADE
Definition: parsenodes.h:2170
@ DROP_RESTRICT
Definition: parsenodes.h:2169
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

References _, appendStringInfo(), appendStringInfoChar(), StringInfoData::data, DEBUG2, ObjectAddressExtra::dependee, DEPFLAG_AUTO, DEPFLAG_EXTENSION, DEPFLAG_INTERNAL, DEPFLAG_IS_PART, DEPFLAG_ORIGINAL, DEPFLAG_PARTITION, DEPFLAG_SUBOBJECT, DROP_CASCADE, DROP_RESTRICT, ereport, errcode(), errdetail_internal(), errdetail_log(), errhint(), errmsg(), errmsg_internal(), errmsg_plural(), ERROR, ObjectAddresses::extras, ObjectAddressExtra::flags, ObjectAddressStack::flags, getObjectDescription(), i, initStringInfo(), StringInfoData::len, MAX_REPORTED_DEPS, message_level_is_interesting(), ngettext, NOTICE, ObjectAddresses::numrefs, PERFORM_DELETION_QUIETLY, pfree(), and ObjectAddresses::refs.

Referenced by performDeletion(), and performMultipleDeletions().

◆ sort_object_addresses()

void sort_object_addresses ( ObjectAddresses addrs)

Definition at line 2816 of file dependency.c.

2817 {
2818  if (addrs->numrefs > 1)
2819  qsort(addrs->refs, addrs->numrefs,
2820  sizeof(ObjectAddress),
2822 }

References ObjectAddresses::numrefs, object_address_comparator(), qsort, and ObjectAddresses::refs.

Referenced by shdepDropOwned().

◆ stack_address_present_add_flags()

static bool stack_address_present_add_flags ( const ObjectAddress object,
int  flags,
ObjectAddressStack stack 
)
static

Definition at line 2747 of file dependency.c.

2750 {
2751  bool result = false;
2752  ObjectAddressStack *stackptr;
2753 
2754  for (stackptr = stack; stackptr; stackptr = stackptr->next)
2755  {
2756  const ObjectAddress *thisobj = stackptr->object;
2757 
2758  if (object->classId == thisobj->classId &&
2759  object->objectId == thisobj->objectId)
2760  {
2761  if (object->objectSubId == thisobj->objectSubId)
2762  {
2763  stackptr->flags |= flags;
2764  result = true;
2765  }
2766  else if (thisobj->objectSubId == 0)
2767  {
2768  /*
2769  * We're visiting a column with whole table already on stack.
2770  * As in object_address_present_add_flags(), we can skip
2771  * further processing of the subobject, but we don't want to
2772  * propagate flags for the subobject to the whole object.
2773  */
2774  result = true;
2775  }
2776  else if (object->objectSubId == 0)
2777  {
2778  /*
2779  * We're visiting a table with column already on stack. As in
2780  * object_address_present_add_flags(), we should propagate
2781  * flags for the whole object to each of its subobjects.
2782  */
2783  if (flags)
2784  stackptr->flags |= (flags | DEPFLAG_SUBOBJECT);
2785  }
2786  }
2787  }
2788 
2789  return result;
2790 }

References ObjectAddress::classId, DEPFLAG_SUBOBJECT, ObjectAddressStack::flags, ObjectAddressStack::next, ObjectAddressStack::object, ObjectAddress::objectId, and ObjectAddress::objectSubId.

Referenced by findDependentObjects().

◆ StaticAssertDecl()

StaticAssertDecl ( lengthof(object_classes = =LAST_OCLASS+1,
"object_classes []must cover all ObjectClasses"   
)

Variable Documentation

◆ object_classes

const Oid object_classes[]
static

Definition at line 151 of file dependency.c.

Referenced by add_object_address().