1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_depend relation
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/pg_depend.c
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/htup_details.h"
19 #include "access/table.h"
20 #include "catalog/catalog.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/pg_constraint.h"
24 #include "catalog/pg_depend.h"
25 #include "catalog/pg_extension.h"
26 #include "catalog/partition.h"
27 #include "commands/extension.h"
28 #include "miscadmin.h"
29 #include "utils/fmgroids.h"
30 #include "utils/lsyscache.h"
31 #include "utils/rel.h"
34 static bool isObjectPinned(const ObjectAddress
*object
);
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.
45 recordDependencyOn(const ObjectAddress
*depender
,
46 const ObjectAddress
*referenced
,
47 DependencyType behavior
)
49 recordMultipleDependencies(depender
, referenced
, 1, behavior
);
53 * Record multiple dependencies (of the same kind) for a single dependent
54 * object. This has a little less overhead than recording each separately.
57 recordMultipleDependencies(const ObjectAddress
*depender
,
58 const ObjectAddress
*referenced
,
60 DependencyType behavior
)
63 CatalogIndexState indstate
;
64 TupleTableSlot
**slot
;
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.
80 if (IsBootstrapProcessingMode())
83 dependDesc
= table_open(DependRelationId
, RowExclusiveLock
);
86 * Allocate the slots to use, but delay costly initialization until we
87 * know that they will be used.
89 max_slots
= Min(nreferenced
,
90 MAX_CATALOG_MULTI_INSERT_BYTES
/ sizeof(FormData_pg_depend
));
91 slot
= palloc(sizeof(TupleTableSlot
*) * max_slots
);
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.
107 if (isObjectPinned(referenced
))
110 if (slot_init_count
< max_slots
)
112 slot
[slot_stored_count
] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc
),
117 ExecClearTuple(slot
[slot_stored_count
]);
120 * Record the dependency. Note we don't bother to check for duplicate
121 * dependencies; there's no harm in them.
123 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_refclassid
- 1] = ObjectIdGetDatum(referenced
->classId
);
124 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_refobjid
- 1] = ObjectIdGetDatum(referenced
->objectId
);
125 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_refobjsubid
- 1] = Int32GetDatum(referenced
->objectSubId
);
126 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_deptype
- 1] = CharGetDatum((char) behavior
);
127 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_classid
- 1] = ObjectIdGetDatum(depender
->classId
);
128 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_objid
- 1] = ObjectIdGetDatum(depender
->objectId
);
129 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_objsubid
- 1] = Int32GetDatum(depender
->objectSubId
);
131 memset(slot
[slot_stored_count
]->tts_isnull
, false,
132 slot
[slot_stored_count
]->tts_tupleDescriptor
->natts
* sizeof(bool));
134 ExecStoreVirtualTuple(slot
[slot_stored_count
]);
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
)
142 indstate
= CatalogOpenIndexes(dependDesc
);
144 CatalogTuplesMultiInsertWithInfo(dependDesc
, slot
, slot_stored_count
,
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
)
155 indstate
= CatalogOpenIndexes(dependDesc
);
157 CatalogTuplesMultiInsertWithInfo(dependDesc
, slot
, slot_stored_count
,
161 if (indstate
!= NULL
)
162 CatalogCloseIndexes(indstate
);
164 table_close(dependDesc
, RowExclusiveLock
);
166 /* Drop only the number of slots used */
167 for (i
= 0; i
< slot_init_count
; i
++)
168 ExecDropSingleTupleTableSlot(slot
[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).
193 recordDependencyOnCurrentExtension(const ObjectAddress
*object
,
196 /* Only whole objects can be extension members */
197 Assert(object
->objectSubId
== 0);
199 if (creating_extension
)
201 ObjectAddress extension
;
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.
214 oldext
= getExtensionOfObject(object
->classId
, object
->objectId
);
215 if (OidIsValid(oldext
))
217 /* If already a member of this extension, nothing to do */
218 if (oldext
== CurrentExtensionObject
)
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\"",
224 getObjectDescription(object
, false),
225 get_extension_name(oldext
))));
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\"",
231 getObjectDescription(object
, false),
232 get_extension_name(CurrentExtensionObject
)),
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
;
238 extension
.objectId
= CurrentExtensionObject
;
239 extension
.objectSubId
= 0;
241 recordDependencyOn(object
, &extension
, DEPENDENCY_EXTENSION
);
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
258 checkMembershipInCurrentExtension(const ObjectAddress
*object
)
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 */
268 Assert(object
->objectSubId
== 0);
270 if (creating_extension
)
274 oldext
= getExtensionOfObject(object
->classId
, object
->objectId
);
275 /* If already a member of this extension, OK */
276 if (oldext
== CurrentExtensionObject
)
280 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
281 errmsg("%s is not a member of extension \"%s\"",
282 getObjectDescription(object
, false),
283 get_extension_name(CurrentExtensionObject
)),
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.
301 deleteDependencyRecordsFor(Oid classId
, Oid objectId
,
302 bool skipExtensionDeps
)
310 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
313 Anum_pg_depend_classid
,
314 BTEqualStrategyNumber
, F_OIDEQ
,
315 ObjectIdGetDatum(classId
));
317 Anum_pg_depend_objid
,
318 BTEqualStrategyNumber
, F_OIDEQ
,
319 ObjectIdGetDatum(objectId
));
321 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
324 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
326 if (skipExtensionDeps
&&
327 ((Form_pg_depend
) GETSTRUCT(tup
))->deptype
== DEPENDENCY_EXTENSION
)
330 CatalogTupleDelete(depRel
, &tup
->t_self
);
334 systable_endscan(scan
);
336 table_close(depRel
, RowExclusiveLock
);
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).
351 deleteDependencyRecordsForClass(Oid classId
, Oid objectId
,
352 Oid refclassId
, char deptype
)
360 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
363 Anum_pg_depend_classid
,
364 BTEqualStrategyNumber
, F_OIDEQ
,
365 ObjectIdGetDatum(classId
));
367 Anum_pg_depend_objid
,
368 BTEqualStrategyNumber
, F_OIDEQ
,
369 ObjectIdGetDatum(objectId
));
371 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
374 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
376 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
378 if (depform
->refclassid
== refclassId
&& depform
->deptype
== deptype
)
380 CatalogTupleDelete(depRel
, &tup
->t_self
);
385 systable_endscan(scan
);
387 table_close(depRel
, RowExclusiveLock
);
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.
398 deleteDependencyRecordsForSpecific(Oid classId
, Oid objectId
, char deptype
,
399 Oid refclassId
, Oid refobjectId
)
407 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
410 Anum_pg_depend_classid
,
411 BTEqualStrategyNumber
, F_OIDEQ
,
412 ObjectIdGetDatum(classId
));
414 Anum_pg_depend_objid
,
415 BTEqualStrategyNumber
, F_OIDEQ
,
416 ObjectIdGetDatum(objectId
));
418 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
421 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
423 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
425 if (depform
->refclassid
== refclassId
&&
426 depform
->refobjid
== refobjectId
&&
427 depform
->deptype
== deptype
)
429 CatalogTupleDelete(depRel
, &tup
->t_self
);
434 systable_endscan(scan
);
436 table_close(depRel
, RowExclusiveLock
);
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.
457 changeDependencyFor(Oid classId
, Oid objectId
,
458 Oid refClassId
, Oid oldRefObjectId
,
466 ObjectAddress objAddr
;
467 ObjectAddress depAddr
;
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.
477 objAddr
.classId
= refClassId
;
478 objAddr
.objectId
= oldRefObjectId
;
479 objAddr
.objectSubId
= 0;
481 oldIsPinned
= isObjectPinned(&objAddr
);
483 objAddr
.objectId
= newRefObjectId
;
485 newIsPinned
= isObjectPinned(&objAddr
);
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.
500 depAddr
.classId
= classId
;
501 depAddr
.objectId
= objectId
;
502 depAddr
.objectSubId
= 0;
503 recordDependencyOn(&depAddr
, &objAddr
, DEPENDENCY_NORMAL
);
508 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
510 /* There should be existing dependency record(s), so search. */
512 Anum_pg_depend_classid
,
513 BTEqualStrategyNumber
, F_OIDEQ
,
514 ObjectIdGetDatum(classId
));
516 Anum_pg_depend_objid
,
517 BTEqualStrategyNumber
, F_OIDEQ
,
518 ObjectIdGetDatum(objectId
));
520 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
523 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
525 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
527 if (depform
->refclassid
== refClassId
&&
528 depform
->refobjid
== oldRefObjectId
)
531 CatalogTupleDelete(depRel
, &tup
->t_self
);
534 /* make a modifiable copy */
535 tup
= heap_copytuple(tup
);
536 depform
= (Form_pg_depend
) GETSTRUCT(tup
);
538 depform
->refobjid
= newRefObjectId
;
540 CatalogTupleUpdate(depRel
, &tup
->t_self
, tup
);
549 systable_endscan(scan
);
551 table_close(depRel
, RowExclusiveLock
);
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.
565 changeDependenciesOf(Oid classId
, Oid oldObjectId
,
574 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
577 Anum_pg_depend_classid
,
578 BTEqualStrategyNumber
, F_OIDEQ
,
579 ObjectIdGetDatum(classId
));
581 Anum_pg_depend_objid
,
582 BTEqualStrategyNumber
, F_OIDEQ
,
583 ObjectIdGetDatum(oldObjectId
));
585 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
588 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
590 Form_pg_depend depform
;
592 /* make a modifiable copy */
593 tup
= heap_copytuple(tup
);
594 depform
= (Form_pg_depend
) GETSTRUCT(tup
);
596 depform
->objid
= newObjectId
;
598 CatalogTupleUpdate(depRel
, &tup
->t_self
, tup
);
605 systable_endscan(scan
);
607 table_close(depRel
, RowExclusiveLock
);
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.
621 changeDependenciesOn(Oid refClassId
, Oid oldRefObjectId
,
629 ObjectAddress objAddr
;
632 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
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.)
640 objAddr
.classId
= refClassId
;
641 objAddr
.objectId
= oldRefObjectId
;
642 objAddr
.objectSubId
= 0;
644 if (isObjectPinned(&objAddr
))
646 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
647 errmsg("cannot remove dependency on %s because it is a system object",
648 getObjectDescription(&objAddr
, false))));
651 * We can handle adding a dependency on something pinned, though, since
652 * that just means deleting the dependency entry.
654 objAddr
.objectId
= newRefObjectId
;
656 newIsPinned
= isObjectPinned(&objAddr
);
658 /* Now search for dependency records */
660 Anum_pg_depend_refclassid
,
661 BTEqualStrategyNumber
, F_OIDEQ
,
662 ObjectIdGetDatum(refClassId
));
664 Anum_pg_depend_refobjid
,
665 BTEqualStrategyNumber
, F_OIDEQ
,
666 ObjectIdGetDatum(oldRefObjectId
));
668 scan
= systable_beginscan(depRel
, DependReferenceIndexId
, true,
671 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
674 CatalogTupleDelete(depRel
, &tup
->t_self
);
677 Form_pg_depend depform
;
679 /* make a modifiable copy */
680 tup
= heap_copytuple(tup
);
681 depform
= (Form_pg_depend
) GETSTRUCT(tup
);
683 depform
->refobjid
= newRefObjectId
;
685 CatalogTupleUpdate(depRel
, &tup
->t_self
, tup
);
693 systable_endscan(scan
);
695 table_close(depRel
, RowExclusiveLock
);
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).
709 isObjectPinned(const ObjectAddress
*object
)
711 return IsPinnedObject(object
->classId
, object
->objectId
);
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.
732 getExtensionOfObject(Oid classId
, Oid objectId
)
734 Oid result
= InvalidOid
;
740 depRel
= table_open(DependRelationId
, AccessShareLock
);
743 Anum_pg_depend_classid
,
744 BTEqualStrategyNumber
, F_OIDEQ
,
745 ObjectIdGetDatum(classId
));
747 Anum_pg_depend_objid
,
748 BTEqualStrategyNumber
, F_OIDEQ
,
749 ObjectIdGetDatum(objectId
));
751 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
754 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
756 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
758 if (depform
->refclassid
== ExtensionRelationId
&&
759 depform
->deptype
== DEPENDENCY_EXTENSION
)
761 result
= depform
->refobjid
;
762 break; /* no need to keep scanning */
766 systable_endscan(scan
);
768 table_close(depRel
, AccessShareLock
);
774 * Return (possibly NIL) list of extensions that the given object depends on
775 * in DEPENDENCY_AUTO_EXTENSION mode.
778 getAutoExtensionsOfObject(Oid classId
, Oid objectId
)
786 depRel
= table_open(DependRelationId
, AccessShareLock
);
789 Anum_pg_depend_classid
,
790 BTEqualStrategyNumber
, F_OIDEQ
,
791 ObjectIdGetDatum(classId
));
793 Anum_pg_depend_objid
,
794 BTEqualStrategyNumber
, F_OIDEQ
,
795 ObjectIdGetDatum(objectId
));
797 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
800 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
802 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
804 if (depform
->refclassid
== ExtensionRelationId
&&
805 depform
->deptype
== DEPENDENCY_AUTO_EXTENSION
)
806 result
= lappend_oid(result
, depform
->refobjid
);
809 systable_endscan(scan
);
811 table_close(depRel
, AccessShareLock
);
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.
828 sequenceIsOwned(Oid seqId
, char deptype
, Oid
*tableId
, int32
*colId
)
836 depRel
= table_open(DependRelationId
, AccessShareLock
);
839 Anum_pg_depend_classid
,
840 BTEqualStrategyNumber
, F_OIDEQ
,
841 ObjectIdGetDatum(RelationRelationId
));
843 Anum_pg_depend_objid
,
844 BTEqualStrategyNumber
, F_OIDEQ
,
845 ObjectIdGetDatum(seqId
));
847 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
850 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
852 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
854 if (depform
->refclassid
== RelationRelationId
&&
855 depform
->deptype
== deptype
)
857 *tableId
= depform
->refobjid
;
858 *colId
= depform
->refobjsubid
;
860 break; /* no need to keep scanning */
864 systable_endscan(scan
);
866 table_close(depRel
, AccessShareLock
);
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.
877 getOwnedSequences_internal(Oid relid
, AttrNumber attnum
, char deptype
)
885 depRel
= table_open(DependRelationId
, AccessShareLock
);
888 Anum_pg_depend_refclassid
,
889 BTEqualStrategyNumber
, F_OIDEQ
,
890 ObjectIdGetDatum(RelationRelationId
));
892 Anum_pg_depend_refobjid
,
893 BTEqualStrategyNumber
, F_OIDEQ
,
894 ObjectIdGetDatum(relid
));
897 Anum_pg_depend_refobjsubid
,
898 BTEqualStrategyNumber
, F_INT4EQ
,
899 Int32GetDatum(attnum
));
901 scan
= systable_beginscan(depRel
, DependReferenceIndexId
, true,
902 NULL
, attnum
? 3 : 2, key
);
904 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
906 Form_pg_depend deprec
= (Form_pg_depend
) GETSTRUCT(tup
);
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 &&
916 (deprec
->deptype
== DEPENDENCY_AUTO
|| deprec
->deptype
== DEPENDENCY_INTERNAL
) &&
917 get_rel_relkind(deprec
->objid
) == RELKIND_SEQUENCE
)
919 if (!deptype
|| deprec
->deptype
== deptype
)
920 result
= lappend_oid(result
, deprec
->objid
);
924 systable_endscan(scan
);
926 table_close(depRel
, AccessShareLock
);
932 * Collect a list of OIDs of all sequences owned (identity or serial) by the
933 * specified relation.
936 getOwnedSequences(Oid relid
)
938 return getOwnedSequences_internal(relid
, 0, 0);
942 * Get owned identity sequence, error if not exactly one.
945 getIdentitySequence(Relation rel
, AttrNumber attnum
, bool missing_ok
)
947 Oid relid
= RelationGetRelid(rel
);
951 * The identity sequence is associated with the topmost partitioned table,
952 * which might have column order different than the given partition.
954 if (RelationGetForm(rel
)->relispartition
)
956 List
*ancestors
= get_partition_ancestors(relid
);
957 const char *attname
= get_attname(relid
, attnum
, false);
959 relid
= llast_oid(ancestors
);
960 attnum
= get_attnum(relid
, attname
);
961 if (attnum
== InvalidAttrNumber
)
962 elog(ERROR
, "cache lookup failed for attribute \"%s\" of relation %u",
964 list_free(ancestors
);
967 seqlist
= getOwnedSequences_internal(relid
, attnum
, DEPENDENCY_INTERNAL
);
968 if (list_length(seqlist
) > 1)
969 elog(ERROR
, "more than one owned sequence found");
970 else if (seqlist
== NIL
)
975 elog(ERROR
, "no owned sequence found");
978 return linitial_oid(seqlist
);
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.
988 get_index_constraint(Oid indexId
)
990 Oid constraintId
= InvalidOid
;
996 /* Search the dependency table for the index */
997 depRel
= table_open(DependRelationId
, AccessShareLock
);
1000 Anum_pg_depend_classid
,
1001 BTEqualStrategyNumber
, F_OIDEQ
,
1002 ObjectIdGetDatum(RelationRelationId
));
1003 ScanKeyInit(&key
[1],
1004 Anum_pg_depend_objid
,
1005 BTEqualStrategyNumber
, F_OIDEQ
,
1006 ObjectIdGetDatum(indexId
));
1007 ScanKeyInit(&key
[2],
1008 Anum_pg_depend_objsubid
,
1009 BTEqualStrategyNumber
, F_INT4EQ
,
1012 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
1015 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
1017 Form_pg_depend deprec
= (Form_pg_depend
) GETSTRUCT(tup
);
1020 * We assume any internal dependency on a constraint must be what we
1023 if (deprec
->refclassid
== ConstraintRelationId
&&
1024 deprec
->refobjsubid
== 0 &&
1025 deprec
->deptype
== DEPENDENCY_INTERNAL
)
1027 constraintId
= deprec
->refobjid
;
1032 systable_endscan(scan
);
1033 table_close(depRel
, AccessShareLock
);
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.
1044 get_index_ref_constraints(Oid indexId
)
1052 /* Search the dependency table for the index */
1053 depRel
= table_open(DependRelationId
, AccessShareLock
);
1055 ScanKeyInit(&key
[0],
1056 Anum_pg_depend_refclassid
,
1057 BTEqualStrategyNumber
, F_OIDEQ
,
1058 ObjectIdGetDatum(RelationRelationId
));
1059 ScanKeyInit(&key
[1],
1060 Anum_pg_depend_refobjid
,
1061 BTEqualStrategyNumber
, F_OIDEQ
,
1062 ObjectIdGetDatum(indexId
));
1063 ScanKeyInit(&key
[2],
1064 Anum_pg_depend_refobjsubid
,
1065 BTEqualStrategyNumber
, F_INT4EQ
,
1068 scan
= systable_beginscan(depRel
, DependReferenceIndexId
, true,
1071 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
1073 Form_pg_depend deprec
= (Form_pg_depend
) GETSTRUCT(tup
);
1076 * We assume any normal dependency from a constraint must be what we
1079 if (deprec
->classid
== ConstraintRelationId
&&
1080 deprec
->objsubid
== 0 &&
1081 deprec
->deptype
== DEPENDENCY_NORMAL
)
1083 result
= lappend_oid(result
, deprec
->objid
);
1087 systable_endscan(scan
);
1088 table_close(depRel
, AccessShareLock
);