Fix a memory leak in dumping functions with TRANSFORMs
[pgsql.git] / src / backend / catalog / pg_depend.c
blob2b4514e8a3590adf7aa983fc7804467ca8409e1e
1 /*-------------------------------------------------------------------------
3 * pg_depend.c
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
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 "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
40 * references.
42 * This simply creates an entry in pg_depend, without any other processing.
44 void
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.
56 void
57 recordMultipleDependencies(const ObjectAddress *depender,
58 const ObjectAddress *referenced,
59 int nreferenced,
60 DependencyType behavior)
62 Relation dependDesc;
63 CatalogIndexState indstate;
64 TupleTableSlot **slot;
65 int i,
66 max_slots,
67 slot_init_count,
68 slot_stored_count;
70 if (nreferenced <= 0)
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())
81 return;
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 */
94 indstate = NULL;
96 /* number of slots currently storing tuples */
97 slot_stored_count = 0;
98 /* number of slots currently initialized */
99 slot_init_count = 0;
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))
108 continue;
110 if (slot_init_count < max_slots)
112 slot[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc),
113 &TTSOpsHeapTuple);
114 slot_init_count++;
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]);
135 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,
145 indstate);
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,
158 indstate);
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]);
169 pfree(slot);
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).
192 void
193 recordDependencyOnCurrentExtension(const ObjectAddress *object,
194 bool isReplace)
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 */
204 if (isReplace)
206 Oid oldext;
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)
219 return;
220 /* Already a member of some other extension, so reject */
221 ereport(ERROR,
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 */
228 ereport(ERROR,
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
255 * properties.
257 void
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)
272 Oid oldext;
274 oldext = getExtensionOfObject(object->classId, object->objectId);
275 /* If already a member of this extension, OK */
276 if (oldext == CurrentExtensionObject)
277 return;
278 /* Else complain */
279 ereport(ERROR,
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.
300 long
301 deleteDependencyRecordsFor(Oid classId, Oid objectId,
302 bool skipExtensionDeps)
304 long count = 0;
305 Relation depRel;
306 ScanKeyData key[2];
307 SysScanDesc scan;
308 HeapTuple tup;
310 depRel = table_open(DependRelationId, RowExclusiveLock);
312 ScanKeyInit(&key[0],
313 Anum_pg_depend_classid,
314 BTEqualStrategyNumber, F_OIDEQ,
315 ObjectIdGetDatum(classId));
316 ScanKeyInit(&key[1],
317 Anum_pg_depend_objid,
318 BTEqualStrategyNumber, F_OIDEQ,
319 ObjectIdGetDatum(objectId));
321 scan = systable_beginscan(depRel, DependDependerIndexId, true,
322 NULL, 2, key);
324 while (HeapTupleIsValid(tup = systable_getnext(scan)))
326 if (skipExtensionDeps &&
327 ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
328 continue;
330 CatalogTupleDelete(depRel, &tup->t_self);
331 count++;
334 systable_endscan(scan);
336 table_close(depRel, RowExclusiveLock);
338 return count;
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).
350 long
351 deleteDependencyRecordsForClass(Oid classId, Oid objectId,
352 Oid refclassId, char deptype)
354 long count = 0;
355 Relation depRel;
356 ScanKeyData key[2];
357 SysScanDesc scan;
358 HeapTuple tup;
360 depRel = table_open(DependRelationId, RowExclusiveLock);
362 ScanKeyInit(&key[0],
363 Anum_pg_depend_classid,
364 BTEqualStrategyNumber, F_OIDEQ,
365 ObjectIdGetDatum(classId));
366 ScanKeyInit(&key[1],
367 Anum_pg_depend_objid,
368 BTEqualStrategyNumber, F_OIDEQ,
369 ObjectIdGetDatum(objectId));
371 scan = systable_beginscan(depRel, DependDependerIndexId, true,
372 NULL, 2, key);
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);
381 count++;
385 systable_endscan(scan);
387 table_close(depRel, RowExclusiveLock);
389 return count;
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.
397 long
398 deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
399 Oid refclassId, Oid refobjectId)
401 long count = 0;
402 Relation depRel;
403 ScanKeyData key[2];
404 SysScanDesc scan;
405 HeapTuple tup;
407 depRel = table_open(DependRelationId, RowExclusiveLock);
409 ScanKeyInit(&key[0],
410 Anum_pg_depend_classid,
411 BTEqualStrategyNumber, F_OIDEQ,
412 ObjectIdGetDatum(classId));
413 ScanKeyInit(&key[1],
414 Anum_pg_depend_objid,
415 BTEqualStrategyNumber, F_OIDEQ,
416 ObjectIdGetDatum(objectId));
418 scan = systable_beginscan(depRel, DependDependerIndexId, true,
419 NULL, 2, key);
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);
430 count++;
434 systable_endscan(scan);
436 table_close(depRel, RowExclusiveLock);
438 return count;
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.
456 long
457 changeDependencyFor(Oid classId, Oid objectId,
458 Oid refClassId, Oid oldRefObjectId,
459 Oid newRefObjectId)
461 long count = 0;
462 Relation depRel;
463 ScanKeyData key[2];
464 SysScanDesc scan;
465 HeapTuple tup;
466 ObjectAddress objAddr;
467 ObjectAddress depAddr;
468 bool oldIsPinned;
469 bool newIsPinned;
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);
487 if (oldIsPinned)
490 * If both are pinned, we need do nothing. However, return 1 not 0,
491 * else callers will think this is an error case.
493 if (newIsPinned)
494 return 1;
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);
505 return 1;
508 depRel = table_open(DependRelationId, RowExclusiveLock);
510 /* There should be existing dependency record(s), so search. */
511 ScanKeyInit(&key[0],
512 Anum_pg_depend_classid,
513 BTEqualStrategyNumber, F_OIDEQ,
514 ObjectIdGetDatum(classId));
515 ScanKeyInit(&key[1],
516 Anum_pg_depend_objid,
517 BTEqualStrategyNumber, F_OIDEQ,
518 ObjectIdGetDatum(objectId));
520 scan = systable_beginscan(depRel, DependDependerIndexId, true,
521 NULL, 2, key);
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)
530 if (newIsPinned)
531 CatalogTupleDelete(depRel, &tup->t_self);
532 else
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);
542 heap_freetuple(tup);
545 count++;
549 systable_endscan(scan);
551 table_close(depRel, RowExclusiveLock);
553 return count;
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.
564 long
565 changeDependenciesOf(Oid classId, Oid oldObjectId,
566 Oid newObjectId)
568 long count = 0;
569 Relation depRel;
570 ScanKeyData key[2];
571 SysScanDesc scan;
572 HeapTuple tup;
574 depRel = table_open(DependRelationId, RowExclusiveLock);
576 ScanKeyInit(&key[0],
577 Anum_pg_depend_classid,
578 BTEqualStrategyNumber, F_OIDEQ,
579 ObjectIdGetDatum(classId));
580 ScanKeyInit(&key[1],
581 Anum_pg_depend_objid,
582 BTEqualStrategyNumber, F_OIDEQ,
583 ObjectIdGetDatum(oldObjectId));
585 scan = systable_beginscan(depRel, DependDependerIndexId, true,
586 NULL, 2, key);
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);
600 heap_freetuple(tup);
602 count++;
605 systable_endscan(scan);
607 table_close(depRel, RowExclusiveLock);
609 return count;
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.
620 long
621 changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
622 Oid newRefObjectId)
624 long count = 0;
625 Relation depRel;
626 ScanKeyData key[2];
627 SysScanDesc scan;
628 HeapTuple tup;
629 ObjectAddress objAddr;
630 bool newIsPinned;
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))
645 ereport(ERROR,
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 */
659 ScanKeyInit(&key[0],
660 Anum_pg_depend_refclassid,
661 BTEqualStrategyNumber, F_OIDEQ,
662 ObjectIdGetDatum(refClassId));
663 ScanKeyInit(&key[1],
664 Anum_pg_depend_refobjid,
665 BTEqualStrategyNumber, F_OIDEQ,
666 ObjectIdGetDatum(oldRefObjectId));
668 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
669 NULL, 2, key);
671 while (HeapTupleIsValid((tup = systable_getnext(scan))))
673 if (newIsPinned)
674 CatalogTupleDelete(depRel, &tup->t_self);
675 else
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);
687 heap_freetuple(tup);
690 count++;
693 systable_endscan(scan);
695 table_close(depRel, RowExclusiveLock);
697 return count;
701 * isObjectPinned()
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).
708 static bool
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;
735 Relation depRel;
736 ScanKeyData key[2];
737 SysScanDesc scan;
738 HeapTuple tup;
740 depRel = table_open(DependRelationId, AccessShareLock);
742 ScanKeyInit(&key[0],
743 Anum_pg_depend_classid,
744 BTEqualStrategyNumber, F_OIDEQ,
745 ObjectIdGetDatum(classId));
746 ScanKeyInit(&key[1],
747 Anum_pg_depend_objid,
748 BTEqualStrategyNumber, F_OIDEQ,
749 ObjectIdGetDatum(objectId));
751 scan = systable_beginscan(depRel, DependDependerIndexId, true,
752 NULL, 2, key);
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);
770 return result;
774 * Return (possibly NIL) list of extensions that the given object depends on
775 * in DEPENDENCY_AUTO_EXTENSION mode.
777 List *
778 getAutoExtensionsOfObject(Oid classId, Oid objectId)
780 List *result = NIL;
781 Relation depRel;
782 ScanKeyData key[2];
783 SysScanDesc scan;
784 HeapTuple tup;
786 depRel = table_open(DependRelationId, AccessShareLock);
788 ScanKeyInit(&key[0],
789 Anum_pg_depend_classid,
790 BTEqualStrategyNumber, F_OIDEQ,
791 ObjectIdGetDatum(classId));
792 ScanKeyInit(&key[1],
793 Anum_pg_depend_objid,
794 BTEqualStrategyNumber, F_OIDEQ,
795 ObjectIdGetDatum(objectId));
797 scan = systable_beginscan(depRel, DependDependerIndexId, true,
798 NULL, 2, key);
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);
813 return result;
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.
827 bool
828 sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
830 bool ret = false;
831 Relation depRel;
832 ScanKeyData key[2];
833 SysScanDesc scan;
834 HeapTuple tup;
836 depRel = table_open(DependRelationId, AccessShareLock);
838 ScanKeyInit(&key[0],
839 Anum_pg_depend_classid,
840 BTEqualStrategyNumber, F_OIDEQ,
841 ObjectIdGetDatum(RelationRelationId));
842 ScanKeyInit(&key[1],
843 Anum_pg_depend_objid,
844 BTEqualStrategyNumber, F_OIDEQ,
845 ObjectIdGetDatum(seqId));
847 scan = systable_beginscan(depRel, DependDependerIndexId, true,
848 NULL, 2, key);
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;
859 ret = true;
860 break; /* no need to keep scanning */
864 systable_endscan(scan);
866 table_close(depRel, AccessShareLock);
868 return ret;
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.
876 static List *
877 getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
879 List *result = NIL;
880 Relation depRel;
881 ScanKeyData key[3];
882 SysScanDesc scan;
883 HeapTuple tup;
885 depRel = table_open(DependRelationId, AccessShareLock);
887 ScanKeyInit(&key[0],
888 Anum_pg_depend_refclassid,
889 BTEqualStrategyNumber, F_OIDEQ,
890 ObjectIdGetDatum(RelationRelationId));
891 ScanKeyInit(&key[1],
892 Anum_pg_depend_refobjid,
893 BTEqualStrategyNumber, F_OIDEQ,
894 ObjectIdGetDatum(relid));
895 if (attnum)
896 ScanKeyInit(&key[2],
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);
928 return result;
932 * Collect a list of OIDs of all sequences owned (identity or serial) by the
933 * specified relation.
935 List *
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);
948 List *seqlist;
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",
963 attname, relid);
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)
972 if (missing_ok)
973 return InvalidOid;
974 else
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;
991 Relation depRel;
992 ScanKeyData key[3];
993 SysScanDesc scan;
994 HeapTuple tup;
996 /* Search the dependency table for the index */
997 depRel = table_open(DependRelationId, AccessShareLock);
999 ScanKeyInit(&key[0],
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,
1010 Int32GetDatum(0));
1012 scan = systable_beginscan(depRel, DependDependerIndexId, true,
1013 NULL, 3, key);
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
1021 * are looking for.
1023 if (deprec->refclassid == ConstraintRelationId &&
1024 deprec->refobjsubid == 0 &&
1025 deprec->deptype == DEPENDENCY_INTERNAL)
1027 constraintId = deprec->refobjid;
1028 break;
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.
1043 List *
1044 get_index_ref_constraints(Oid indexId)
1046 List *result = NIL;
1047 Relation depRel;
1048 ScanKeyData key[3];
1049 SysScanDesc scan;
1050 HeapTuple tup;
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,
1066 Int32GetDatum(0));
1068 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
1069 NULL, 3, key);
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
1077 * are looking for.
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);
1090 return result;