1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_depend relation
6 * Portions Copyright (c) 1996-2022, 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 "commands/extension.h"
27 #include "miscadmin.h"
28 #include "utils/fmgroids.h"
29 #include "utils/lsyscache.h"
30 #include "utils/rel.h"
33 static bool isObjectPinned(const ObjectAddress
*object
);
37 * Record a dependency between 2 objects via their respective objectAddress.
38 * The first argument is the dependent object, the second the one it
41 * This simply creates an entry in pg_depend, without any other processing.
44 recordDependencyOn(const ObjectAddress
*depender
,
45 const ObjectAddress
*referenced
,
46 DependencyType behavior
)
48 recordMultipleDependencies(depender
, referenced
, 1, behavior
);
52 * Record multiple dependencies (of the same kind) for a single dependent
53 * object. This has a little less overhead than recording each separately.
56 recordMultipleDependencies(const ObjectAddress
*depender
,
57 const ObjectAddress
*referenced
,
59 DependencyType behavior
)
62 CatalogIndexState indstate
;
63 TupleTableSlot
**slot
;
70 return; /* nothing to do */
73 * During bootstrap, do nothing since pg_depend may not exist yet.
75 * Objects created during bootstrap are most likely pinned, and the few
76 * that are not do not have dependencies on each other, so that there
77 * would be no need to make a pg_depend entry anyway.
79 if (IsBootstrapProcessingMode())
82 dependDesc
= table_open(DependRelationId
, RowExclusiveLock
);
85 * Allocate the slots to use, but delay costly initialization until we
86 * know that they will be used.
88 max_slots
= Min(nreferenced
,
89 MAX_CATALOG_MULTI_INSERT_BYTES
/ sizeof(FormData_pg_depend
));
90 slot
= palloc(sizeof(TupleTableSlot
*) * max_slots
);
92 /* Don't open indexes unless we need to make an update */
95 /* number of slots currently storing tuples */
96 slot_stored_count
= 0;
97 /* number of slots currently initialized */
99 for (i
= 0; i
< nreferenced
; i
++, referenced
++)
102 * If the referenced object is pinned by the system, there's no real
103 * need to record dependencies on it. This saves lots of space in
104 * pg_depend, so it's worth the time taken to check.
106 if (isObjectPinned(referenced
))
109 if (slot_init_count
< max_slots
)
111 slot
[slot_stored_count
] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc
),
116 ExecClearTuple(slot
[slot_stored_count
]);
119 * Record the dependency. Note we don't bother to check for duplicate
120 * dependencies; there's no harm in them.
122 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_refclassid
- 1] = ObjectIdGetDatum(referenced
->classId
);
123 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_refobjid
- 1] = ObjectIdGetDatum(referenced
->objectId
);
124 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_refobjsubid
- 1] = Int32GetDatum(referenced
->objectSubId
);
125 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_deptype
- 1] = CharGetDatum((char) behavior
);
126 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_classid
- 1] = ObjectIdGetDatum(depender
->classId
);
127 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_objid
- 1] = ObjectIdGetDatum(depender
->objectId
);
128 slot
[slot_stored_count
]->tts_values
[Anum_pg_depend_objsubid
- 1] = Int32GetDatum(depender
->objectSubId
);
130 memset(slot
[slot_stored_count
]->tts_isnull
, false,
131 slot
[slot_stored_count
]->tts_tupleDescriptor
->natts
* sizeof(bool));
133 ExecStoreVirtualTuple(slot
[slot_stored_count
]);
136 /* If slots are full, insert a batch of tuples */
137 if (slot_stored_count
== max_slots
)
139 /* fetch index info only when we know we need it */
140 if (indstate
== NULL
)
141 indstate
= CatalogOpenIndexes(dependDesc
);
143 CatalogTuplesMultiInsertWithInfo(dependDesc
, slot
, slot_stored_count
,
145 slot_stored_count
= 0;
149 /* Insert any tuples left in the buffer */
150 if (slot_stored_count
> 0)
152 /* fetch index info only when we know we need it */
153 if (indstate
== NULL
)
154 indstate
= CatalogOpenIndexes(dependDesc
);
156 CatalogTuplesMultiInsertWithInfo(dependDesc
, slot
, slot_stored_count
,
160 if (indstate
!= NULL
)
161 CatalogCloseIndexes(indstate
);
163 table_close(dependDesc
, RowExclusiveLock
);
165 /* Drop only the number of slots used */
166 for (i
= 0; i
< slot_init_count
; i
++)
167 ExecDropSingleTupleTableSlot(slot
[i
]);
172 * If we are executing a CREATE EXTENSION operation, mark the given object
173 * as being a member of the extension. Otherwise, do nothing.
175 * This must be called during creation of any user-definable object type
176 * that could be a member of an extension.
178 * If isReplace is true, the object already existed (or might have already
179 * existed), so we must check for a pre-existing extension membership entry.
180 * Passing false is a guarantee that the object is newly created, and so
181 * could not already be a member of any extension.
183 * Note: isReplace = true is typically used when updating an object in
184 * CREATE OR REPLACE and similar commands. The net effect is that if an
185 * extension script uses such a command on a pre-existing free-standing
186 * object, the object will be absorbed into the extension. If the object
187 * is already a member of some other extension, the command will fail.
188 * This behavior is desirable for cases such as replacing a shell type.
191 recordDependencyOnCurrentExtension(const ObjectAddress
*object
,
194 /* Only whole objects can be extension members */
195 Assert(object
->objectSubId
== 0);
197 if (creating_extension
)
199 ObjectAddress extension
;
201 /* Only need to check for existing membership if isReplace */
206 oldext
= getExtensionOfObject(object
->classId
, object
->objectId
);
207 if (OidIsValid(oldext
))
209 /* If already a member of this extension, nothing to do */
210 if (oldext
== CurrentExtensionObject
)
212 /* Already a member of some other extension, so reject */
214 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
215 errmsg("%s is already a member of extension \"%s\"",
216 getObjectDescription(object
, false),
217 get_extension_name(oldext
))));
221 /* OK, record it as a member of CurrentExtensionObject */
222 extension
.classId
= ExtensionRelationId
;
223 extension
.objectId
= CurrentExtensionObject
;
224 extension
.objectSubId
= 0;
226 recordDependencyOn(object
, &extension
, DEPENDENCY_EXTENSION
);
231 * deleteDependencyRecordsFor -- delete all records with given depender
232 * classId/objectId. Returns the number of records deleted.
234 * This is used when redefining an existing object. Links leading to the
235 * object do not change, and links leading from it will be recreated
236 * (possibly with some differences from before).
238 * If skipExtensionDeps is true, we do not delete any dependencies that
239 * show that the given object is a member of an extension. This avoids
240 * needing a lot of extra logic to fetch and recreate that dependency.
243 deleteDependencyRecordsFor(Oid classId
, Oid objectId
,
244 bool skipExtensionDeps
)
252 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
255 Anum_pg_depend_classid
,
256 BTEqualStrategyNumber
, F_OIDEQ
,
257 ObjectIdGetDatum(classId
));
259 Anum_pg_depend_objid
,
260 BTEqualStrategyNumber
, F_OIDEQ
,
261 ObjectIdGetDatum(objectId
));
263 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
266 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
268 if (skipExtensionDeps
&&
269 ((Form_pg_depend
) GETSTRUCT(tup
))->deptype
== DEPENDENCY_EXTENSION
)
272 CatalogTupleDelete(depRel
, &tup
->t_self
);
276 systable_endscan(scan
);
278 table_close(depRel
, RowExclusiveLock
);
284 * deleteDependencyRecordsForClass -- delete all records with given depender
285 * classId/objectId, dependee classId, and deptype.
286 * Returns the number of records deleted.
288 * This is a variant of deleteDependencyRecordsFor, useful when revoking
289 * an object property that is expressed by a dependency record (such as
290 * extension membership).
293 deleteDependencyRecordsForClass(Oid classId
, Oid objectId
,
294 Oid refclassId
, char deptype
)
302 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
305 Anum_pg_depend_classid
,
306 BTEqualStrategyNumber
, F_OIDEQ
,
307 ObjectIdGetDatum(classId
));
309 Anum_pg_depend_objid
,
310 BTEqualStrategyNumber
, F_OIDEQ
,
311 ObjectIdGetDatum(objectId
));
313 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
316 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
318 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
320 if (depform
->refclassid
== refclassId
&& depform
->deptype
== deptype
)
322 CatalogTupleDelete(depRel
, &tup
->t_self
);
327 systable_endscan(scan
);
329 table_close(depRel
, RowExclusiveLock
);
335 * deleteDependencyRecordsForSpecific -- delete all records with given depender
336 * classId/objectId, dependee classId/objectId, of the given deptype.
337 * Returns the number of records deleted.
340 deleteDependencyRecordsForSpecific(Oid classId
, Oid objectId
, char deptype
,
341 Oid refclassId
, Oid refobjectId
)
349 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
352 Anum_pg_depend_classid
,
353 BTEqualStrategyNumber
, F_OIDEQ
,
354 ObjectIdGetDatum(classId
));
356 Anum_pg_depend_objid
,
357 BTEqualStrategyNumber
, F_OIDEQ
,
358 ObjectIdGetDatum(objectId
));
360 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
363 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
365 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
367 if (depform
->refclassid
== refclassId
&&
368 depform
->refobjid
== refobjectId
&&
369 depform
->deptype
== deptype
)
371 CatalogTupleDelete(depRel
, &tup
->t_self
);
376 systable_endscan(scan
);
378 table_close(depRel
, RowExclusiveLock
);
384 * Adjust dependency record(s) to point to a different object of the same type
386 * classId/objectId specify the referencing object.
387 * refClassId/oldRefObjectId specify the old referenced object.
388 * newRefObjectId is the new referenced object (must be of class refClassId).
390 * Note the lack of objsubid parameters. If there are subobject references
391 * they will all be readjusted. Also, there is an expectation that we are
392 * dealing with NORMAL dependencies: if we have to replace an (implicit)
393 * dependency on a pinned object with an explicit dependency on an unpinned
394 * one, the new one will be NORMAL.
396 * Returns the number of records updated -- zero indicates a problem.
399 changeDependencyFor(Oid classId
, Oid objectId
,
400 Oid refClassId
, Oid oldRefObjectId
,
408 ObjectAddress objAddr
;
409 ObjectAddress depAddr
;
414 * Check to see if either oldRefObjectId or newRefObjectId is pinned.
415 * Pinned objects should not have any dependency entries pointing to them,
416 * so in these cases we should add or remove a pg_depend entry, or do
417 * nothing at all, rather than update an entry as in the normal case.
419 objAddr
.classId
= refClassId
;
420 objAddr
.objectId
= oldRefObjectId
;
421 objAddr
.objectSubId
= 0;
423 oldIsPinned
= isObjectPinned(&objAddr
);
425 objAddr
.objectId
= newRefObjectId
;
427 newIsPinned
= isObjectPinned(&objAddr
);
432 * If both are pinned, we need do nothing. However, return 1 not 0,
433 * else callers will think this is an error case.
439 * There is no old dependency record, but we should insert a new one.
440 * Assume a normal dependency is wanted.
442 depAddr
.classId
= classId
;
443 depAddr
.objectId
= objectId
;
444 depAddr
.objectSubId
= 0;
445 recordDependencyOn(&depAddr
, &objAddr
, DEPENDENCY_NORMAL
);
450 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
452 /* There should be existing dependency record(s), so search. */
454 Anum_pg_depend_classid
,
455 BTEqualStrategyNumber
, F_OIDEQ
,
456 ObjectIdGetDatum(classId
));
458 Anum_pg_depend_objid
,
459 BTEqualStrategyNumber
, F_OIDEQ
,
460 ObjectIdGetDatum(objectId
));
462 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
465 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
467 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
469 if (depform
->refclassid
== refClassId
&&
470 depform
->refobjid
== oldRefObjectId
)
473 CatalogTupleDelete(depRel
, &tup
->t_self
);
476 /* make a modifiable copy */
477 tup
= heap_copytuple(tup
);
478 depform
= (Form_pg_depend
) GETSTRUCT(tup
);
480 depform
->refobjid
= newRefObjectId
;
482 CatalogTupleUpdate(depRel
, &tup
->t_self
, tup
);
491 systable_endscan(scan
);
493 table_close(depRel
, RowExclusiveLock
);
499 * Adjust all dependency records to come from a different object of the same type
501 * classId/oldObjectId specify the old referencing object.
502 * newObjectId is the new referencing object (must be of class classId).
504 * Returns the number of records updated.
507 changeDependenciesOf(Oid classId
, Oid oldObjectId
,
516 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
519 Anum_pg_depend_classid
,
520 BTEqualStrategyNumber
, F_OIDEQ
,
521 ObjectIdGetDatum(classId
));
523 Anum_pg_depend_objid
,
524 BTEqualStrategyNumber
, F_OIDEQ
,
525 ObjectIdGetDatum(oldObjectId
));
527 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
530 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
532 Form_pg_depend depform
;
534 /* make a modifiable copy */
535 tup
= heap_copytuple(tup
);
536 depform
= (Form_pg_depend
) GETSTRUCT(tup
);
538 depform
->objid
= newObjectId
;
540 CatalogTupleUpdate(depRel
, &tup
->t_self
, tup
);
547 systable_endscan(scan
);
549 table_close(depRel
, RowExclusiveLock
);
555 * Adjust all dependency records to point to a different object of the same type
557 * refClassId/oldRefObjectId specify the old referenced object.
558 * newRefObjectId is the new referenced object (must be of class refClassId).
560 * Returns the number of records updated.
563 changeDependenciesOn(Oid refClassId
, Oid oldRefObjectId
,
571 ObjectAddress objAddr
;
574 depRel
= table_open(DependRelationId
, RowExclusiveLock
);
577 * If oldRefObjectId is pinned, there won't be any dependency entries on
578 * it --- we can't cope in that case. (This isn't really worth expending
579 * code to fix, in current usage; it just means you can't rename stuff out
580 * of pg_catalog, which would likely be a bad move anyway.)
582 objAddr
.classId
= refClassId
;
583 objAddr
.objectId
= oldRefObjectId
;
584 objAddr
.objectSubId
= 0;
586 if (isObjectPinned(&objAddr
))
588 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
589 errmsg("cannot remove dependency on %s because it is a system object",
590 getObjectDescription(&objAddr
, false))));
593 * We can handle adding a dependency on something pinned, though, since
594 * that just means deleting the dependency entry.
596 objAddr
.objectId
= newRefObjectId
;
598 newIsPinned
= isObjectPinned(&objAddr
);
600 /* Now search for dependency records */
602 Anum_pg_depend_refclassid
,
603 BTEqualStrategyNumber
, F_OIDEQ
,
604 ObjectIdGetDatum(refClassId
));
606 Anum_pg_depend_refobjid
,
607 BTEqualStrategyNumber
, F_OIDEQ
,
608 ObjectIdGetDatum(oldRefObjectId
));
610 scan
= systable_beginscan(depRel
, DependReferenceIndexId
, true,
613 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
616 CatalogTupleDelete(depRel
, &tup
->t_self
);
619 Form_pg_depend depform
;
621 /* make a modifiable copy */
622 tup
= heap_copytuple(tup
);
623 depform
= (Form_pg_depend
) GETSTRUCT(tup
);
625 depform
->refobjid
= newRefObjectId
;
627 CatalogTupleUpdate(depRel
, &tup
->t_self
, tup
);
635 systable_endscan(scan
);
637 table_close(depRel
, RowExclusiveLock
);
645 * Test if an object is required for basic database functionality.
647 * The passed subId, if any, is ignored; we assume that only whole objects
648 * are pinned (and that this implies pinning their components).
651 isObjectPinned(const ObjectAddress
*object
)
653 return IsPinnedObject(object
->classId
, object
->objectId
);
658 * Various special-purpose lookups and manipulations of pg_depend.
663 * Find the extension containing the specified object, if any
665 * Returns the OID of the extension, or InvalidOid if the object does not
666 * belong to any extension.
668 * Extension membership is marked by an EXTENSION dependency from the object
669 * to the extension. Note that the result will be indeterminate if pg_depend
670 * contains links from this object to more than one extension ... but that
671 * should never happen.
674 getExtensionOfObject(Oid classId
, Oid objectId
)
676 Oid result
= InvalidOid
;
682 depRel
= table_open(DependRelationId
, AccessShareLock
);
685 Anum_pg_depend_classid
,
686 BTEqualStrategyNumber
, F_OIDEQ
,
687 ObjectIdGetDatum(classId
));
689 Anum_pg_depend_objid
,
690 BTEqualStrategyNumber
, F_OIDEQ
,
691 ObjectIdGetDatum(objectId
));
693 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
696 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
698 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
700 if (depform
->refclassid
== ExtensionRelationId
&&
701 depform
->deptype
== DEPENDENCY_EXTENSION
)
703 result
= depform
->refobjid
;
704 break; /* no need to keep scanning */
708 systable_endscan(scan
);
710 table_close(depRel
, AccessShareLock
);
716 * Return (possibly NIL) list of extensions that the given object depends on
717 * in DEPENDENCY_AUTO_EXTENSION mode.
720 getAutoExtensionsOfObject(Oid classId
, Oid objectId
)
728 depRel
= table_open(DependRelationId
, AccessShareLock
);
731 Anum_pg_depend_classid
,
732 BTEqualStrategyNumber
, F_OIDEQ
,
733 ObjectIdGetDatum(classId
));
735 Anum_pg_depend_objid
,
736 BTEqualStrategyNumber
, F_OIDEQ
,
737 ObjectIdGetDatum(objectId
));
739 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
742 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
744 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
746 if (depform
->refclassid
== ExtensionRelationId
&&
747 depform
->deptype
== DEPENDENCY_AUTO_EXTENSION
)
748 result
= lappend_oid(result
, depform
->refobjid
);
751 systable_endscan(scan
);
753 table_close(depRel
, AccessShareLock
);
759 * Detect whether a sequence is marked as "owned" by a column
761 * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
762 * column. If we find one, store the identity of the owning column
763 * into *tableId and *colId and return true; else return false.
765 * Note: if there's more than one such pg_depend entry then you get
766 * a random one of them returned into the out parameters. This should
767 * not happen, though.
770 sequenceIsOwned(Oid seqId
, char deptype
, Oid
*tableId
, int32
*colId
)
778 depRel
= table_open(DependRelationId
, AccessShareLock
);
781 Anum_pg_depend_classid
,
782 BTEqualStrategyNumber
, F_OIDEQ
,
783 ObjectIdGetDatum(RelationRelationId
));
785 Anum_pg_depend_objid
,
786 BTEqualStrategyNumber
, F_OIDEQ
,
787 ObjectIdGetDatum(seqId
));
789 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
792 while (HeapTupleIsValid((tup
= systable_getnext(scan
))))
794 Form_pg_depend depform
= (Form_pg_depend
) GETSTRUCT(tup
);
796 if (depform
->refclassid
== RelationRelationId
&&
797 depform
->deptype
== deptype
)
799 *tableId
= depform
->refobjid
;
800 *colId
= depform
->refobjsubid
;
802 break; /* no need to keep scanning */
806 systable_endscan(scan
);
808 table_close(depRel
, AccessShareLock
);
814 * Collect a list of OIDs of all sequences owned by the specified relation,
815 * and column if specified. If deptype is not zero, then only find sequences
816 * with the specified dependency type.
819 getOwnedSequences_internal(Oid relid
, AttrNumber attnum
, char deptype
)
827 depRel
= table_open(DependRelationId
, AccessShareLock
);
830 Anum_pg_depend_refclassid
,
831 BTEqualStrategyNumber
, F_OIDEQ
,
832 ObjectIdGetDatum(RelationRelationId
));
834 Anum_pg_depend_refobjid
,
835 BTEqualStrategyNumber
, F_OIDEQ
,
836 ObjectIdGetDatum(relid
));
839 Anum_pg_depend_refobjsubid
,
840 BTEqualStrategyNumber
, F_INT4EQ
,
841 Int32GetDatum(attnum
));
843 scan
= systable_beginscan(depRel
, DependReferenceIndexId
, true,
844 NULL
, attnum
? 3 : 2, key
);
846 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
848 Form_pg_depend deprec
= (Form_pg_depend
) GETSTRUCT(tup
);
851 * We assume any auto or internal dependency of a sequence on a column
852 * must be what we are looking for. (We need the relkind test because
853 * indexes can also have auto dependencies on columns.)
855 if (deprec
->classid
== RelationRelationId
&&
856 deprec
->objsubid
== 0 &&
857 deprec
->refobjsubid
!= 0 &&
858 (deprec
->deptype
== DEPENDENCY_AUTO
|| deprec
->deptype
== DEPENDENCY_INTERNAL
) &&
859 get_rel_relkind(deprec
->objid
) == RELKIND_SEQUENCE
)
861 if (!deptype
|| deprec
->deptype
== deptype
)
862 result
= lappend_oid(result
, deprec
->objid
);
866 systable_endscan(scan
);
868 table_close(depRel
, AccessShareLock
);
874 * Collect a list of OIDs of all sequences owned (identity or serial) by the
875 * specified relation.
878 getOwnedSequences(Oid relid
)
880 return getOwnedSequences_internal(relid
, 0, 0);
884 * Get owned identity sequence, error if not exactly one.
887 getIdentitySequence(Oid relid
, AttrNumber attnum
, bool missing_ok
)
889 List
*seqlist
= getOwnedSequences_internal(relid
, attnum
, DEPENDENCY_INTERNAL
);
891 if (list_length(seqlist
) > 1)
892 elog(ERROR
, "more than one owned sequence found");
893 else if (list_length(seqlist
) < 1)
898 elog(ERROR
, "no owned sequence found");
901 return linitial_oid(seqlist
);
905 * get_index_constraint
906 * Given the OID of an index, return the OID of the owning unique,
907 * primary-key, or exclusion constraint, or InvalidOid if there
908 * is no owning constraint.
911 get_index_constraint(Oid indexId
)
913 Oid constraintId
= InvalidOid
;
919 /* Search the dependency table for the index */
920 depRel
= table_open(DependRelationId
, AccessShareLock
);
923 Anum_pg_depend_classid
,
924 BTEqualStrategyNumber
, F_OIDEQ
,
925 ObjectIdGetDatum(RelationRelationId
));
927 Anum_pg_depend_objid
,
928 BTEqualStrategyNumber
, F_OIDEQ
,
929 ObjectIdGetDatum(indexId
));
931 Anum_pg_depend_objsubid
,
932 BTEqualStrategyNumber
, F_INT4EQ
,
935 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
938 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
940 Form_pg_depend deprec
= (Form_pg_depend
) GETSTRUCT(tup
);
943 * We assume any internal dependency on a constraint must be what we
946 if (deprec
->refclassid
== ConstraintRelationId
&&
947 deprec
->refobjsubid
== 0 &&
948 deprec
->deptype
== DEPENDENCY_INTERNAL
)
950 constraintId
= deprec
->refobjid
;
955 systable_endscan(scan
);
956 table_close(depRel
, AccessShareLock
);
962 * get_index_ref_constraints
963 * Given the OID of an index, return the OID of all foreign key
964 * constraints which reference the index.
967 get_index_ref_constraints(Oid indexId
)
975 /* Search the dependency table for the index */
976 depRel
= table_open(DependRelationId
, AccessShareLock
);
979 Anum_pg_depend_refclassid
,
980 BTEqualStrategyNumber
, F_OIDEQ
,
981 ObjectIdGetDatum(RelationRelationId
));
983 Anum_pg_depend_refobjid
,
984 BTEqualStrategyNumber
, F_OIDEQ
,
985 ObjectIdGetDatum(indexId
));
987 Anum_pg_depend_refobjsubid
,
988 BTEqualStrategyNumber
, F_INT4EQ
,
991 scan
= systable_beginscan(depRel
, DependReferenceIndexId
, true,
994 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
996 Form_pg_depend deprec
= (Form_pg_depend
) GETSTRUCT(tup
);
999 * We assume any normal dependency from a constraint must be what we
1002 if (deprec
->classid
== ConstraintRelationId
&&
1003 deprec
->objsubid
== 0 &&
1004 deprec
->deptype
== DEPENDENCY_NORMAL
)
1006 result
= lappend_oid(result
, deprec
->objid
);
1010 systable_endscan(scan
);
1011 table_close(depRel
, AccessShareLock
);