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-2019, 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  * Detect whether a sequence is marked as "owned" by a column
653  *
654  * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
655  * column. If we find one, store the identity of the owning column
656  * into *tableId and *colId and return true; else return false.
657  *
658  * Note: if there's more than one such pg_depend entry then you get
659  * a random one of them returned into the out parameters. This should
660  * not happen, though.
661  */
662 bool
663 sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
664 {
665  bool ret = false;
666  Relation depRel;
667  ScanKeyData key[2];
668  SysScanDesc scan;
669  HeapTuple tup;
670 
671  depRel = table_open(DependRelationId, AccessShareLock);
672 
673  ScanKeyInit(&key[0],
674  Anum_pg_depend_classid,
675  BTEqualStrategyNumber, F_OIDEQ,
676  ObjectIdGetDatum(RelationRelationId));
677  ScanKeyInit(&key[1],
678  Anum_pg_depend_objid,
679  BTEqualStrategyNumber, F_OIDEQ,
680  ObjectIdGetDatum(seqId));
681 
682  scan = systable_beginscan(depRel, DependDependerIndexId, true,
683  NULL, 2, key);
684 
685  while (HeapTupleIsValid((tup = systable_getnext(scan))))
686  {
687  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
688 
689  if (depform->refclassid == RelationRelationId &&
690  depform->deptype == deptype)
691  {
692  *tableId = depform->refobjid;
693  *colId = depform->refobjsubid;
694  ret = true;
695  break; /* no need to keep scanning */
696  }
697  }
698 
699  systable_endscan(scan);
700 
701  table_close(depRel, AccessShareLock);
702 
703  return ret;
704 }
705 
706 /*
707  * Collect a list of OIDs of all sequences owned by the specified relation,
708  * and column if specified. If deptype is not zero, then only find sequences
709  * with the specified dependency type.
710  */
711 static List *
713 {
714  List *result = NIL;
715  Relation depRel;
716  ScanKeyData key[3];
717  SysScanDesc scan;
718  HeapTuple tup;
719 
720  depRel = table_open(DependRelationId, AccessShareLock);
721 
722  ScanKeyInit(&key[0],
723  Anum_pg_depend_refclassid,
724  BTEqualStrategyNumber, F_OIDEQ,
725  ObjectIdGetDatum(RelationRelationId));
726  ScanKeyInit(&key[1],
727  Anum_pg_depend_refobjid,
728  BTEqualStrategyNumber, F_OIDEQ,
729  ObjectIdGetDatum(relid));
730  if (attnum)
731  ScanKeyInit(&key[2],
732  Anum_pg_depend_refobjsubid,
733  BTEqualStrategyNumber, F_INT4EQ,
734  Int32GetDatum(attnum));
735 
736  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
737  NULL, attnum ? 3 : 2, key);
738 
739  while (HeapTupleIsValid(tup = systable_getnext(scan)))
740  {
741  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
742 
743  /*
744  * We assume any auto or internal dependency of a sequence on a column
745  * must be what we are looking for. (We need the relkind test because
746  * indexes can also have auto dependencies on columns.)
747  */
748  if (deprec->classid == RelationRelationId &&
749  deprec->objsubid == 0 &&
750  deprec->refobjsubid != 0 &&
751  (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
752  get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
753  {
754  if (!deptype || deprec->deptype == deptype)
755  result = lappend_oid(result, deprec->objid);
756  }
757  }
758 
759  systable_endscan(scan);
760 
761  table_close(depRel, AccessShareLock);
762 
763  return result;
764 }
765 
766 /*
767  * Collect a list of OIDs of all sequences owned (identity or serial) by the
768  * specified relation.
769  */
770 List *
772 {
773  return getOwnedSequences_internal(relid, 0, 0);
774 }
775 
776 /*
777  * Get owned identity sequence, error if not exactly one.
778  */
779 Oid
780 getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
781 {
782  List *seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
783 
784  if (list_length(seqlist) > 1)
785  elog(ERROR, "more than one owned sequence found");
786  else if (list_length(seqlist) < 1)
787  {
788  if (missing_ok)
789  return InvalidOid;
790  else
791  elog(ERROR, "no owned sequence found");
792  }
793 
794  return linitial_oid(seqlist);
795 }
796 
797 /*
798  * get_constraint_index
799  * Given the OID of a unique, primary-key, or exclusion constraint,
800  * return the OID of the underlying index.
801  *
802  * Return InvalidOid if the index couldn't be found; this suggests the
803  * given OID is bogus, but we leave it to caller to decide what to do.
804  */
805 Oid
807 {
808  Oid indexId = InvalidOid;
809  Relation depRel;
810  ScanKeyData key[3];
811  SysScanDesc scan;
812  HeapTuple tup;
813 
814  /* Search the dependency table for the dependent index */
815  depRel = table_open(DependRelationId, AccessShareLock);
816 
817  ScanKeyInit(&key[0],
818  Anum_pg_depend_refclassid,
819  BTEqualStrategyNumber, F_OIDEQ,
820  ObjectIdGetDatum(ConstraintRelationId));
821  ScanKeyInit(&key[1],
822  Anum_pg_depend_refobjid,
823  BTEqualStrategyNumber, F_OIDEQ,
824  ObjectIdGetDatum(constraintId));
825  ScanKeyInit(&key[2],
826  Anum_pg_depend_refobjsubid,
827  BTEqualStrategyNumber, F_INT4EQ,
828  Int32GetDatum(0));
829 
830  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
831  NULL, 3, key);
832 
833  while (HeapTupleIsValid(tup = systable_getnext(scan)))
834  {
835  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
836 
837  /*
838  * We assume any internal dependency of an index on the constraint
839  * must be what we are looking for.
840  */
841  if (deprec->classid == RelationRelationId &&
842  deprec->objsubid == 0 &&
843  deprec->deptype == DEPENDENCY_INTERNAL)
844  {
845  char relkind = get_rel_relkind(deprec->objid);
846 
847  /*
848  * This is pure paranoia; there shouldn't be any other relkinds
849  * dependent on a constraint.
850  */
851  if (relkind != RELKIND_INDEX &&
852  relkind != RELKIND_PARTITIONED_INDEX)
853  continue;
854 
855  indexId = deprec->objid;
856  break;
857  }
858  }
859 
860  systable_endscan(scan);
861  table_close(depRel, AccessShareLock);
862 
863  return indexId;
864 }
865 
866 /*
867  * get_index_constraint
868  * Given the OID of an index, return the OID of the owning unique,
869  * primary-key, or exclusion constraint, or InvalidOid if there
870  * is no owning constraint.
871  */
872 Oid
874 {
875  Oid constraintId = InvalidOid;
876  Relation depRel;
877  ScanKeyData key[3];
878  SysScanDesc scan;
879  HeapTuple tup;
880 
881  /* Search the dependency table for the index */
882  depRel = table_open(DependRelationId, AccessShareLock);
883 
884  ScanKeyInit(&key[0],
885  Anum_pg_depend_classid,
886  BTEqualStrategyNumber, F_OIDEQ,
887  ObjectIdGetDatum(RelationRelationId));
888  ScanKeyInit(&key[1],
889  Anum_pg_depend_objid,
890  BTEqualStrategyNumber, F_OIDEQ,
891  ObjectIdGetDatum(indexId));
892  ScanKeyInit(&key[2],
893  Anum_pg_depend_objsubid,
894  BTEqualStrategyNumber, F_INT4EQ,
895  Int32GetDatum(0));
896 
897  scan = systable_beginscan(depRel, DependDependerIndexId, true,
898  NULL, 3, key);
899 
900  while (HeapTupleIsValid(tup = systable_getnext(scan)))
901  {
902  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
903 
904  /*
905  * We assume any internal dependency on a constraint must be what we
906  * are looking for.
907  */
908  if (deprec->refclassid == ConstraintRelationId &&
909  deprec->refobjsubid == 0 &&
910  deprec->deptype == DEPENDENCY_INTERNAL)
911  {
912  constraintId = deprec->refobjid;
913  break;
914  }
915  }
916 
917  systable_endscan(scan);
918  table_close(depRel, AccessShareLock);
919 
920  return constraintId;
921 }
922 
923 /*
924  * get_index_ref_constraints
925  * Given the OID of an index, return the OID of all foreign key
926  * constraints which reference the index.
927  */
928 List *
930 {
931  List *result = NIL;
932  Relation depRel;
933  ScanKeyData key[3];
934  SysScanDesc scan;
935  HeapTuple tup;
936 
937  /* Search the dependency table for the index */
938  depRel = table_open(DependRelationId, AccessShareLock);
939 
940  ScanKeyInit(&key[0],
941  Anum_pg_depend_refclassid,
942  BTEqualStrategyNumber, F_OIDEQ,
943  ObjectIdGetDatum(RelationRelationId));
944  ScanKeyInit(&key[1],
945  Anum_pg_depend_refobjid,
946  BTEqualStrategyNumber, F_OIDEQ,
947  ObjectIdGetDatum(indexId));
948  ScanKeyInit(&key[2],
949  Anum_pg_depend_refobjsubid,
950  BTEqualStrategyNumber, F_INT4EQ,
951  Int32GetDatum(0));
952 
953  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
954  NULL, 3, key);
955 
956  while (HeapTupleIsValid(tup = systable_getnext(scan)))
957  {
958  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
959 
960  /*
961  * We assume any normal dependency from a constraint must be what we
962  * are looking for.
963  */
964  if (deprec->classid == ConstraintRelationId &&
965  deprec->objsubid == 0 &&
966  deprec->deptype == DEPENDENCY_NORMAL)
967  {
968  result = lappend_oid(result, deprec->objid);
969  }
970  }
971 
972  systable_endscan(scan);
973  table_close(depRel, AccessShareLock);
974 
975  return result;
976 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
Oid CurrentExtensionObject
Definition: extension.c:71
#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:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:663
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define DependReferenceIndexId
Definition: indexing.h:151
char * get_extension_name(Oid ext_oid)
Definition: extension.c:183
#define DependDependerIndexId
Definition: indexing.h:149
static List * getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
Definition: pg_depend.c:712
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:570
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:780
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
#define OidIsValid(objectId)
Definition: c.h:638
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
char * getObjectDescription(const ObjectAddress *object)
char relkind
Definition: pg_class.h:81
signed int int32
Definition: c.h:346
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
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:873
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
#define ereport(elevel, rest)
Definition: elog.h:141
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:771
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:84
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:70
int16 attnum
Definition: pg_attribute.h:79
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
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:929
#define CharGetDatum(X)
Definition: postgres.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:374
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:784
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:297
#define elog(elevel,...)
Definition: elog.h:226
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:806
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
int16 AttrNumber
Definition: attnum.h:21
#define BTEqualStrategyNumber
Definition: stratnum.h:31