PostgreSQL Source Code git master
pg_depend.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_depend.c
4 * routines to support manipulation of the pg_depend relation
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/catalog/pg_depend.c
12 *
13 *-------------------------------------------------------------------------
14 */
15#include "postgres.h"
16
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"
24#include "catalog/pg_depend.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"
32
33
34static bool isObjectPinned(const ObjectAddress *object);
35
36
37/*
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.
41 *
42 * This simply creates an entry in pg_depend, without any other processing.
43 */
44void
46 const ObjectAddress *referenced,
47 DependencyType behavior)
48{
49 recordMultipleDependencies(depender, referenced, 1, behavior);
50}
51
52/*
53 * Record multiple dependencies (of the same kind) for a single dependent
54 * object. This has a little less overhead than recording each separately.
55 */
56void
58 const ObjectAddress *referenced,
59 int nreferenced,
60 DependencyType behavior)
61{
62 Relation dependDesc;
63 CatalogIndexState indstate;
64 TupleTableSlot **slot;
65 int i,
66 max_slots,
67 slot_init_count,
68 slot_stored_count;
69
70 if (nreferenced <= 0)
71 return; /* nothing to do */
72
73 /*
74 * During bootstrap, do nothing since pg_depend may not exist yet.
75 *
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.
79 */
81 return;
82
83 dependDesc = table_open(DependRelationId, RowExclusiveLock);
84
85 /*
86 * Allocate the slots to use, but delay costly initialization until we
87 * know that they will be used.
88 */
89 max_slots = Min(nreferenced,
91 slot = palloc(sizeof(TupleTableSlot *) * max_slots);
92
93 /* Don't open indexes unless we need to make an update */
94 indstate = NULL;
95
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++)
101 {
102 /*
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.
106 */
107 if (isObjectPinned(referenced))
108 continue;
109
110 if (slot_init_count < max_slots)
111 {
112 slot[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc),
114 slot_init_count++;
115 }
116
117 ExecClearTuple(slot[slot_stored_count]);
118
119 /*
120 * Record the dependency. Note we don't bother to check for duplicate
121 * dependencies; there's no harm in them.
122 */
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);
130
131 memset(slot[slot_stored_count]->tts_isnull, false,
132 slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
133
134 ExecStoreVirtualTuple(slot[slot_stored_count]);
135 slot_stored_count++;
136
137 /* If slots are full, insert a batch of tuples */
138 if (slot_stored_count == max_slots)
139 {
140 /* fetch index info only when we know we need it */
141 if (indstate == NULL)
142 indstate = CatalogOpenIndexes(dependDesc);
143
144 CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
145 indstate);
146 slot_stored_count = 0;
147 }
148 }
149
150 /* Insert any tuples left in the buffer */
151 if (slot_stored_count > 0)
152 {
153 /* fetch index info only when we know we need it */
154 if (indstate == NULL)
155 indstate = CatalogOpenIndexes(dependDesc);
156
157 CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
158 indstate);
159 }
160
161 if (indstate != NULL)
162 CatalogCloseIndexes(indstate);
163
164 table_close(dependDesc, RowExclusiveLock);
165
166 /* Drop only the number of slots used */
167 for (i = 0; i < slot_init_count; i++)
169 pfree(slot);
170}
171
172/*
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.
176 *
177 * This must be called during creation of any user-definable object type
178 * that could be a member of an extension.
179 *
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.
184 *
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).
191 */
192void
194 bool isReplace)
195{
196 /* Only whole objects can be extension members */
197 Assert(object->objectSubId == 0);
198
200 {
201 ObjectAddress extension;
202
203 /* Only need to check for existing membership if isReplace */
204 if (isReplace)
205 {
206 Oid oldext;
207
208 /*
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.
213 */
214 oldext = getExtensionOfObject(object->classId, object->objectId);
215 if (OidIsValid(oldext))
216 {
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 */
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))));
226 }
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),
233 errdetail("An extension is not allowed to replace an object that it does not own.")));
234 }
235
236 /* OK, record it as a member of CurrentExtensionObject */
237 extension.classId = ExtensionRelationId;
239 extension.objectSubId = 0;
240
241 recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
242 }
243}
244
245/*
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.
249 *
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.
256 */
257void
259{
260 /*
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.
265 */
266
267 /* Only whole objects can be extension members */
268 Assert(object->objectSubId == 0);
269
271 {
272 Oid oldext;
273
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 */
280 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
281 errmsg("%s is not a member of extension \"%s\"",
282 getObjectDescription(object, false),
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.")));
285 }
286}
287
288/*
289 * deleteDependencyRecordsFor -- delete all records with given depender
290 * classId/objectId. Returns the number of records deleted.
291 *
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).
295 *
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.
299 */
300long
302 bool skipExtensionDeps)
303{
304 long count = 0;
305 Relation depRel;
306 ScanKeyData key[2];
307 SysScanDesc scan;
308 HeapTuple tup;
309
310 depRel = table_open(DependRelationId, RowExclusiveLock);
311
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));
320
321 scan = systable_beginscan(depRel, DependDependerIndexId, true,
322 NULL, 2, key);
323
324 while (HeapTupleIsValid(tup = systable_getnext(scan)))
325 {
326 if (skipExtensionDeps &&
327 ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
328 continue;
329
330 CatalogTupleDelete(depRel, &tup->t_self);
331 count++;
332 }
333
334 systable_endscan(scan);
335
337
338 return count;
339}
340
341/*
342 * deleteDependencyRecordsForClass -- delete all records with given depender
343 * classId/objectId, dependee classId, and deptype.
344 * Returns the number of records deleted.
345 *
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).
349 */
350long
352 Oid refclassId, char deptype)
353{
354 long count = 0;
355 Relation depRel;
356 ScanKeyData key[2];
357 SysScanDesc scan;
358 HeapTuple tup;
359
360 depRel = table_open(DependRelationId, RowExclusiveLock);
361
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));
370
371 scan = systable_beginscan(depRel, DependDependerIndexId, true,
372 NULL, 2, key);
373
374 while (HeapTupleIsValid(tup = systable_getnext(scan)))
375 {
376 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
377
378 if (depform->refclassid == refclassId && depform->deptype == deptype)
379 {
380 CatalogTupleDelete(depRel, &tup->t_self);
381 count++;
382 }
383 }
384
385 systable_endscan(scan);
386
388
389 return count;
390}
391
392/*
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.
396 */
397long
398deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
399 Oid refclassId, Oid refobjectId)
400{
401 long count = 0;
402 Relation depRel;
403 ScanKeyData key[2];
404 SysScanDesc scan;
405 HeapTuple tup;
406
407 depRel = table_open(DependRelationId, RowExclusiveLock);
408
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));
417
418 scan = systable_beginscan(depRel, DependDependerIndexId, true,
419 NULL, 2, key);
420
421 while (HeapTupleIsValid(tup = systable_getnext(scan)))
422 {
423 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
424
425 if (depform->refclassid == refclassId &&
426 depform->refobjid == refobjectId &&
427 depform->deptype == deptype)
428 {
429 CatalogTupleDelete(depRel, &tup->t_self);
430 count++;
431 }
432 }
433
434 systable_endscan(scan);
435
437
438 return count;
439}
440
441/*
442 * Adjust dependency record(s) to point to a different object of the same type
443 *
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).
447 *
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.
453 *
454 * Returns the number of records updated -- zero indicates a problem.
455 */
456long
457changeDependencyFor(Oid classId, Oid objectId,
458 Oid refClassId, Oid oldRefObjectId,
459 Oid newRefObjectId)
460{
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;
470
471 /*
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.
476 */
477 objAddr.classId = refClassId;
478 objAddr.objectId = oldRefObjectId;
479 objAddr.objectSubId = 0;
480
481 oldIsPinned = isObjectPinned(&objAddr);
482
483 objAddr.objectId = newRefObjectId;
484
485 newIsPinned = isObjectPinned(&objAddr);
486
487 if (oldIsPinned)
488 {
489 /*
490 * If both are pinned, we need do nothing. However, return 1 not 0,
491 * else callers will think this is an error case.
492 */
493 if (newIsPinned)
494 return 1;
495
496 /*
497 * There is no old dependency record, but we should insert a new one.
498 * Assume a normal dependency is wanted.
499 */
500 depAddr.classId = classId;
501 depAddr.objectId = objectId;
502 depAddr.objectSubId = 0;
503 recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
504
505 return 1;
506 }
507
508 depRel = table_open(DependRelationId, RowExclusiveLock);
509
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));
519
520 scan = systable_beginscan(depRel, DependDependerIndexId, true,
521 NULL, 2, key);
522
523 while (HeapTupleIsValid((tup = systable_getnext(scan))))
524 {
525 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
526
527 if (depform->refclassid == refClassId &&
528 depform->refobjid == oldRefObjectId)
529 {
530 if (newIsPinned)
531 CatalogTupleDelete(depRel, &tup->t_self);
532 else
533 {
534 /* make a modifiable copy */
535 tup = heap_copytuple(tup);
536 depform = (Form_pg_depend) GETSTRUCT(tup);
537
538 depform->refobjid = newRefObjectId;
539
540 CatalogTupleUpdate(depRel, &tup->t_self, tup);
541
542 heap_freetuple(tup);
543 }
544
545 count++;
546 }
547 }
548
549 systable_endscan(scan);
550
552
553 return count;
554}
555
556/*
557 * Adjust all dependency records to come from a different object of the same type
558 *
559 * classId/oldObjectId specify the old referencing object.
560 * newObjectId is the new referencing object (must be of class classId).
561 *
562 * Returns the number of records updated.
563 */
564long
565changeDependenciesOf(Oid classId, Oid oldObjectId,
566 Oid newObjectId)
567{
568 long count = 0;
569 Relation depRel;
570 ScanKeyData key[2];
571 SysScanDesc scan;
572 HeapTuple tup;
573
574 depRel = table_open(DependRelationId, RowExclusiveLock);
575
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));
584
585 scan = systable_beginscan(depRel, DependDependerIndexId, true,
586 NULL, 2, key);
587
588 while (HeapTupleIsValid((tup = systable_getnext(scan))))
589 {
590 Form_pg_depend depform;
591
592 /* make a modifiable copy */
593 tup = heap_copytuple(tup);
594 depform = (Form_pg_depend) GETSTRUCT(tup);
595
596 depform->objid = newObjectId;
597
598 CatalogTupleUpdate(depRel, &tup->t_self, tup);
599
600 heap_freetuple(tup);
601
602 count++;
603 }
604
605 systable_endscan(scan);
606
608
609 return count;
610}
611
612/*
613 * Adjust all dependency records to point to a different object of the same type
614 *
615 * refClassId/oldRefObjectId specify the old referenced object.
616 * newRefObjectId is the new referenced object (must be of class refClassId).
617 *
618 * Returns the number of records updated.
619 */
620long
621changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
622 Oid newRefObjectId)
623{
624 long count = 0;
625 Relation depRel;
626 ScanKeyData key[2];
627 SysScanDesc scan;
628 HeapTuple tup;
629 ObjectAddress objAddr;
630 bool newIsPinned;
631
632 depRel = table_open(DependRelationId, RowExclusiveLock);
633
634 /*
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.)
639 */
640 objAddr.classId = refClassId;
641 objAddr.objectId = oldRefObjectId;
642 objAddr.objectSubId = 0;
643
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))));
649
650 /*
651 * We can handle adding a dependency on something pinned, though, since
652 * that just means deleting the dependency entry.
653 */
654 objAddr.objectId = newRefObjectId;
655
656 newIsPinned = isObjectPinned(&objAddr);
657
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));
667
668 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
669 NULL, 2, key);
670
671 while (HeapTupleIsValid((tup = systable_getnext(scan))))
672 {
673 if (newIsPinned)
674 CatalogTupleDelete(depRel, &tup->t_self);
675 else
676 {
677 Form_pg_depend depform;
678
679 /* make a modifiable copy */
680 tup = heap_copytuple(tup);
681 depform = (Form_pg_depend) GETSTRUCT(tup);
682
683 depform->refobjid = newRefObjectId;
684
685 CatalogTupleUpdate(depRel, &tup->t_self, tup);
686
687 heap_freetuple(tup);
688 }
689
690 count++;
691 }
692
693 systable_endscan(scan);
694
696
697 return count;
698}
699
700/*
701 * isObjectPinned()
702 *
703 * Test if an object is required for basic database functionality.
704 *
705 * The passed subId, if any, is ignored; we assume that only whole objects
706 * are pinned (and that this implies pinning their components).
707 */
708static bool
710{
711 return IsPinnedObject(object->classId, object->objectId);
712}
713
714
715/*
716 * Various special-purpose lookups and manipulations of pg_depend.
717 */
718
719
720/*
721 * Find the extension containing the specified object, if any
722 *
723 * Returns the OID of the extension, or InvalidOid if the object does not
724 * belong to any extension.
725 *
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.
730 */
731Oid
732getExtensionOfObject(Oid classId, Oid objectId)
733{
734 Oid result = InvalidOid;
735 Relation depRel;
736 ScanKeyData key[2];
737 SysScanDesc scan;
738 HeapTuple tup;
739
740 depRel = table_open(DependRelationId, AccessShareLock);
741
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));
750
751 scan = systable_beginscan(depRel, DependDependerIndexId, true,
752 NULL, 2, key);
753
754 while (HeapTupleIsValid((tup = systable_getnext(scan))))
755 {
756 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
757
758 if (depform->refclassid == ExtensionRelationId &&
759 depform->deptype == DEPENDENCY_EXTENSION)
760 {
761 result = depform->refobjid;
762 break; /* no need to keep scanning */
763 }
764 }
765
766 systable_endscan(scan);
767
769
770 return result;
771}
772
773/*
774 * Return (possibly NIL) list of extensions that the given object depends on
775 * in DEPENDENCY_AUTO_EXTENSION mode.
776 */
777List *
779{
780 List *result = NIL;
781 Relation depRel;
782 ScanKeyData key[2];
783 SysScanDesc scan;
784 HeapTuple tup;
785
786 depRel = table_open(DependRelationId, AccessShareLock);
787
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));
796
797 scan = systable_beginscan(depRel, DependDependerIndexId, true,
798 NULL, 2, key);
799
800 while (HeapTupleIsValid((tup = systable_getnext(scan))))
801 {
802 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
803
804 if (depform->refclassid == ExtensionRelationId &&
805 depform->deptype == DEPENDENCY_AUTO_EXTENSION)
806 result = lappend_oid(result, depform->refobjid);
807 }
808
809 systable_endscan(scan);
810
812
813 return result;
814}
815
816/*
817 * Detect whether a sequence is marked as "owned" by a column
818 *
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.
822 *
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.
826 */
827bool
828sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
829{
830 bool ret = false;
831 Relation depRel;
832 ScanKeyData key[2];
833 SysScanDesc scan;
834 HeapTuple tup;
835
836 depRel = table_open(DependRelationId, AccessShareLock);
837
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));
846
847 scan = systable_beginscan(depRel, DependDependerIndexId, true,
848 NULL, 2, key);
849
850 while (HeapTupleIsValid((tup = systable_getnext(scan))))
851 {
852 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
853
854 if (depform->refclassid == RelationRelationId &&
855 depform->deptype == deptype)
856 {
857 *tableId = depform->refobjid;
858 *colId = depform->refobjsubid;
859 ret = true;
860 break; /* no need to keep scanning */
861 }
862 }
863
864 systable_endscan(scan);
865
867
868 return ret;
869}
870
871/*
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.
875 */
876static List *
878{
879 List *result = NIL;
880 Relation depRel;
881 ScanKeyData key[3];
882 SysScanDesc scan;
883 HeapTuple tup;
884
885 depRel = table_open(DependRelationId, AccessShareLock);
886
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,
900
901 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
902 NULL, attnum ? 3 : 2, key);
903
904 while (HeapTupleIsValid(tup = systable_getnext(scan)))
905 {
907
908 /*
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.)
912 */
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)
918 {
919 if (!deptype || deprec->deptype == deptype)
920 result = lappend_oid(result, deprec->objid);
921 }
922 }
923
924 systable_endscan(scan);
925
927
928 return result;
929}
930
931/*
932 * Collect a list of OIDs of all sequences owned (identity or serial) by the
933 * specified relation.
934 */
935List *
937{
938 return getOwnedSequences_internal(relid, 0, 0);
939}
940
941/*
942 * Get owned identity sequence, error if not exactly one.
943 */
944Oid
946{
947 Oid relid = RelationGetRelid(rel);
948 List *seqlist;
949
950 /*
951 * The identity sequence is associated with the topmost partitioned table,
952 * which might have column order different than the given partition.
953 */
954 if (RelationGetForm(rel)->relispartition)
955 {
956 List *ancestors = get_partition_ancestors(relid);
957 const char *attname = get_attname(relid, attnum, false);
958
959 relid = llast_oid(ancestors);
960 attnum = get_attnum(relid, attname);
962 elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
963 attname, relid);
964 list_free(ancestors);
965 }
966
968 if (list_length(seqlist) > 1)
969 elog(ERROR, "more than one owned sequence found");
970 else if (seqlist == NIL)
971 {
972 if (missing_ok)
973 return InvalidOid;
974 else
975 elog(ERROR, "no owned sequence found");
976 }
977
978 return linitial_oid(seqlist);
979}
980
981/*
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.
986 */
987Oid
989{
990 Oid constraintId = InvalidOid;
991 Relation depRel;
992 ScanKeyData key[3];
993 SysScanDesc scan;
994 HeapTuple tup;
995
996 /* Search the dependency table for the index */
997 depRel = table_open(DependRelationId, AccessShareLock);
998
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));
1011
1012 scan = systable_beginscan(depRel, DependDependerIndexId, true,
1013 NULL, 3, key);
1014
1015 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1016 {
1017 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
1018
1019 /*
1020 * We assume any internal dependency on a constraint must be what we
1021 * are looking for.
1022 */
1023 if (deprec->refclassid == ConstraintRelationId &&
1024 deprec->refobjsubid == 0 &&
1025 deprec->deptype == DEPENDENCY_INTERNAL)
1026 {
1027 constraintId = deprec->refobjid;
1028 break;
1029 }
1030 }
1031
1032 systable_endscan(scan);
1034
1035 return constraintId;
1036}
1037
1038/*
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.
1042 */
1043List *
1045{
1046 List *result = NIL;
1047 Relation depRel;
1048 ScanKeyData key[3];
1049 SysScanDesc scan;
1050 HeapTuple tup;
1051
1052 /* Search the dependency table for the index */
1053 depRel = table_open(DependRelationId, AccessShareLock);
1054
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));
1067
1068 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
1069 NULL, 3, key);
1070
1071 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1072 {
1073 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
1074
1075 /*
1076 * We assume any normal dependency from a constraint must be what we
1077 * are looking for.
1078 */
1079 if (deprec->classid == ConstraintRelationId &&
1080 deprec->objsubid == 0 &&
1081 deprec->deptype == DEPENDENCY_NORMAL)
1082 {
1083 result = lappend_oid(result, deprec->objid);
1084 }
1085 }
1086
1087 systable_endscan(scan);
1089
1090 return result;
1091}
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
#define Min(x, y)
Definition: c.h:961
#define Assert(condition)
Definition: c.h:815
int32_t int32
Definition: c.h:484
#define OidIsValid(objectId)
Definition: c.h:732
bool IsPinnedObject(Oid classId, Oid objectId)
Definition: catalog.c:341
DependencyType
Definition: dependency.h:32
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_AUTO_EXTENSION
Definition: dependency.h:39
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
@ DEPENDENCY_EXTENSION
Definition: dependency.h:38
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1425
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1441
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1739
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
bool creating_extension
Definition: extension.c:73
Oid CurrentExtensionObject
Definition: extension.c:74
char * get_extension_name(Oid ext_oid)
Definition: extension.c:180
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:273
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
#define MAX_CATALOG_MULTI_INSERT_BYTES
Definition: indexing.h:33
int i
Definition: isn.c:72
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
void list_free(List *list)
Definition: list.c:1546
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:466
char * getObjectDescription(const ObjectAddress *object, bool missing_ok)
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:258
void recordMultipleDependencies(const ObjectAddress *depender, const ObjectAddress *referenced, int nreferenced, DependencyType behavior)
Definition: pg_depend.c:57
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:457
static bool isObjectPinned(const ObjectAddress *object)
Definition: pg_depend.c:709
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:351
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:732
long changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId)
Definition: pg_depend.c:565
List * get_index_ref_constraints(Oid indexId)
Definition: pg_depend.c:1044
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:936
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:301
long deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype, Oid refclassId, Oid refobjectId)
Definition: pg_depend.c:398
long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:621
static List * getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
Definition: pg_depend.c:877
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:945
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:988
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:193
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:828
List * getAutoExtensionsOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:778
FormData_pg_depend
Definition: pg_depend.h:65
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define llast_oid(l)
Definition: pg_list.h:200
#define linitial_oid(l)
Definition: pg_list.h:180
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
Datum * tts_values
Definition: tuptable.h:125
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454