1/*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_depend relation
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/pg_depend.c
13 *-------------------------------------------------------------------------
29#include "utils/fmgroids.h"
38 * Record a dependency between 2 objects via their respective ObjectAddress.
39 * The first argument is the dependent object, the second the one it
42 * This simply creates an entry in pg_depend, without any other processing.
53 * Record multiple dependencies (of the same kind) for a single dependent
54 * object. This has a little less overhead than recording each separately.
71 return;
/* nothing to do */
74 * During bootstrap, do nothing since pg_depend may not exist yet.
76 * Objects created during bootstrap are most likely pinned, and the few
77 * that are not do not have dependencies on each other, so that there
78 * would be no need to make a pg_depend entry anyway.
86 * Allocate the slots to use, but delay costly initialization until we
87 * know that they will be used.
89 max_slots =
Min(nreferenced,
93 /* Don't open indexes unless we need to make an update */
96 /* number of slots currently storing tuples */
97 slot_stored_count = 0;
98 /* number of slots currently initialized */
100 for (
i = 0;
i < nreferenced;
i++, referenced++)
103 * If the referenced object is pinned by the system, there's no real
104 * need to record dependencies on it. This saves lots of space in
105 * pg_depend, so it's worth the time taken to check.
110 if (slot_init_count < max_slots)
120 * Record the dependency. Note we don't bother to check for duplicate
121 * dependencies; there's no harm in them.
131 memset(slot[slot_stored_count]->tts_isnull,
false,
132 slot[slot_stored_count]->tts_tupleDescriptor->natts *
sizeof(
bool));
137 /* If slots are full, insert a batch of tuples */
138 if (slot_stored_count == max_slots)
140 /* fetch index info only when we know we need it */
141 if (indstate == NULL)
146 slot_stored_count = 0;
150 /* Insert any tuples left in the buffer */
151 if (slot_stored_count > 0)
153 /* fetch index info only when we know we need it */
154 if (indstate == NULL)
161 if (indstate != NULL)
166 /* Drop only the number of slots used */
167 for (
i = 0;
i < slot_init_count;
i++)
173 * If we are executing a CREATE EXTENSION operation, mark the given object
174 * as being a member of the extension, or check that it already is one.
175 * Otherwise, do nothing.
177 * This must be called during creation of any user-definable object type
178 * that could be a member of an extension.
180 * isReplace must be true if the object already existed, and false if it is
181 * newly created. In the former case we insist that it already be a member
182 * of the current extension. In the latter case we can skip checking whether
183 * it is already a member of any extension.
185 * Note: isReplace = true is typically used when updating an object in
186 * CREATE OR REPLACE and similar commands. We used to allow the target
187 * object to not already be an extension member, instead silently absorbing
188 * it into the current extension. However, this was both error-prone
189 * (extensions might accidentally overwrite free-standing objects) and
190 * a security hazard (since the object would retain its previous ownership).
196 /* Only whole objects can be extension members */
203 /* Only need to check for existing membership if isReplace */
209 * Side note: these catalog lookups are safe only because the
210 * object is a pre-existing one. In the not-isReplace case, the
211 * caller has most likely not yet done a CommandCounterIncrement
212 * that would make the new object visible.
217 /* If already a member of this extension, nothing to do */
220 /* Already a member of some other extension, so reject */
222 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
223 errmsg(
"%s is already a member of extension \"%s\"",
227 /* It's a free-standing object, so reject */
229 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
230 errmsg(
"%s is not a member of extension \"%s\"",
233 errdetail(
"An extension is not allowed to replace an object that it does not own.")));
236 /* OK, record it as a member of CurrentExtensionObject */
237 extension.
classId = ExtensionRelationId;
246 * If we are executing a CREATE EXTENSION operation, check that the given
247 * object is a member of the extension, and throw an error if it isn't.
248 * Otherwise, do nothing.
250 * This must be called whenever a CREATE IF NOT EXISTS operation (for an
251 * object type that can be an extension member) has found that an object of
252 * the desired name already exists. It is insecure for an extension to use
253 * IF NOT EXISTS except when the conflicting object is already an extension
254 * member; otherwise a hostile user could substitute an object with arbitrary
261 * This is actually the same condition tested in
262 * recordDependencyOnCurrentExtension; but we want to issue a
263 * differently-worded error, and anyway it would be pretty confusing to
264 * call recordDependencyOnCurrentExtension in these circumstances.
267 /* Only whole objects can be extension members */
275 /* If already a member of this extension, OK */
280 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
281 errmsg(
"%s is not a member of extension \"%s\"",
284 errdetail(
"An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.")));
289 * deleteDependencyRecordsFor -- delete all records with given depender
290 * classId/objectId. Returns the number of records deleted.
292 * This is used when redefining an existing object. Links leading to the
293 * object do not change, and links leading from it will be recreated
294 * (possibly with some differences from before).
296 * If skipExtensionDeps is true, we do not delete any dependencies that
297 * show that the given object is a member of an extension. This avoids
298 * needing a lot of extra logic to fetch and recreate that dependency.
302 bool skipExtensionDeps)
313 Anum_pg_depend_classid,
317 Anum_pg_depend_objid,
326 if (skipExtensionDeps &&
342 * deleteDependencyRecordsForClass -- delete all records with given depender
343 * classId/objectId, dependee classId, and deptype.
344 * Returns the number of records deleted.
346 * This is a variant of deleteDependencyRecordsFor, useful when revoking
347 * an object property that is expressed by a dependency record (such as
348 * extension membership).
352 Oid refclassId,
char deptype)
363 Anum_pg_depend_classid,
367 Anum_pg_depend_objid,
378 if (depform->refclassid == refclassId && depform->deptype == deptype)
393 * deleteDependencyRecordsForSpecific -- delete all records with given depender
394 * classId/objectId, dependee classId/objectId, of the given deptype.
395 * Returns the number of records deleted.
399 Oid refclassId,
Oid refobjectId)
410 Anum_pg_depend_classid,
414 Anum_pg_depend_objid,
425 if (depform->refclassid == refclassId &&
426 depform->refobjid == refobjectId &&
427 depform->deptype == deptype)
442 * Adjust dependency record(s) to point to a different object of the same type
444 * classId/objectId specify the referencing object.
445 * refClassId/oldRefObjectId specify the old referenced object.
446 * newRefObjectId is the new referenced object (must be of class refClassId).
448 * Note the lack of objsubid parameters. If there are subobject references
449 * they will all be readjusted. Also, there is an expectation that we are
450 * dealing with NORMAL dependencies: if we have to replace an (implicit)
451 * dependency on a pinned object with an explicit dependency on an unpinned
452 * one, the new one will be NORMAL.
454 * Returns the number of records updated -- zero indicates a problem.
458 Oid refClassId,
Oid oldRefObjectId,
472 * Check to see if either oldRefObjectId or newRefObjectId is pinned.
473 * Pinned objects should not have any dependency entries pointing to them,
474 * so in these cases we should add or remove a pg_depend entry, or do
475 * nothing at all, rather than update an entry as in the normal case.
490 * If both are pinned, we need do nothing. However, return 1 not 0,
491 * else callers will think this is an error case.
497 * There is no old dependency record, but we should insert a new one.
498 * Assume a normal dependency is wanted.
510 /* There should be existing dependency record(s), so search. */
512 Anum_pg_depend_classid,
516 Anum_pg_depend_objid,
527 if (depform->refclassid == refClassId &&
528 depform->refobjid == oldRefObjectId)
534 /* make a modifiable copy */
538 depform->refobjid = newRefObjectId;
557 * Adjust all dependency records to come from a different object of the same type
559 * classId/oldObjectId specify the old referencing object.
560 * newObjectId is the new referencing object (must be of class classId).
562 * Returns the number of records updated.
577 Anum_pg_depend_classid,
581 Anum_pg_depend_objid,
592 /* make a modifiable copy */
596 depform->objid = newObjectId;
613 * Adjust all dependency records to point to a different object of the same type
615 * refClassId/oldRefObjectId specify the old referenced object.
616 * newRefObjectId is the new referenced object (must be of class refClassId).
618 * Returns the number of records updated.
635 * If oldRefObjectId is pinned, there won't be any dependency entries on
636 * it --- we can't cope in that case. (This isn't really worth expending
637 * code to fix, in current usage; it just means you can't rename stuff out
638 * of pg_catalog, which would likely be a bad move anyway.)
646 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
647 errmsg(
"cannot remove dependency on %s because it is a system object",
651 * We can handle adding a dependency on something pinned, though, since
652 * that just means deleting the dependency entry.
658 /* Now search for dependency records */
660 Anum_pg_depend_refclassid,
664 Anum_pg_depend_refobjid,
679 /* make a modifiable copy */
683 depform->refobjid = newRefObjectId;
703 * Test if an object is required for basic database functionality.
705 * The passed subId, if any, is ignored; we assume that only whole objects
706 * are pinned (and that this implies pinning their components).
716 * Various special-purpose lookups and manipulations of pg_depend.
721 * Find the extension containing the specified object, if any
723 * Returns the OID of the extension, or InvalidOid if the object does not
724 * belong to any extension.
726 * Extension membership is marked by an EXTENSION dependency from the object
727 * to the extension. Note that the result will be indeterminate if pg_depend
728 * contains links from this object to more than one extension ... but that
729 * should never happen.
743 Anum_pg_depend_classid,
747 Anum_pg_depend_objid,
758 if (depform->refclassid == ExtensionRelationId &&
761 result = depform->refobjid;
762 break;
/* no need to keep scanning */
774 * Return (possibly NIL) list of extensions that the given object depends on
775 * in DEPENDENCY_AUTO_EXTENSION mode.
789 Anum_pg_depend_classid,
793 Anum_pg_depend_objid,
804 if (depform->refclassid == ExtensionRelationId &&
817 * Detect whether a sequence is marked as "owned" by a column
819 * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
820 * column. If we find one, store the identity of the owning column
821 * into *tableId and *colId and return true; else return false.
823 * Note: if there's more than one such pg_depend entry then you get
824 * a random one of them returned into the out parameters. This should
825 * not happen, though.
839 Anum_pg_depend_classid,
843 Anum_pg_depend_objid,
854 if (depform->refclassid == RelationRelationId &&
855 depform->deptype == deptype)
857 *tableId = depform->refobjid;
858 *colId = depform->refobjsubid;
860 break;
/* no need to keep scanning */
872 * Collect a list of OIDs of all sequences owned by the specified relation,
873 * and column if specified. If deptype is not zero, then only find sequences
874 * with the specified dependency type.
888 Anum_pg_depend_refclassid,
892 Anum_pg_depend_refobjid,
897 Anum_pg_depend_refobjsubid,
909 * We assume any auto or internal dependency of a sequence on a column
910 * must be what we are looking for. (We need the relkind test because
911 * indexes can also have auto dependencies on columns.)
913 if (deprec->classid == RelationRelationId &&
914 deprec->objsubid == 0 &&
915 deprec->refobjsubid != 0 &&
919 if (!deptype || deprec->deptype == deptype)
932 * Collect a list of OIDs of all sequences owned (identity or serial) by the
933 * specified relation.
942 * Get owned identity sequence, error if not exactly one.
951 * The identity sequence is associated with the topmost partitioned table,
952 * which might have column order different than the given partition.
962 elog(
ERROR,
"cache lookup failed for attribute \"%s\" of relation %u",
969 elog(
ERROR,
"more than one owned sequence found");
970 else if (seqlist ==
NIL)
982 * get_index_constraint
983 * Given the OID of an index, return the OID of the owning unique,
984 * primary-key, or exclusion constraint, or InvalidOid if there
985 * is no owning constraint.
996 /* Search the dependency table for the index */
1000 Anum_pg_depend_classid,
1004 Anum_pg_depend_objid,
1008 Anum_pg_depend_objsubid,
1020 * We assume any internal dependency on a constraint must be what we
1023 if (deprec->refclassid == ConstraintRelationId &&
1024 deprec->refobjsubid == 0 &&
1027 constraintId = deprec->refobjid;
1035 return constraintId;
1039 * get_index_ref_constraints
1040 * Given the OID of an index, return the OID of all foreign key
1041 * constraints which reference the index.
1052 /* Search the dependency table for the index */
1056 Anum_pg_depend_refclassid,
1060 Anum_pg_depend_refobjid,
1064 Anum_pg_depend_refobjsubid,
1076 * We assume any normal dependency from a constraint must be what we
1079 if (deprec->classid == ConstraintRelationId &&
1080 deprec->objsubid == 0 &&
#define InvalidAttrNumber
#define OidIsValid(objectId)
bool IsPinnedObject(Oid classId, Oid objectId)
@ DEPENDENCY_AUTO_EXTENSION
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
const TupleTableSlotOps TTSOpsHeapTuple
Oid CurrentExtensionObject
char * get_extension_name(Oid ext_oid)
void systable_endscan(SysScanDesc sysscan)
HeapTuple systable_getnext(SysScanDesc sysscan)
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_copytuple(HeapTuple tuple)
void heap_freetuple(HeapTuple htup)
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
void CatalogCloseIndexes(CatalogIndexState indstate)
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
#define MAX_CATALOG_MULTI_INSERT_BYTES
List * lappend_oid(List *list, Oid datum)
void list_free(List *list)
AttrNumber get_attnum(Oid relid, const char *attname)
char get_rel_relkind(Oid relid)
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
void pfree(void *pointer)
#define IsBootstrapProcessingMode()
char * getObjectDescription(const ObjectAddress *object, bool missing_ok)
List * get_partition_ancestors(Oid relid)
void checkMembershipInCurrentExtension(const ObjectAddress *object)
void recordMultipleDependencies(const ObjectAddress *depender, const ObjectAddress *referenced, int nreferenced, DependencyType behavior)
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
static bool isObjectPinned(const ObjectAddress *object)
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Oid getExtensionOfObject(Oid classId, Oid objectId)
long changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId)
List * get_index_ref_constraints(Oid indexId)
List * getOwnedSequences(Oid relid)
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
long deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype, Oid refclassId, Oid refobjectId)
long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
static List * getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Oid get_index_constraint(Oid indexId)
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
List * getAutoExtensionsOfObject(Oid classId, Oid objectId)
FormData_pg_depend * Form_pg_depend
static int list_length(const List *l)
static Datum ObjectIdGetDatum(Oid X)
static Datum Int32GetDatum(int32 X)
static Datum CharGetDatum(char X)
#define RelationGetForm(relation)
#define RelationGetRelid(relation)
#define RelationGetDescr(relation)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
#define BTEqualStrategyNumber
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)