Update copyright for 2022
[pgsql.git] / src / backend / catalog / pg_depend.c
blobe86e5e689823493d31f8614bb5ad1870a8a80dcd
1 /*-------------------------------------------------------------------------
3 * pg_depend.c
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
10 * IDENTIFICATION
11 * src/backend/catalog/pg_depend.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
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
39 * references.
41 * This simply creates an entry in pg_depend, without any other processing.
43 void
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.
55 void
56 recordMultipleDependencies(const ObjectAddress *depender,
57 const ObjectAddress *referenced,
58 int nreferenced,
59 DependencyType behavior)
61 Relation dependDesc;
62 CatalogIndexState indstate;
63 TupleTableSlot **slot;
64 int i,
65 max_slots,
66 slot_init_count,
67 slot_stored_count;
69 if (nreferenced <= 0)
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())
80 return;
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 */
93 indstate = NULL;
95 /* number of slots currently storing tuples */
96 slot_stored_count = 0;
97 /* number of slots currently initialized */
98 slot_init_count = 0;
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))
107 continue;
109 if (slot_init_count < max_slots)
111 slot[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc),
112 &TTSOpsHeapTuple);
113 slot_init_count++;
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]);
134 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,
144 indstate);
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,
157 indstate);
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]);
168 pfree(slot);
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.
190 void
191 recordDependencyOnCurrentExtension(const ObjectAddress *object,
192 bool isReplace)
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 */
202 if (isReplace)
204 Oid oldext;
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)
211 return;
212 /* Already a member of some other extension, so reject */
213 ereport(ERROR,
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.
242 long
243 deleteDependencyRecordsFor(Oid classId, Oid objectId,
244 bool skipExtensionDeps)
246 long count = 0;
247 Relation depRel;
248 ScanKeyData key[2];
249 SysScanDesc scan;
250 HeapTuple tup;
252 depRel = table_open(DependRelationId, RowExclusiveLock);
254 ScanKeyInit(&key[0],
255 Anum_pg_depend_classid,
256 BTEqualStrategyNumber, F_OIDEQ,
257 ObjectIdGetDatum(classId));
258 ScanKeyInit(&key[1],
259 Anum_pg_depend_objid,
260 BTEqualStrategyNumber, F_OIDEQ,
261 ObjectIdGetDatum(objectId));
263 scan = systable_beginscan(depRel, DependDependerIndexId, true,
264 NULL, 2, key);
266 while (HeapTupleIsValid(tup = systable_getnext(scan)))
268 if (skipExtensionDeps &&
269 ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
270 continue;
272 CatalogTupleDelete(depRel, &tup->t_self);
273 count++;
276 systable_endscan(scan);
278 table_close(depRel, RowExclusiveLock);
280 return count;
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).
292 long
293 deleteDependencyRecordsForClass(Oid classId, Oid objectId,
294 Oid refclassId, char deptype)
296 long count = 0;
297 Relation depRel;
298 ScanKeyData key[2];
299 SysScanDesc scan;
300 HeapTuple tup;
302 depRel = table_open(DependRelationId, RowExclusiveLock);
304 ScanKeyInit(&key[0],
305 Anum_pg_depend_classid,
306 BTEqualStrategyNumber, F_OIDEQ,
307 ObjectIdGetDatum(classId));
308 ScanKeyInit(&key[1],
309 Anum_pg_depend_objid,
310 BTEqualStrategyNumber, F_OIDEQ,
311 ObjectIdGetDatum(objectId));
313 scan = systable_beginscan(depRel, DependDependerIndexId, true,
314 NULL, 2, key);
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);
323 count++;
327 systable_endscan(scan);
329 table_close(depRel, RowExclusiveLock);
331 return count;
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.
339 long
340 deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
341 Oid refclassId, Oid refobjectId)
343 long count = 0;
344 Relation depRel;
345 ScanKeyData key[2];
346 SysScanDesc scan;
347 HeapTuple tup;
349 depRel = table_open(DependRelationId, RowExclusiveLock);
351 ScanKeyInit(&key[0],
352 Anum_pg_depend_classid,
353 BTEqualStrategyNumber, F_OIDEQ,
354 ObjectIdGetDatum(classId));
355 ScanKeyInit(&key[1],
356 Anum_pg_depend_objid,
357 BTEqualStrategyNumber, F_OIDEQ,
358 ObjectIdGetDatum(objectId));
360 scan = systable_beginscan(depRel, DependDependerIndexId, true,
361 NULL, 2, key);
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);
372 count++;
376 systable_endscan(scan);
378 table_close(depRel, RowExclusiveLock);
380 return count;
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.
398 long
399 changeDependencyFor(Oid classId, Oid objectId,
400 Oid refClassId, Oid oldRefObjectId,
401 Oid newRefObjectId)
403 long count = 0;
404 Relation depRel;
405 ScanKeyData key[2];
406 SysScanDesc scan;
407 HeapTuple tup;
408 ObjectAddress objAddr;
409 ObjectAddress depAddr;
410 bool oldIsPinned;
411 bool newIsPinned;
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);
429 if (oldIsPinned)
432 * If both are pinned, we need do nothing. However, return 1 not 0,
433 * else callers will think this is an error case.
435 if (newIsPinned)
436 return 1;
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);
447 return 1;
450 depRel = table_open(DependRelationId, RowExclusiveLock);
452 /* There should be existing dependency record(s), so search. */
453 ScanKeyInit(&key[0],
454 Anum_pg_depend_classid,
455 BTEqualStrategyNumber, F_OIDEQ,
456 ObjectIdGetDatum(classId));
457 ScanKeyInit(&key[1],
458 Anum_pg_depend_objid,
459 BTEqualStrategyNumber, F_OIDEQ,
460 ObjectIdGetDatum(objectId));
462 scan = systable_beginscan(depRel, DependDependerIndexId, true,
463 NULL, 2, key);
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)
472 if (newIsPinned)
473 CatalogTupleDelete(depRel, &tup->t_self);
474 else
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);
484 heap_freetuple(tup);
487 count++;
491 systable_endscan(scan);
493 table_close(depRel, RowExclusiveLock);
495 return count;
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.
506 long
507 changeDependenciesOf(Oid classId, Oid oldObjectId,
508 Oid newObjectId)
510 long count = 0;
511 Relation depRel;
512 ScanKeyData key[2];
513 SysScanDesc scan;
514 HeapTuple tup;
516 depRel = table_open(DependRelationId, RowExclusiveLock);
518 ScanKeyInit(&key[0],
519 Anum_pg_depend_classid,
520 BTEqualStrategyNumber, F_OIDEQ,
521 ObjectIdGetDatum(classId));
522 ScanKeyInit(&key[1],
523 Anum_pg_depend_objid,
524 BTEqualStrategyNumber, F_OIDEQ,
525 ObjectIdGetDatum(oldObjectId));
527 scan = systable_beginscan(depRel, DependDependerIndexId, true,
528 NULL, 2, key);
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);
542 heap_freetuple(tup);
544 count++;
547 systable_endscan(scan);
549 table_close(depRel, RowExclusiveLock);
551 return count;
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.
562 long
563 changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
564 Oid newRefObjectId)
566 long count = 0;
567 Relation depRel;
568 ScanKeyData key[2];
569 SysScanDesc scan;
570 HeapTuple tup;
571 ObjectAddress objAddr;
572 bool newIsPinned;
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))
587 ereport(ERROR,
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 */
601 ScanKeyInit(&key[0],
602 Anum_pg_depend_refclassid,
603 BTEqualStrategyNumber, F_OIDEQ,
604 ObjectIdGetDatum(refClassId));
605 ScanKeyInit(&key[1],
606 Anum_pg_depend_refobjid,
607 BTEqualStrategyNumber, F_OIDEQ,
608 ObjectIdGetDatum(oldRefObjectId));
610 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
611 NULL, 2, key);
613 while (HeapTupleIsValid((tup = systable_getnext(scan))))
615 if (newIsPinned)
616 CatalogTupleDelete(depRel, &tup->t_self);
617 else
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);
629 heap_freetuple(tup);
632 count++;
635 systable_endscan(scan);
637 table_close(depRel, RowExclusiveLock);
639 return count;
643 * isObjectPinned()
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).
650 static bool
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;
677 Relation depRel;
678 ScanKeyData key[2];
679 SysScanDesc scan;
680 HeapTuple tup;
682 depRel = table_open(DependRelationId, AccessShareLock);
684 ScanKeyInit(&key[0],
685 Anum_pg_depend_classid,
686 BTEqualStrategyNumber, F_OIDEQ,
687 ObjectIdGetDatum(classId));
688 ScanKeyInit(&key[1],
689 Anum_pg_depend_objid,
690 BTEqualStrategyNumber, F_OIDEQ,
691 ObjectIdGetDatum(objectId));
693 scan = systable_beginscan(depRel, DependDependerIndexId, true,
694 NULL, 2, key);
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);
712 return result;
716 * Return (possibly NIL) list of extensions that the given object depends on
717 * in DEPENDENCY_AUTO_EXTENSION mode.
719 List *
720 getAutoExtensionsOfObject(Oid classId, Oid objectId)
722 List *result = NIL;
723 Relation depRel;
724 ScanKeyData key[2];
725 SysScanDesc scan;
726 HeapTuple tup;
728 depRel = table_open(DependRelationId, AccessShareLock);
730 ScanKeyInit(&key[0],
731 Anum_pg_depend_classid,
732 BTEqualStrategyNumber, F_OIDEQ,
733 ObjectIdGetDatum(classId));
734 ScanKeyInit(&key[1],
735 Anum_pg_depend_objid,
736 BTEqualStrategyNumber, F_OIDEQ,
737 ObjectIdGetDatum(objectId));
739 scan = systable_beginscan(depRel, DependDependerIndexId, true,
740 NULL, 2, key);
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);
755 return result;
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.
769 bool
770 sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
772 bool ret = false;
773 Relation depRel;
774 ScanKeyData key[2];
775 SysScanDesc scan;
776 HeapTuple tup;
778 depRel = table_open(DependRelationId, AccessShareLock);
780 ScanKeyInit(&key[0],
781 Anum_pg_depend_classid,
782 BTEqualStrategyNumber, F_OIDEQ,
783 ObjectIdGetDatum(RelationRelationId));
784 ScanKeyInit(&key[1],
785 Anum_pg_depend_objid,
786 BTEqualStrategyNumber, F_OIDEQ,
787 ObjectIdGetDatum(seqId));
789 scan = systable_beginscan(depRel, DependDependerIndexId, true,
790 NULL, 2, key);
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;
801 ret = true;
802 break; /* no need to keep scanning */
806 systable_endscan(scan);
808 table_close(depRel, AccessShareLock);
810 return ret;
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.
818 static List *
819 getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
821 List *result = NIL;
822 Relation depRel;
823 ScanKeyData key[3];
824 SysScanDesc scan;
825 HeapTuple tup;
827 depRel = table_open(DependRelationId, AccessShareLock);
829 ScanKeyInit(&key[0],
830 Anum_pg_depend_refclassid,
831 BTEqualStrategyNumber, F_OIDEQ,
832 ObjectIdGetDatum(RelationRelationId));
833 ScanKeyInit(&key[1],
834 Anum_pg_depend_refobjid,
835 BTEqualStrategyNumber, F_OIDEQ,
836 ObjectIdGetDatum(relid));
837 if (attnum)
838 ScanKeyInit(&key[2],
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);
870 return result;
874 * Collect a list of OIDs of all sequences owned (identity or serial) by the
875 * specified relation.
877 List *
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)
895 if (missing_ok)
896 return InvalidOid;
897 else
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;
914 Relation depRel;
915 ScanKeyData key[3];
916 SysScanDesc scan;
917 HeapTuple tup;
919 /* Search the dependency table for the index */
920 depRel = table_open(DependRelationId, AccessShareLock);
922 ScanKeyInit(&key[0],
923 Anum_pg_depend_classid,
924 BTEqualStrategyNumber, F_OIDEQ,
925 ObjectIdGetDatum(RelationRelationId));
926 ScanKeyInit(&key[1],
927 Anum_pg_depend_objid,
928 BTEqualStrategyNumber, F_OIDEQ,
929 ObjectIdGetDatum(indexId));
930 ScanKeyInit(&key[2],
931 Anum_pg_depend_objsubid,
932 BTEqualStrategyNumber, F_INT4EQ,
933 Int32GetDatum(0));
935 scan = systable_beginscan(depRel, DependDependerIndexId, true,
936 NULL, 3, key);
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
944 * are looking for.
946 if (deprec->refclassid == ConstraintRelationId &&
947 deprec->refobjsubid == 0 &&
948 deprec->deptype == DEPENDENCY_INTERNAL)
950 constraintId = deprec->refobjid;
951 break;
955 systable_endscan(scan);
956 table_close(depRel, AccessShareLock);
958 return constraintId;
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.
966 List *
967 get_index_ref_constraints(Oid indexId)
969 List *result = NIL;
970 Relation depRel;
971 ScanKeyData key[3];
972 SysScanDesc scan;
973 HeapTuple tup;
975 /* Search the dependency table for the index */
976 depRel = table_open(DependRelationId, AccessShareLock);
978 ScanKeyInit(&key[0],
979 Anum_pg_depend_refclassid,
980 BTEqualStrategyNumber, F_OIDEQ,
981 ObjectIdGetDatum(RelationRelationId));
982 ScanKeyInit(&key[1],
983 Anum_pg_depend_refobjid,
984 BTEqualStrategyNumber, F_OIDEQ,
985 ObjectIdGetDatum(indexId));
986 ScanKeyInit(&key[2],
987 Anum_pg_depend_refobjsubid,
988 BTEqualStrategyNumber, F_INT4EQ,
989 Int32GetDatum(0));
991 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
992 NULL, 3, key);
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
1000 * are looking for.
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);
1013 return result;