PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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/pg_type.h"
27#include "catalog/partition.h"
28#include "commands/extension.h"
29#include "miscadmin.h"
30#include "storage/lmgr.h"
31#include "storage/lock.h"
32#include "utils/fmgroids.h"
33#include "utils/lsyscache.h"
34#include "utils/rel.h"
35#include "utils/snapmgr.h"
36#include "utils/syscache.h"
37
38
39static bool isObjectPinned(const ObjectAddress *object);
40static void dependencyLockAndCheckObject(Oid classId, Oid objectId);
41
42
43/*
44 * Record a dependency between 2 objects via their respective ObjectAddress.
45 * The first argument is the dependent object, the second the one it
46 * references.
47 *
48 * This simply creates an entry in pg_depend, without any other processing.
49 */
50void
57
58/*
59 * Record multiple dependencies (of the same kind) for a single dependent
60 * object. This has a little less overhead than recording each separately.
61 */
62void
65 int nreferenced,
66 DependencyType behavior)
67{
70 TupleTableSlot **slot;
71 int i,
75
76 if (nreferenced <= 0)
77 return; /* nothing to do */
78
79 /*
80 * During bootstrap, do nothing since pg_depend may not exist yet.
81 *
82 * Objects created during bootstrap are most likely pinned, and the few
83 * that are not do not have dependencies on each other, so that there
84 * would be no need to make a pg_depend entry anyway.
85 */
87 return;
88
90
91 /*
92 * Allocate the slots to use, but delay costly initialization until we
93 * know that they will be used.
94 */
98
99 /* Don't open indexes unless we need to make an update */
100 indstate = NULL;
101
102 /* number of slots currently storing tuples */
104 /* number of slots currently initialized */
105 slot_init_count = 0;
106 for (i = 0; i < nreferenced; i++, referenced++)
107 {
108 /*
109 * If the referenced object is pinned by the system, there's no real
110 * need to record dependencies on it. This saves lots of space in
111 * pg_depend, so it's worth the time taken to check.
112 */
114 continue;
115
116 /*
117 * Make sure the new referenced object doesn't go away while we record
118 * the dependency. DROP routines should lock the object exclusively
119 * before they check dependencies.
120 */
122
124 {
128 }
129
131
132 /*
133 * Record the dependency. Note we don't bother to check for duplicate
134 * dependencies; there's no harm in them.
135 */
143
144 memset(slot[slot_stored_count]->tts_isnull, false,
145 slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
146
149
150 /* If slots are full, insert a batch of tuples */
152 {
153 /* fetch index info only when we know we need it */
154 if (indstate == NULL)
156
158 indstate);
160 }
161 }
162
163 /* Insert any tuples left in the buffer */
164 if (slot_stored_count > 0)
165 {
166 /* fetch index info only when we know we need it */
167 if (indstate == NULL)
169
171 indstate);
172 }
173
174 if (indstate != NULL)
176
178
179 /* Drop only the number of slots used */
180 for (i = 0; i < slot_init_count; i++)
182 pfree(slot);
183}
184
185/*
186 * If we are executing a CREATE EXTENSION operation, mark the given object
187 * as being a member of the extension, or check that it already is one.
188 * Otherwise, do nothing.
189 *
190 * This must be called during creation of any user-definable object type
191 * that could be a member of an extension.
192 *
193 * isReplace must be true if the object already existed, and false if it is
194 * newly created. In the former case we insist that it already be a member
195 * of the current extension. In the latter case we can skip checking whether
196 * it is already a member of any extension.
197 *
198 * Note: isReplace = true is typically used when updating an object in
199 * CREATE OR REPLACE and similar commands. We used to allow the target
200 * object to not already be an extension member, instead silently absorbing
201 * it into the current extension. However, this was both error-prone
202 * (extensions might accidentally overwrite free-standing objects) and
203 * a security hazard (since the object would retain its previous ownership).
204 */
205void
207 bool isReplace)
208{
209 /* Only whole objects can be extension members */
210 Assert(object->objectSubId == 0);
211
213 {
215
216 /* Only need to check for existing membership if isReplace */
217 if (isReplace)
218 {
219 Oid oldext;
220
221 /*
222 * Side note: these catalog lookups are safe only because the
223 * object is a pre-existing one. In the not-isReplace case, the
224 * caller has most likely not yet done a CommandCounterIncrement
225 * that would make the new object visible.
226 */
227 oldext = getExtensionOfObject(object->classId, object->objectId);
228 if (OidIsValid(oldext))
229 {
230 /* If already a member of this extension, nothing to do */
232 return;
233 /* Already a member of some other extension, so reject */
236 errmsg("%s is already a member of extension \"%s\"",
237 getObjectDescription(object, false),
239 }
240 /* It's a free-standing object, so reject */
243 errmsg("%s is not a member of extension \"%s\"",
244 getObjectDescription(object, false),
246 errdetail("An extension is not allowed to replace an object that it does not own.")));
247 }
248
249 /* OK, record it as a member of CurrentExtensionObject */
252 extension.objectSubId = 0;
253
255 }
256}
257
258/*
259 * If we are executing a CREATE EXTENSION operation, check that the given
260 * object is a member of the extension, and throw an error if it isn't.
261 * Otherwise, do nothing.
262 *
263 * This must be called whenever a CREATE IF NOT EXISTS operation (for an
264 * object type that can be an extension member) has found that an object of
265 * the desired name already exists. It is insecure for an extension to use
266 * IF NOT EXISTS except when the conflicting object is already an extension
267 * member; otherwise a hostile user could substitute an object with arbitrary
268 * properties.
269 */
270void
272{
273 /*
274 * This is actually the same condition tested in
275 * recordDependencyOnCurrentExtension; but we want to issue a
276 * differently-worded error, and anyway it would be pretty confusing to
277 * call recordDependencyOnCurrentExtension in these circumstances.
278 */
279
280 /* Only whole objects can be extension members */
281 Assert(object->objectSubId == 0);
282
284 {
285 Oid oldext;
286
287 oldext = getExtensionOfObject(object->classId, object->objectId);
288 /* If already a member of this extension, OK */
290 return;
291 /* Else complain */
294 errmsg("%s is not a member of extension \"%s\"",
295 getObjectDescription(object, false),
297 errdetail("An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.")));
298 }
299}
300
301/*
302 * deleteDependencyRecordsFor -- delete all records with given depender
303 * classId/objectId. Returns the number of records deleted.
304 *
305 * This is used when redefining an existing object. Links leading to the
306 * object do not change, and links leading from it will be recreated
307 * (possibly with some differences from before).
308 *
309 * If skipExtensionDeps is true, we do not delete any dependencies that
310 * show that the given object is a member of an extension. This avoids
311 * needing a lot of extra logic to fetch and recreate that dependency.
312 */
313long
316{
317 long count = 0;
319 ScanKeyData key[2];
320 SysScanDesc scan;
322
324
325 ScanKeyInit(&key[0],
328 ObjectIdGetDatum(classId));
329 ScanKeyInit(&key[1],
332 ObjectIdGetDatum(objectId));
333
335 NULL, 2, key);
336
337 while (HeapTupleIsValid(tup = systable_getnext(scan)))
338 {
339 if (skipExtensionDeps &&
341 continue;
342
343 CatalogTupleDelete(depRel, &tup->t_self);
344 count++;
345 }
346
347 systable_endscan(scan);
348
350
351 return count;
352}
353
354/*
355 * deleteDependencyRecordsForClass -- delete all records with given depender
356 * classId/objectId, dependee classId, and deptype.
357 * Returns the number of records deleted.
358 *
359 * This is a variant of deleteDependencyRecordsFor, useful when revoking
360 * an object property that is expressed by a dependency record (such as
361 * extension membership).
362 */
363long
365 Oid refclassId, char deptype)
366{
367 long count = 0;
369 ScanKeyData key[2];
370 SysScanDesc scan;
372
374
375 ScanKeyInit(&key[0],
378 ObjectIdGetDatum(classId));
379 ScanKeyInit(&key[1],
382 ObjectIdGetDatum(objectId));
383
385 NULL, 2, key);
386
387 while (HeapTupleIsValid(tup = systable_getnext(scan)))
388 {
390
391 if (depform->refclassid == refclassId && depform->deptype == deptype)
392 {
393 CatalogTupleDelete(depRel, &tup->t_self);
394 count++;
395 }
396 }
397
398 systable_endscan(scan);
399
401
402 return count;
403}
404
405/*
406 * deleteDependencyRecordsForSpecific -- delete all records with given depender
407 * classId/objectId, dependee classId/objectId, of the given deptype.
408 * Returns the number of records deleted.
409 */
410long
411deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
413{
414 long count = 0;
416 ScanKeyData key[2];
417 SysScanDesc scan;
419
421
422 ScanKeyInit(&key[0],
425 ObjectIdGetDatum(classId));
426 ScanKeyInit(&key[1],
429 ObjectIdGetDatum(objectId));
430
432 NULL, 2, key);
433
434 while (HeapTupleIsValid(tup = systable_getnext(scan)))
435 {
437
438 if (depform->refclassid == refclassId &&
439 depform->refobjid == refobjectId &&
440 depform->deptype == deptype)
441 {
442 CatalogTupleDelete(depRel, &tup->t_self);
443 count++;
444 }
445 }
446
447 systable_endscan(scan);
448
450
451 return count;
452}
453
454/*
455 * Adjust dependency record(s) to point to a different object of the same type
456 *
457 * classId/objectId specify the referencing object.
458 * refClassId/oldRefObjectId specify the old referenced object.
459 * newRefObjectId is the new referenced object (must be of class refClassId).
460 *
461 * Note the lack of objsubid parameters. If there are subobject references
462 * they will all be readjusted. Also, there is an expectation that we are
463 * dealing with NORMAL dependencies: if we have to replace an (implicit)
464 * dependency on a pinned object with an explicit dependency on an unpinned
465 * one, the new one will be NORMAL.
466 *
467 * Returns the number of records updated -- zero indicates a problem.
468 */
469long
470changeDependencyFor(Oid classId, Oid objectId,
473{
474 long count = 0;
476 ScanKeyData key[2];
477 SysScanDesc scan;
481 bool oldIsPinned;
482 bool newIsPinned;
483
484 /*
485 * Check to see if either oldRefObjectId or newRefObjectId is pinned.
486 * Pinned objects should not have any dependency entries pointing to them,
487 * so in these cases we should add or remove a pg_depend entry, or do
488 * nothing at all, rather than update an entry as in the normal case.
489 */
491 objAddr.objectId = oldRefObjectId;
492 objAddr.objectSubId = 0;
493
495
496 objAddr.objectId = newRefObjectId;
497
499
500 if (oldIsPinned)
501 {
502 /*
503 * If both are pinned, we need do nothing. However, return 1 not 0,
504 * else callers will think this is an error case.
505 */
506 if (newIsPinned)
507 return 1;
508
509 /*
510 * There is no old dependency record, but we should insert a new one.
511 * Assume a normal dependency is wanted.
512 */
513 depAddr.classId = classId;
514 depAddr.objectId = objectId;
515 depAddr.objectSubId = 0;
517
518 return 1;
519 }
520
521 /*
522 * Make sure the new referenced object doesn't go away while we record the
523 * dependency.
524 */
525 if (!newIsPinned)
527
529
530 /* There should be existing dependency record(s), so search. */
531 ScanKeyInit(&key[0],
534 ObjectIdGetDatum(classId));
535 ScanKeyInit(&key[1],
538 ObjectIdGetDatum(objectId));
539
541 NULL, 2, key);
542
543 while (HeapTupleIsValid((tup = systable_getnext(scan))))
544 {
546
547 if (depform->refclassid == refClassId &&
548 depform->refobjid == oldRefObjectId)
549 {
550 if (newIsPinned)
551 CatalogTupleDelete(depRel, &tup->t_self);
552 else
553 {
554 /* make a modifiable copy */
557
558 depform->refobjid = newRefObjectId;
559
560 CatalogTupleUpdate(depRel, &tup->t_self, tup);
561
563 }
564
565 count++;
566 }
567 }
568
569 systable_endscan(scan);
570
572
573 return count;
574}
575
576/*
577 * Adjust all dependency records to come from a different object of the same type
578 *
579 * classId/oldObjectId specify the old referencing object.
580 * newObjectId is the new referencing object (must be of class classId).
581 *
582 * Returns the number of records updated.
583 */
584long
587{
588 long count = 0;
590 ScanKeyData key[2];
591 SysScanDesc scan;
593
595
596 ScanKeyInit(&key[0],
599 ObjectIdGetDatum(classId));
600 ScanKeyInit(&key[1],
604
606 NULL, 2, key);
607
608 while (HeapTupleIsValid((tup = systable_getnext(scan))))
609 {
611
612 /* make a modifiable copy */
615
616 depform->objid = newObjectId;
617
618 CatalogTupleUpdate(depRel, &tup->t_self, tup);
619
621
622 count++;
623 }
624
625 systable_endscan(scan);
626
628
629 return count;
630}
631
632/*
633 * Adjust all dependency records to point to a different object of the same type
634 *
635 * refClassId/oldRefObjectId specify the old referenced object.
636 * newRefObjectId is the new referenced object (must be of class refClassId).
637 *
638 * Returns the number of records updated.
639 */
640long
643{
644 long count = 0;
646 ScanKeyData key[2];
647 SysScanDesc scan;
650 bool newIsPinned;
651
653
654 /*
655 * If oldRefObjectId is pinned, there won't be any dependency entries on
656 * it --- we can't cope in that case. (This isn't really worth expending
657 * code to fix, in current usage; it just means you can't rename stuff out
658 * of pg_catalog, which would likely be a bad move anyway.)
659 */
660 objAddr.classId = refClassId;
661 objAddr.objectId = oldRefObjectId;
662 objAddr.objectSubId = 0;
663
667 errmsg("cannot remove dependency on %s because it is a system object",
668 getObjectDescription(&objAddr, false))));
669
670 /*
671 * We can handle adding a dependency on something pinned, though, since
672 * that just means deleting the dependency entry.
673 */
674 objAddr.objectId = newRefObjectId;
675
677
678 /* Now search for dependency records */
679 ScanKeyInit(&key[0],
683 ScanKeyInit(&key[1],
687
689 NULL, 2, key);
690
691 while (HeapTupleIsValid((tup = systable_getnext(scan))))
692 {
693 if (newIsPinned)
694 CatalogTupleDelete(depRel, &tup->t_self);
695 else
696 {
698
699 /* make a modifiable copy */
702
703 depform->refobjid = newRefObjectId;
704
705 CatalogTupleUpdate(depRel, &tup->t_self, tup);
706
708 }
709
710 count++;
711 }
712
713 systable_endscan(scan);
714
716
717 return count;
718}
719
720/*
721 * isObjectPinned()
722 *
723 * Test if an object is required for basic database functionality.
724 *
725 * The passed subId, if any, is ignored; we assume that only whole objects
726 * are pinned (and that this implies pinning their components).
727 */
728static bool
730{
731 return IsPinnedObject(object->classId, object->objectId);
732}
733
734
735/*
736 * dependencyLockAndCheckObject
737 *
738 * Lock the object that we are about to record a dependency on. After it's
739 * locked, verify that it hasn't been dropped while we weren't looking. If it
740 * has been dropped, throw an an error.
741 *
742 * If the caller already holds a lock that conflicts with DROP
743 * (AccessShareLock or stronger), this does nothing. Callers should acquire
744 * locks already when they look up the referenced objects, but many callers
745 * currently do not. This is a backstop to make sure that we don't record a
746 * bogus reference permanently in the catalogs in that case. In the future,
747 * after we have tightened up all the callers to acquire locks earlier, this
748 * could just verify that the object is already locked and throw an error if
749 * not.
750 */
751static void
753{
754 /*
755 * Pinned objects cannot be dropped concurrently, and callers checked this
756 * already.
757 */
758 Assert(!IsPinnedObject(classId, objectId));
759
760 if (classId != RelationRelationId)
761 {
762 LOCKTAG tag;
763 SysCacheIdentifier cache;
764 Relation rel;
765 SysScanDesc scan;
767 HeapTuple tuple;
768
771 classId,
772 objectId,
773 0);
774
775 if (LockHeldByMe(&tag, AccessShareLock, true))
776 return;
777
778 /* Assume we should lock the whole object not a sub-object */
779 LockDatabaseObject(classId, objectId, 0, AccessShareLock);
780
781 /*
782 * Check that the object still exists. If the catalog has a suitable
783 * syscache, check that first.
784 */
785 cache = get_object_catcache_oid(classId);
786 if (cache != SYSCACHEID_INVALID)
787 {
788 if (SearchSysCacheExists1(cache, ObjectIdGetDatum(objectId)))
789 return;
790 }
791
792 /*
793 * If it's not found in the syscache, or there's no suitable syscache
794 * we can use, scan the catalog table using SnapshotSelf. This
795 * handles the case that it's an object we just created (for example,
796 * if it's a composite type created as part of creating a table).
797 */
798 rel = table_open(classId, AccessShareLock);
799
801 get_object_attnum_oid(classId),
803 ObjectIdGetDatum(objectId));
804
805 scan = systable_beginscan(rel, get_object_oid_index(classId),
806 true, SnapshotSelf, 1, &skey);
807
808 tuple = systable_getnext(scan);
809 if (!HeapTupleIsValid(tuple))
812 errmsg("referenced %s was concurrently dropped",
813 get_object_class_descr(classId))));
814
815 systable_endscan(scan);
817 }
818 else
819 {
820 /*
821 * Same logic for pg_class entries, but locking relations is handled
822 * by different functions.
823 *
824 * Callers are more careful with locking relations than other objects,
825 * so we should already have a lock on the relation, or on another
826 * object that indirectly prevents the relation from being dropped.
827 * For example, we might have a strong lock on a table while adding
828 * dependency to its index. However, we cannot detect the indirectly
829 * protected case here easily. To err on the safe side, acquire a
830 * lock directly on the relation if we're not holding one already.
831 */
832
833 /* all shared relations are pinned */
834 Assert(!IsSharedRelation(objectId));
835
836 if (CheckRelationOidLockedByMe(objectId, AccessShareLock, true))
837 return;
839
841 return;
844 errmsg("referenced relation was concurrently dropped")));
845 }
846}
847
848/*
849 * Various special-purpose lookups and manipulations of pg_depend.
850 */
851
852
853/*
854 * Find the extension containing the specified object, if any
855 *
856 * Returns the OID of the extension, or InvalidOid if the object does not
857 * belong to any extension.
858 *
859 * Extension membership is marked by an EXTENSION dependency from the object
860 * to the extension. Note that the result will be indeterminate if pg_depend
861 * contains links from this object to more than one extension ... but that
862 * should never happen.
863 */
864Oid
865getExtensionOfObject(Oid classId, Oid objectId)
866{
869 ScanKeyData key[2];
870 SysScanDesc scan;
872
874
875 ScanKeyInit(&key[0],
878 ObjectIdGetDatum(classId));
879 ScanKeyInit(&key[1],
882 ObjectIdGetDatum(objectId));
883
885 NULL, 2, key);
886
887 while (HeapTupleIsValid((tup = systable_getnext(scan))))
888 {
890
891 if (depform->refclassid == ExtensionRelationId &&
892 depform->deptype == DEPENDENCY_EXTENSION)
893 {
894 result = depform->refobjid;
895 break; /* no need to keep scanning */
896 }
897 }
898
899 systable_endscan(scan);
900
902
903 return result;
904}
905
906/*
907 * Return (possibly NIL) list of extensions that the given object depends on
908 * in DEPENDENCY_AUTO_EXTENSION mode.
909 */
910List *
912{
913 List *result = NIL;
915 ScanKeyData key[2];
916 SysScanDesc scan;
918
920
921 ScanKeyInit(&key[0],
924 ObjectIdGetDatum(classId));
925 ScanKeyInit(&key[1],
928 ObjectIdGetDatum(objectId));
929
931 NULL, 2, key);
932
933 while (HeapTupleIsValid((tup = systable_getnext(scan))))
934 {
936
937 if (depform->refclassid == ExtensionRelationId &&
939 result = lappend_oid(result, depform->refobjid);
940 }
941
942 systable_endscan(scan);
943
945
946 return result;
947}
948
949/*
950 * Look up a type belonging to an extension.
951 *
952 * Returns the type's OID, or InvalidOid if not found.
953 *
954 * Notice that the type is specified by name only, without a schema.
955 * That's because this will typically be used by relocatable extensions
956 * which can't make a-priori assumptions about which schema their objects
957 * are in. As long as the extension only defines one type of this name,
958 * the answer is unique anyway.
959 *
960 * We might later add the ability to look up functions, operators, etc.
961 */
962Oid
964{
967 ScanKeyData key[3];
968 SysScanDesc scan;
970
972
973 ScanKeyInit(&key[0],
977 ScanKeyInit(&key[1],
981 ScanKeyInit(&key[2],
984 Int32GetDatum(0));
985
987 NULL, 3, key);
988
989 while (HeapTupleIsValid(tup = systable_getnext(scan)))
990 {
992
993 if (depform->classid == TypeRelationId &&
994 depform->deptype == DEPENDENCY_EXTENSION)
995 {
996 Oid typoid = depform->objid;
998
1001 continue; /* should we throw an error? */
1003 typname) == 0)
1004 {
1005 result = typoid;
1007 break; /* no need to keep searching */
1008 }
1010 }
1011 }
1012
1013 systable_endscan(scan);
1014
1016
1017 return result;
1018}
1019
1020/*
1021 * Detect whether a sequence is marked as "owned" by a column
1022 *
1023 * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
1024 * column. If we find one, store the identity of the owning column
1025 * into *tableId and *colId and return true; else return false.
1026 *
1027 * Note: if there's more than one such pg_depend entry then you get
1028 * a random one of them returned into the out parameters. This should
1029 * not happen, though.
1030 */
1031bool
1033{
1034 bool ret = false;
1036 ScanKeyData key[2];
1037 SysScanDesc scan;
1038 HeapTuple tup;
1039
1041
1042 ScanKeyInit(&key[0],
1046 ScanKeyInit(&key[1],
1050
1052 NULL, 2, key);
1053
1054 while (HeapTupleIsValid((tup = systable_getnext(scan))))
1055 {
1057
1058 if (depform->refclassid == RelationRelationId &&
1059 depform->deptype == deptype)
1060 {
1061 *tableId = depform->refobjid;
1062 *colId = depform->refobjsubid;
1063 ret = true;
1064 break; /* no need to keep scanning */
1065 }
1066 }
1067
1068 systable_endscan(scan);
1069
1071
1072 return ret;
1073}
1074
1075/*
1076 * Collect a list of OIDs of all sequences owned by the specified relation,
1077 * and column if specified. If deptype is not zero, then only find sequences
1078 * with the specified dependency type.
1079 */
1080static List *
1082{
1083 List *result = NIL;
1085 ScanKeyData key[3];
1086 SysScanDesc scan;
1087 HeapTuple tup;
1088
1090
1091 ScanKeyInit(&key[0],
1095 ScanKeyInit(&key[1],
1098 ObjectIdGetDatum(relid));
1099 if (attnum)
1100 ScanKeyInit(&key[2],
1104
1106 NULL, attnum ? 3 : 2, key);
1107
1108 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1109 {
1111
1112 /*
1113 * We assume any auto or internal dependency of a sequence on a column
1114 * must be what we are looking for. (We need the relkind test because
1115 * indexes can also have auto dependencies on columns.)
1116 */
1117 if (deprec->classid == RelationRelationId &&
1118 deprec->objsubid == 0 &&
1119 deprec->refobjsubid != 0 &&
1120 (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
1122 {
1123 if (!deptype || deprec->deptype == deptype)
1124 result = lappend_oid(result, deprec->objid);
1125 }
1126 }
1127
1128 systable_endscan(scan);
1129
1131
1132 return result;
1133}
1134
1135/*
1136 * Collect a list of OIDs of all sequences owned (identity or serial) by the
1137 * specified relation.
1138 */
1139List *
1141{
1142 return getOwnedSequences_internal(relid, 0, 0);
1143}
1144
1145/*
1146 * Get owned identity sequence, error if not exactly one.
1147 */
1148Oid
1150{
1151 Oid relid = RelationGetRelid(rel);
1152 List *seqlist;
1153
1154 /*
1155 * The identity sequence is associated with the topmost partitioned table,
1156 * which might have column order different than the given partition.
1157 */
1159 {
1160 List *ancestors = get_partition_ancestors(relid);
1161 const char *attname = get_attname(relid, attnum, false);
1162
1163 relid = llast_oid(ancestors);
1164 attnum = get_attnum(relid, attname);
1166 elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
1167 attname, relid);
1168 list_free(ancestors);
1169 }
1170
1172 if (list_length(seqlist) > 1)
1173 elog(ERROR, "more than one owned sequence found");
1174 else if (seqlist == NIL)
1175 {
1176 if (missing_ok)
1177 return InvalidOid;
1178 else
1179 elog(ERROR, "no owned sequence found");
1180 }
1181
1182 return linitial_oid(seqlist);
1183}
1184
1185/*
1186 * get_index_constraint
1187 * Given the OID of an index, return the OID of the owning unique,
1188 * primary-key, or exclusion constraint, or InvalidOid if there
1189 * is no owning constraint.
1190 */
1191Oid
1193{
1196 ScanKeyData key[3];
1197 SysScanDesc scan;
1198 HeapTuple tup;
1199
1200 /* Search the dependency table for the index */
1202
1203 ScanKeyInit(&key[0],
1207 ScanKeyInit(&key[1],
1211 ScanKeyInit(&key[2],
1214 Int32GetDatum(0));
1215
1217 NULL, 3, key);
1218
1219 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1220 {
1222
1223 /*
1224 * We assume any internal dependency on a constraint must be what we
1225 * are looking for.
1226 */
1227 if (deprec->refclassid == ConstraintRelationId &&
1228 deprec->refobjsubid == 0 &&
1229 deprec->deptype == DEPENDENCY_INTERNAL)
1230 {
1231 constraintId = deprec->refobjid;
1232 break;
1233 }
1234 }
1235
1236 systable_endscan(scan);
1238
1239 return constraintId;
1240}
1241
1242/*
1243 * get_index_ref_constraints
1244 * Given the OID of an index, return the OID of all foreign key
1245 * constraints which reference the index.
1246 */
1247List *
1249{
1250 List *result = NIL;
1252 ScanKeyData key[3];
1253 SysScanDesc scan;
1254 HeapTuple tup;
1255
1256 /* Search the dependency table for the index */
1258
1259 ScanKeyInit(&key[0],
1263 ScanKeyInit(&key[1],
1267 ScanKeyInit(&key[2],
1270 Int32GetDatum(0));
1271
1273 NULL, 3, key);
1274
1275 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1276 {
1278
1279 /*
1280 * We assume any normal dependency from a constraint must be what we
1281 * are looking for.
1282 */
1283 if (deprec->classid == ConstraintRelationId &&
1284 deprec->objsubid == 0 &&
1285 deprec->deptype == DEPENDENCY_NORMAL)
1286 {
1287 result = lappend_oid(result, deprec->objid);
1288 }
1289 }
1290
1291 systable_endscan(scan);
1293
1294 return result;
1295}
int16 AttrNumber
Definition attnum.h:21
#define InvalidAttrNumber
Definition attnum.h:23
#define NameStr(name)
Definition c.h:835
#define Min(x, y)
Definition c.h:1091
#define Assert(condition)
Definition c.h:943
int32_t int32
Definition c.h:620
#define OidIsValid(objectId)
Definition c.h:858
bool IsPinnedObject(Oid classId, Oid objectId)
Definition catalog.c:370
bool IsSharedRelation(Oid relationId)
Definition catalog.c:304
uint32 result
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 errcode(int sqlerrcode)
Definition elog.c:875
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
const TupleTableSlotOps TTSOpsHeapTuple
Definition execTuples.c:85
bool creating_extension
Definition extension.c:80
Oid CurrentExtensionObject
Definition extension.c:81
char * get_extension_name(Oid ext_oid)
Definition extension.c:251
#define palloc_array(type, count)
Definition fe_memutils.h:91
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
Oid MyDatabaseId
Definition globals.c:96
HeapTuple heap_copytuple(HeapTuple tuple)
Definition heaptuple.c:686
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition indexing.c:273
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition indexing.c:43
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
#define MAX_CATALOG_MULTI_INSERT_BYTES
Definition indexing.h:33
int i
Definition isn.c:77
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
void list_free(List *list)
Definition list.c:1546
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition lmgr.c:1008
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:107
bool CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
Definition lmgr.c:351
bool LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode, bool orstronger)
Definition lock.c:640
#define AccessShareLock
Definition lockdefs.h:36
#define RowExclusiveLock
Definition lockdefs.h:38
#define SET_LOCKTAG_OBJECT(locktag, dboid, classoid, objoid, objsubid)
Definition locktag.h:162
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:1076
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2309
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:1045
void pfree(void *pointer)
Definition mcxt.c:1619
#define IsBootstrapProcessingMode()
Definition miscadmin.h:486
static char * errmsg
AttrNumber get_object_attnum_oid(Oid class_id)
const char * get_object_class_descr(Oid class_id)
char * getObjectDescription(const ObjectAddress *object, bool missing_ok)
Oid get_object_oid_index(Oid class_id)
SysCacheIdentifier get_object_catcache_oid(Oid class_id)
List * get_partition_ancestors(Oid relid)
Definition partition.c:134
NameData attname
int16 attnum
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition pg_depend.c:271
Oid getExtensionType(Oid extensionOid, const char *typname)
Definition pg_depend.c:963
void recordMultipleDependencies(const ObjectAddress *depender, const ObjectAddress *referenced, int nreferenced, DependencyType behavior)
Definition pg_depend.c:63
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:51
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition pg_depend.c:470
static bool isObjectPinned(const ObjectAddress *object)
Definition pg_depend.c:729
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition pg_depend.c:364
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition pg_depend.c:865
long changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId)
Definition pg_depend.c:585
List * get_index_ref_constraints(Oid indexId)
Definition pg_depend.c:1248
static void dependencyLockAndCheckObject(Oid classId, Oid objectId)
Definition pg_depend.c:752
List * getOwnedSequences(Oid relid)
Definition pg_depend.c:1140
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition pg_depend.c:314
long deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype, Oid refclassId, Oid refobjectId)
Definition pg_depend.c:411
long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition pg_depend.c:641
static List * getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
Definition pg_depend.c:1081
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Definition pg_depend.c:1149
Oid get_index_constraint(Oid indexId)
Definition pg_depend.c:1192
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition pg_depend.c:206
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition pg_depend.c:1032
List * getAutoExtensionsOfObject(Oid classId, Oid objectId)
Definition pg_depend.c:911
FormData_pg_depend
Definition pg_depend.h:67
END_CATALOG_STRUCT typedef FormData_pg_depend * Form_pg_depend
Definition pg_depend.h:76
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
END_CATALOG_STRUCT typedef FormData_pg_type * Form_pg_type
Definition pg_type.h:265
NameData typname
Definition pg_type.h:43
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define InvalidOid
unsigned int Oid
static int fb(int x)
#define RelationGetForm(relation)
Definition rel.h:510
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetDescr(relation)
Definition rel.h:542
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define SnapshotSelf
Definition snapmgr.h:32
#define BTEqualStrategyNumber
Definition stratnum.h:31
Definition pg_list.h:54
Datum * tts_values
Definition tuptable.h:131
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
#define SearchSysCacheExists1(cacheId, key1)
Definition syscache.h:100
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:476