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-2020, 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/dependency.h"
21 #include "catalog/indexing.h"
22 #include "catalog/pg_constraint.h"
23 #include "catalog/pg_depend.h"
24 #include "catalog/pg_extension.h"
25 #include "commands/extension.h"
26 #include "miscadmin.h"
27 #include "utils/fmgroids.h"
28 #include "utils/lsyscache.h"
29 #include "utils/rel.h"
30 
31 
32 static bool isObjectPinned(const ObjectAddress *object, Relation rel);
33 
34 
35 /*
36  * Record a dependency between 2 objects via their respective objectAddress.
37  * The first argument is the dependent object, the second the one it
38  * references.
39  *
40  * This simply creates an entry in pg_depend, without any other processing.
41  */
42 void
44  const ObjectAddress *referenced,
45  DependencyType behavior)
46 {
47  recordMultipleDependencies(depender, referenced, 1, behavior);
48 }
49 
50 /*
51  * Record multiple dependencies (of the same kind) for a single dependent
52  * object. This has a little less overhead than recording each separately.
53  */
54 void
56  const ObjectAddress *referenced,
57  int nreferenced,
58  DependencyType behavior)
59 {
60  Relation dependDesc;
61  CatalogIndexState indstate;
62  HeapTuple tup;
63  int i;
64  bool nulls[Natts_pg_depend];
65  Datum values[Natts_pg_depend];
66 
67  if (nreferenced <= 0)
68  return; /* nothing to do */
69 
70  /*
71  * During bootstrap, do nothing since pg_depend may not exist yet. initdb
72  * will fill in appropriate pg_depend entries after bootstrap.
73  */
75  return;
76 
77  dependDesc = table_open(DependRelationId, RowExclusiveLock);
78 
79  /* Don't open indexes unless we need to make an update */
80  indstate = NULL;
81 
82  memset(nulls, false, sizeof(nulls));
83 
84  for (i = 0; i < nreferenced; i++, referenced++)
85  {
86  /*
87  * If the referenced object is pinned by the system, there's no real
88  * need to record dependencies on it. This saves lots of space in
89  * pg_depend, so it's worth the time taken to check.
90  */
91  if (!isObjectPinned(referenced, dependDesc))
92  {
93  /*
94  * Record the Dependency. Note we don't bother to check for
95  * duplicate dependencies; there's no harm in them.
96  */
97  values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
98  values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
99  values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
100 
101  values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
102  values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
103  values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
104 
105  values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
106 
107  tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
108 
109  /* fetch index info only when we know we need it */
110  if (indstate == NULL)
111  indstate = CatalogOpenIndexes(dependDesc);
112 
113  CatalogTupleInsertWithInfo(dependDesc, tup, indstate);
114 
115  heap_freetuple(tup);
116  }
117  }
118 
119  if (indstate != NULL)
120  CatalogCloseIndexes(indstate);
121 
122  table_close(dependDesc, RowExclusiveLock);
123 }
124 
125 /*
126  * If we are executing a CREATE EXTENSION operation, mark the given object
127  * as being a member of the extension. Otherwise, do nothing.
128  *
129  * This must be called during creation of any user-definable object type
130  * that could be a member of an extension.
131  *
132  * If isReplace is true, the object already existed (or might have already
133  * existed), so we must check for a pre-existing extension membership entry.
134  * Passing false is a guarantee that the object is newly created, and so
135  * could not already be a member of any extension.
136  */
137 void
139  bool isReplace)
140 {
141  /* Only whole objects can be extension members */
142  Assert(object->objectSubId == 0);
143 
144  if (creating_extension)
145  {
146  ObjectAddress extension;
147 
148  /* Only need to check for existing membership if isReplace */
149  if (isReplace)
150  {
151  Oid oldext;
152 
153  oldext = getExtensionOfObject(object->classId, object->objectId);
154  if (OidIsValid(oldext))
155  {
156  /* If already a member of this extension, nothing to do */
157  if (oldext == CurrentExtensionObject)
158  return;
159  /* Already a member of some other extension, so reject */
160  ereport(ERROR,
161  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
162  errmsg("%s is already a member of extension \"%s\"",
163  getObjectDescription(object),
164  get_extension_name(oldext))));
165  }
166  }
167 
168  /* OK, record it as a member of CurrentExtensionObject */
169  extension.classId = ExtensionRelationId;
170  extension.objectId = CurrentExtensionObject;
171  extension.objectSubId = 0;
172 
173  recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
174  }
175 }
176 
177 /*
178  * deleteDependencyRecordsFor -- delete all records with given depender
179  * classId/objectId. Returns the number of records deleted.
180  *
181  * This is used when redefining an existing object. Links leading to the
182  * object do not change, and links leading from it will be recreated
183  * (possibly with some differences from before).
184  *
185  * If skipExtensionDeps is true, we do not delete any dependencies that
186  * show that the given object is a member of an extension. This avoids
187  * needing a lot of extra logic to fetch and recreate that dependency.
188  */
189 long
191  bool skipExtensionDeps)
192 {
193  long count = 0;
194  Relation depRel;
195  ScanKeyData key[2];
196  SysScanDesc scan;
197  HeapTuple tup;
198 
199  depRel = table_open(DependRelationId, RowExclusiveLock);
200 
201  ScanKeyInit(&key[0],
202  Anum_pg_depend_classid,
203  BTEqualStrategyNumber, F_OIDEQ,
204  ObjectIdGetDatum(classId));
205  ScanKeyInit(&key[1],
206  Anum_pg_depend_objid,
207  BTEqualStrategyNumber, F_OIDEQ,
208  ObjectIdGetDatum(objectId));
209 
210  scan = systable_beginscan(depRel, DependDependerIndexId, true,
211  NULL, 2, key);
212 
213  while (HeapTupleIsValid(tup = systable_getnext(scan)))
214  {
215  if (skipExtensionDeps &&
216  ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
217  continue;
218 
219  CatalogTupleDelete(depRel, &tup->t_self);
220  count++;
221  }
222 
223  systable_endscan(scan);
224 
225  table_close(depRel, RowExclusiveLock);
226 
227  return count;
228 }
229 
230 /*
231  * deleteDependencyRecordsForClass -- delete all records with given depender
232  * classId/objectId, dependee classId, and deptype.
233  * Returns the number of records deleted.
234  *
235  * This is a variant of deleteDependencyRecordsFor, useful when revoking
236  * an object property that is expressed by a dependency record (such as
237  * extension membership).
238  */
239 long
241  Oid refclassId, char deptype)
242 {
243  long count = 0;
244  Relation depRel;
245  ScanKeyData key[2];
246  SysScanDesc scan;
247  HeapTuple tup;
248 
249  depRel = table_open(DependRelationId, RowExclusiveLock);
250 
251  ScanKeyInit(&key[0],
252  Anum_pg_depend_classid,
253  BTEqualStrategyNumber, F_OIDEQ,
254  ObjectIdGetDatum(classId));
255  ScanKeyInit(&key[1],
256  Anum_pg_depend_objid,
257  BTEqualStrategyNumber, F_OIDEQ,
258  ObjectIdGetDatum(objectId));
259 
260  scan = systable_beginscan(depRel, DependDependerIndexId, true,
261  NULL, 2, key);
262 
263  while (HeapTupleIsValid(tup = systable_getnext(scan)))
264  {
265  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
266 
267  if (depform->refclassid == refclassId && depform->deptype == deptype)
268  {
269  CatalogTupleDelete(depRel, &tup->t_self);
270  count++;
271  }
272  }
273 
274  systable_endscan(scan);
275 
276  table_close(depRel, RowExclusiveLock);
277 
278  return count;
279 }
280 
281 /*
282  * Adjust dependency record(s) to point to a different object of the same type
283  *
284  * classId/objectId specify the referencing object.
285  * refClassId/oldRefObjectId specify the old referenced object.
286  * newRefObjectId is the new referenced object (must be of class refClassId).
287  *
288  * Note the lack of objsubid parameters. If there are subobject references
289  * they will all be readjusted. Also, there is an expectation that we are
290  * dealing with NORMAL dependencies: if we have to replace an (implicit)
291  * dependency on a pinned object with an explicit dependency on an unpinned
292  * one, the new one will be NORMAL.
293  *
294  * Returns the number of records updated -- zero indicates a problem.
295  */
296 long
297 changeDependencyFor(Oid classId, Oid objectId,
298  Oid refClassId, Oid oldRefObjectId,
299  Oid newRefObjectId)
300 {
301  long count = 0;
302  Relation depRel;
303  ScanKeyData key[2];
304  SysScanDesc scan;
305  HeapTuple tup;
306  ObjectAddress objAddr;
307  ObjectAddress depAddr;
308  bool oldIsPinned;
309  bool newIsPinned;
310 
311  depRel = table_open(DependRelationId, RowExclusiveLock);
312 
313  /*
314  * Check to see if either oldRefObjectId or newRefObjectId is pinned.
315  * Pinned objects should not have any dependency entries pointing to them,
316  * so in these cases we should add or remove a pg_depend entry, or do
317  * nothing at all, rather than update an entry as in the normal case.
318  */
319  objAddr.classId = refClassId;
320  objAddr.objectId = oldRefObjectId;
321  objAddr.objectSubId = 0;
322 
323  oldIsPinned = isObjectPinned(&objAddr, depRel);
324 
325  objAddr.objectId = newRefObjectId;
326 
327  newIsPinned = isObjectPinned(&objAddr, depRel);
328 
329  if (oldIsPinned)
330  {
331  table_close(depRel, RowExclusiveLock);
332 
333  /*
334  * If both are pinned, we need do nothing. However, return 1 not 0,
335  * else callers will think this is an error case.
336  */
337  if (newIsPinned)
338  return 1;
339 
340  /*
341  * There is no old dependency record, but we should insert a new one.
342  * Assume a normal dependency is wanted.
343  */
344  depAddr.classId = classId;
345  depAddr.objectId = objectId;
346  depAddr.objectSubId = 0;
347  recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
348 
349  return 1;
350  }
351 
352  /* There should be existing dependency record(s), so search. */
353  ScanKeyInit(&key[0],
354  Anum_pg_depend_classid,
355  BTEqualStrategyNumber, F_OIDEQ,
356  ObjectIdGetDatum(classId));
357  ScanKeyInit(&key[1],
358  Anum_pg_depend_objid,
359  BTEqualStrategyNumber, F_OIDEQ,
360  ObjectIdGetDatum(objectId));
361 
362  scan = systable_beginscan(depRel, DependDependerIndexId, true,
363  NULL, 2, key);
364 
365  while (HeapTupleIsValid((tup = systable_getnext(scan))))
366  {
367  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
368 
369  if (depform->refclassid == refClassId &&
370  depform->refobjid == oldRefObjectId)
371  {
372  if (newIsPinned)
373  CatalogTupleDelete(depRel, &tup->t_self);
374  else
375  {
376  /* make a modifiable copy */
377  tup = heap_copytuple(tup);
378  depform = (Form_pg_depend) GETSTRUCT(tup);
379 
380  depform->refobjid = newRefObjectId;
381 
382  CatalogTupleUpdate(depRel, &tup->t_self, tup);
383 
384  heap_freetuple(tup);
385  }
386 
387  count++;
388  }
389  }
390 
391  systable_endscan(scan);
392 
393  table_close(depRel, RowExclusiveLock);
394 
395  return count;
396 }
397 
398 /*
399  * Adjust all dependency records to come from a different object of the same type
400  *
401  * classId/oldObjectId specify the old referencing object.
402  * newObjectId is the new referencing object (must be of class classId).
403  *
404  * Returns the number of records updated.
405  */
406 long
407 changeDependenciesOf(Oid classId, Oid oldObjectId,
408  Oid newObjectId)
409 {
410  long count = 0;
411  Relation depRel;
412  ScanKeyData key[2];
413  SysScanDesc scan;
414  HeapTuple tup;
415 
416  depRel = table_open(DependRelationId, RowExclusiveLock);
417 
418  ScanKeyInit(&key[0],
419  Anum_pg_depend_classid,
420  BTEqualStrategyNumber, F_OIDEQ,
421  ObjectIdGetDatum(classId));
422  ScanKeyInit(&key[1],
423  Anum_pg_depend_objid,
424  BTEqualStrategyNumber, F_OIDEQ,
425  ObjectIdGetDatum(oldObjectId));
426 
427  scan = systable_beginscan(depRel, DependDependerIndexId, true,
428  NULL, 2, key);
429 
430  while (HeapTupleIsValid((tup = systable_getnext(scan))))
431  {
432  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
433 
434  /* make a modifiable copy */
435  tup = heap_copytuple(tup);
436  depform = (Form_pg_depend) GETSTRUCT(tup);
437 
438  depform->objid = newObjectId;
439 
440  CatalogTupleUpdate(depRel, &tup->t_self, tup);
441 
442  heap_freetuple(tup);
443 
444  count++;
445  }
446 
447  systable_endscan(scan);
448 
449  table_close(depRel, RowExclusiveLock);
450 
451  return count;
452 }
453 
454 /*
455  * Adjust all dependency records to point to a different object of the same type
456  *
457  * refClassId/oldRefObjectId specify the old referenced object.
458  * newRefObjectId is the new referenced object (must be of class refClassId).
459  *
460  * Returns the number of records updated.
461  */
462 long
463 changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
464  Oid newRefObjectId)
465 {
466  long count = 0;
467  Relation depRel;
468  ScanKeyData key[2];
469  SysScanDesc scan;
470  HeapTuple tup;
471  ObjectAddress objAddr;
472  bool newIsPinned;
473 
474  depRel = table_open(DependRelationId, RowExclusiveLock);
475 
476  /*
477  * If oldRefObjectId is pinned, there won't be any dependency entries on
478  * it --- we can't cope in that case. (This isn't really worth expending
479  * code to fix, in current usage; it just means you can't rename stuff out
480  * of pg_catalog, which would likely be a bad move anyway.)
481  */
482  objAddr.classId = refClassId;
483  objAddr.objectId = oldRefObjectId;
484  objAddr.objectSubId = 0;
485 
486  if (isObjectPinned(&objAddr, depRel))
487  ereport(ERROR,
488  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
489  errmsg("cannot remove dependency on %s because it is a system object",
490  getObjectDescription(&objAddr))));
491 
492  /*
493  * We can handle adding a dependency on something pinned, though, since
494  * that just means deleting the dependency entry.
495  */
496  objAddr.objectId = newRefObjectId;
497 
498  newIsPinned = isObjectPinned(&objAddr, depRel);
499 
500  /* Now search for dependency records */
501  ScanKeyInit(&key[0],
502  Anum_pg_depend_refclassid,
503  BTEqualStrategyNumber, F_OIDEQ,
504  ObjectIdGetDatum(refClassId));
505  ScanKeyInit(&key[1],
506  Anum_pg_depend_refobjid,
507  BTEqualStrategyNumber, F_OIDEQ,
508  ObjectIdGetDatum(oldRefObjectId));
509 
510  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
511  NULL, 2, key);
512 
513  while (HeapTupleIsValid((tup = systable_getnext(scan))))
514  {
515  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
516 
517  if (newIsPinned)
518  CatalogTupleDelete(depRel, &tup->t_self);
519  else
520  {
521  /* make a modifiable copy */
522  tup = heap_copytuple(tup);
523  depform = (Form_pg_depend) GETSTRUCT(tup);
524 
525  depform->refobjid = newRefObjectId;
526 
527  CatalogTupleUpdate(depRel, &tup->t_self, tup);
528 
529  heap_freetuple(tup);
530  }
531 
532  count++;
533  }
534 
535  systable_endscan(scan);
536 
537  table_close(depRel, RowExclusiveLock);
538 
539  return count;
540 }
541 
542 /*
543  * isObjectPinned()
544  *
545  * Test if an object is required for basic database functionality.
546  * Caller must already have opened pg_depend.
547  *
548  * The passed subId, if any, is ignored; we assume that only whole objects
549  * are pinned (and that this implies pinning their components).
550  */
551 static bool
553 {
554  bool ret = false;
555  SysScanDesc scan;
556  HeapTuple tup;
557  ScanKeyData key[2];
558 
559  ScanKeyInit(&key[0],
560  Anum_pg_depend_refclassid,
561  BTEqualStrategyNumber, F_OIDEQ,
562  ObjectIdGetDatum(object->classId));
563 
564  ScanKeyInit(&key[1],
565  Anum_pg_depend_refobjid,
566  BTEqualStrategyNumber, F_OIDEQ,
567  ObjectIdGetDatum(object->objectId));
568 
569  scan = systable_beginscan(rel, DependReferenceIndexId, true,
570  NULL, 2, key);
571 
572  /*
573  * Since we won't generate additional pg_depend entries for pinned
574  * objects, there can be at most one entry referencing a pinned object.
575  * Hence, it's sufficient to look at the first returned tuple; we don't
576  * need to loop.
577  */
578  tup = systable_getnext(scan);
579  if (HeapTupleIsValid(tup))
580  {
581  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
582 
583  if (foundDep->deptype == DEPENDENCY_PIN)
584  ret = true;
585  }
586 
587  systable_endscan(scan);
588 
589  return ret;
590 }
591 
592 
593 /*
594  * Various special-purpose lookups and manipulations of pg_depend.
595  */
596 
597 
598 /*
599  * Find the extension containing the specified object, if any
600  *
601  * Returns the OID of the extension, or InvalidOid if the object does not
602  * belong to any extension.
603  *
604  * Extension membership is marked by an EXTENSION dependency from the object
605  * to the extension. Note that the result will be indeterminate if pg_depend
606  * contains links from this object to more than one extension ... but that
607  * should never happen.
608  */
609 Oid
610 getExtensionOfObject(Oid classId, Oid objectId)
611 {
612  Oid result = InvalidOid;
613  Relation depRel;
614  ScanKeyData key[2];
615  SysScanDesc scan;
616  HeapTuple tup;
617 
618  depRel = table_open(DependRelationId, AccessShareLock);
619 
620  ScanKeyInit(&key[0],
621  Anum_pg_depend_classid,
622  BTEqualStrategyNumber, F_OIDEQ,
623  ObjectIdGetDatum(classId));
624  ScanKeyInit(&key[1],
625  Anum_pg_depend_objid,
626  BTEqualStrategyNumber, F_OIDEQ,
627  ObjectIdGetDatum(objectId));
628 
629  scan = systable_beginscan(depRel, DependDependerIndexId, true,
630  NULL, 2, key);
631 
632  while (HeapTupleIsValid((tup = systable_getnext(scan))))
633  {
634  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
635 
636  if (depform->refclassid == ExtensionRelationId &&
637  depform->deptype == DEPENDENCY_EXTENSION)
638  {
639  result = depform->refobjid;
640  break; /* no need to keep scanning */
641  }
642  }
643 
644  systable_endscan(scan);
645 
646  table_close(depRel, AccessShareLock);
647 
648  return result;
649 }
650 
651 /*
652  * Return (possibly NIL) list of extensions that the given object depends on
653  * in DEPENDENCY_AUTO_EXTENSION mode.
654  */
655 List *
657 {
658  List *result = NIL;
659  Relation depRel;
660  ScanKeyData key[2];
661  SysScanDesc scan;
662  HeapTuple tup;
663 
664  depRel = table_open(DependRelationId, AccessShareLock);
665 
666  ScanKeyInit(&key[0],
667  Anum_pg_depend_classid,
668  BTEqualStrategyNumber, F_OIDEQ,
669  ObjectIdGetDatum(classId));
670  ScanKeyInit(&key[1],
671  Anum_pg_depend_objid,
672  BTEqualStrategyNumber, F_OIDEQ,
673  ObjectIdGetDatum(objectId));
674 
675  scan = systable_beginscan(depRel, DependDependerIndexId, true,
676  NULL, 2, key);
677 
678  while (HeapTupleIsValid((tup = systable_getnext(scan))))
679  {
680  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
681 
682  if (depform->refclassid == ExtensionRelationId &&
683  depform->deptype == DEPENDENCY_AUTO_EXTENSION)
684  result = lappend_oid(result, depform->refobjid);
685  }
686 
687  systable_endscan(scan);
688 
689  table_close(depRel, AccessShareLock);
690 
691  return result;
692 }
693 
694 /*
695  * Detect whether a sequence is marked as "owned" by a column
696  *
697  * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
698  * column. If we find one, store the identity of the owning column
699  * into *tableId and *colId and return true; else return false.
700  *
701  * Note: if there's more than one such pg_depend entry then you get
702  * a random one of them returned into the out parameters. This should
703  * not happen, though.
704  */
705 bool
706 sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
707 {
708  bool ret = false;
709  Relation depRel;
710  ScanKeyData key[2];
711  SysScanDesc scan;
712  HeapTuple tup;
713 
714  depRel = table_open(DependRelationId, AccessShareLock);
715 
716  ScanKeyInit(&key[0],
717  Anum_pg_depend_classid,
718  BTEqualStrategyNumber, F_OIDEQ,
719  ObjectIdGetDatum(RelationRelationId));
720  ScanKeyInit(&key[1],
721  Anum_pg_depend_objid,
722  BTEqualStrategyNumber, F_OIDEQ,
723  ObjectIdGetDatum(seqId));
724 
725  scan = systable_beginscan(depRel, DependDependerIndexId, true,
726  NULL, 2, key);
727 
728  while (HeapTupleIsValid((tup = systable_getnext(scan))))
729  {
730  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
731 
732  if (depform->refclassid == RelationRelationId &&
733  depform->deptype == deptype)
734  {
735  *tableId = depform->refobjid;
736  *colId = depform->refobjsubid;
737  ret = true;
738  break; /* no need to keep scanning */
739  }
740  }
741 
742  systable_endscan(scan);
743 
744  table_close(depRel, AccessShareLock);
745 
746  return ret;
747 }
748 
749 /*
750  * Collect a list of OIDs of all sequences owned by the specified relation,
751  * and column if specified. If deptype is not zero, then only find sequences
752  * with the specified dependency type.
753  */
754 static List *
756 {
757  List *result = NIL;
758  Relation depRel;
759  ScanKeyData key[3];
760  SysScanDesc scan;
761  HeapTuple tup;
762 
763  depRel = table_open(DependRelationId, AccessShareLock);
764 
765  ScanKeyInit(&key[0],
766  Anum_pg_depend_refclassid,
767  BTEqualStrategyNumber, F_OIDEQ,
768  ObjectIdGetDatum(RelationRelationId));
769  ScanKeyInit(&key[1],
770  Anum_pg_depend_refobjid,
771  BTEqualStrategyNumber, F_OIDEQ,
772  ObjectIdGetDatum(relid));
773  if (attnum)
774  ScanKeyInit(&key[2],
775  Anum_pg_depend_refobjsubid,
776  BTEqualStrategyNumber, F_INT4EQ,
777  Int32GetDatum(attnum));
778 
779  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
780  NULL, attnum ? 3 : 2, key);
781 
782  while (HeapTupleIsValid(tup = systable_getnext(scan)))
783  {
784  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
785 
786  /*
787  * We assume any auto or internal dependency of a sequence on a column
788  * must be what we are looking for. (We need the relkind test because
789  * indexes can also have auto dependencies on columns.)
790  */
791  if (deprec->classid == RelationRelationId &&
792  deprec->objsubid == 0 &&
793  deprec->refobjsubid != 0 &&
794  (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
795  get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
796  {
797  if (!deptype || deprec->deptype == deptype)
798  result = lappend_oid(result, deprec->objid);
799  }
800  }
801 
802  systable_endscan(scan);
803 
804  table_close(depRel, AccessShareLock);
805 
806  return result;
807 }
808 
809 /*
810  * Collect a list of OIDs of all sequences owned (identity or serial) by the
811  * specified relation.
812  */
813 List *
815 {
816  return getOwnedSequences_internal(relid, 0, 0);
817 }
818 
819 /*
820  * Get owned identity sequence, error if not exactly one.
821  */
822 Oid
823 getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
824 {
825  List *seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
826 
827  if (list_length(seqlist) > 1)
828  elog(ERROR, "more than one owned sequence found");
829  else if (list_length(seqlist) < 1)
830  {
831  if (missing_ok)
832  return InvalidOid;
833  else
834  elog(ERROR, "no owned sequence found");
835  }
836 
837  return linitial_oid(seqlist);
838 }
839 
840 /*
841  * get_constraint_index
842  * Given the OID of a unique, primary-key, or exclusion constraint,
843  * return the OID of the underlying index.
844  *
845  * Return InvalidOid if the index couldn't be found; this suggests the
846  * given OID is bogus, but we leave it to caller to decide what to do.
847  */
848 Oid
850 {
851  Oid indexId = InvalidOid;
852  Relation depRel;
853  ScanKeyData key[3];
854  SysScanDesc scan;
855  HeapTuple tup;
856 
857  /* Search the dependency table for the dependent index */
858  depRel = table_open(DependRelationId, AccessShareLock);
859 
860  ScanKeyInit(&key[0],
861  Anum_pg_depend_refclassid,
862  BTEqualStrategyNumber, F_OIDEQ,
863  ObjectIdGetDatum(ConstraintRelationId));
864  ScanKeyInit(&key[1],
865  Anum_pg_depend_refobjid,
866  BTEqualStrategyNumber, F_OIDEQ,
867  ObjectIdGetDatum(constraintId));
868  ScanKeyInit(&key[2],
869  Anum_pg_depend_refobjsubid,
870  BTEqualStrategyNumber, F_INT4EQ,
871  Int32GetDatum(0));
872 
873  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
874  NULL, 3, key);
875 
876  while (HeapTupleIsValid(tup = systable_getnext(scan)))
877  {
878  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
879 
880  /*
881  * We assume any internal dependency of an index on the constraint
882  * must be what we are looking for.
883  */
884  if (deprec->classid == RelationRelationId &&
885  deprec->objsubid == 0 &&
886  deprec->deptype == DEPENDENCY_INTERNAL)
887  {
888  char relkind = get_rel_relkind(deprec->objid);
889 
890  /*
891  * This is pure paranoia; there shouldn't be any other relkinds
892  * dependent on a constraint.
893  */
894  if (relkind != RELKIND_INDEX &&
895  relkind != RELKIND_PARTITIONED_INDEX)
896  continue;
897 
898  indexId = deprec->objid;
899  break;
900  }
901  }
902 
903  systable_endscan(scan);
904  table_close(depRel, AccessShareLock);
905 
906  return indexId;
907 }
908 
909 /*
910  * get_index_constraint
911  * Given the OID of an index, return the OID of the owning unique,
912  * primary-key, or exclusion constraint, or InvalidOid if there
913  * is no owning constraint.
914  */
915 Oid
917 {
918  Oid constraintId = InvalidOid;
919  Relation depRel;
920  ScanKeyData key[3];
921  SysScanDesc scan;
922  HeapTuple tup;
923 
924  /* Search the dependency table for the index */
925  depRel = table_open(DependRelationId, AccessShareLock);
926 
927  ScanKeyInit(&key[0],
928  Anum_pg_depend_classid,
929  BTEqualStrategyNumber, F_OIDEQ,
930  ObjectIdGetDatum(RelationRelationId));
931  ScanKeyInit(&key[1],
932  Anum_pg_depend_objid,
933  BTEqualStrategyNumber, F_OIDEQ,
934  ObjectIdGetDatum(indexId));
935  ScanKeyInit(&key[2],
936  Anum_pg_depend_objsubid,
937  BTEqualStrategyNumber, F_INT4EQ,
938  Int32GetDatum(0));
939 
940  scan = systable_beginscan(depRel, DependDependerIndexId, true,
941  NULL, 3, key);
942 
943  while (HeapTupleIsValid(tup = systable_getnext(scan)))
944  {
945  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
946 
947  /*
948  * We assume any internal dependency on a constraint must be what we
949  * are looking for.
950  */
951  if (deprec->refclassid == ConstraintRelationId &&
952  deprec->refobjsubid == 0 &&
953  deprec->deptype == DEPENDENCY_INTERNAL)
954  {
955  constraintId = deprec->refobjid;
956  break;
957  }
958  }
959 
960  systable_endscan(scan);
961  table_close(depRel, AccessShareLock);
962 
963  return constraintId;
964 }
965 
966 /*
967  * get_index_ref_constraints
968  * Given the OID of an index, return the OID of all foreign key
969  * constraints which reference the index.
970  */
971 List *
973 {
974  List *result = NIL;
975  Relation depRel;
976  ScanKeyData key[3];
977  SysScanDesc scan;
978  HeapTuple tup;
979 
980  /* Search the dependency table for the index */
981  depRel = table_open(DependRelationId, AccessShareLock);
982 
983  ScanKeyInit(&key[0],
984  Anum_pg_depend_refclassid,
985  BTEqualStrategyNumber, F_OIDEQ,
986  ObjectIdGetDatum(RelationRelationId));
987  ScanKeyInit(&key[1],
988  Anum_pg_depend_refobjid,
989  BTEqualStrategyNumber, F_OIDEQ,
990  ObjectIdGetDatum(indexId));
991  ScanKeyInit(&key[2],
992  Anum_pg_depend_refobjsubid,
993  BTEqualStrategyNumber, F_INT4EQ,
994  Int32GetDatum(0));
995 
996  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
997  NULL, 3, key);
998 
999  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1000  {
1001  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
1002 
1003  /*
1004  * We assume any normal dependency from a constraint must be what we
1005  * are looking for.
1006  */
1007  if (deprec->classid == ConstraintRelationId &&
1008  deprec->objsubid == 0 &&
1009  deprec->deptype == DEPENDENCY_NORMAL)
1010  {
1011  result = lappend_oid(result, deprec->objid);
1012  }
1013  }
1014 
1015  systable_endscan(scan);
1016  table_close(depRel, AccessShareLock);
1017 
1018  return result;
1019 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
Oid CurrentExtensionObject
Definition: extension.c:72
#define NIL
Definition: pg_list.h:65
DependencyType
Definition: dependency.h:31
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:610
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:706
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1866
#define DependReferenceIndexId
Definition: indexing.h:151
char * get_extension_name(Oid ext_oid)
Definition: extension.c:185
#define DependDependerIndexId
Definition: indexing.h:149
static List * getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
Definition: pg_depend.c:755
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:190
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: pg_depend.c:823
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
#define OidIsValid(objectId)
Definition: c.h:644
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
char * getObjectDescription(const ObjectAddress *object)
signed int int32
Definition: c.h:355
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
static bool isObjectPinned(const ObjectAddress *object, Relation rel)
Definition: pg_depend.c:552
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:916
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:814
uintptr_t Datum
Definition: postgres.h:367
void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:204
TupleDesc rd_att
Definition: rel.h:110
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:240
long changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId)
Definition: pg_depend.c:407
#define InvalidOid
Definition: postgres_ext.h:36
bool creating_extension
Definition: extension.c:71
int16 attnum
Definition: pg_attribute.h:79
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:738
void recordMultipleDependencies(const ObjectAddress *depender, const ObjectAddress *referenced, int nreferenced, DependencyType behavior)
Definition: pg_depend.c:55
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:138
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:42
#define linitial_oid(l)
Definition: pg_list.h:197
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
static int list_length(const List *l)
Definition: pg_list.h:169
List * get_index_ref_constraints(Oid indexId)
Definition: pg_depend.c:972
#define CharGetDatum(X)
Definition: postgres.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:392
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:824
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:297
#define elog(elevel,...)
Definition: elog.h:214
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:60
Oid get_constraint_index(Oid constraintId)
Definition: pg_depend.c:849
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:463
List * getAutoExtensionsOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:656
int16 AttrNumber
Definition: attnum.h:21
#define BTEqualStrategyNumber
Definition: stratnum.h:31