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  * deleteDependencyRecordsForSpecific -- delete all records with given depender
283  * classId/objectId, dependee classId/objectId, of the given deptype.
284  * Returns the number of records deleted.
285  */
286 long
287 deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
288  Oid refclassId, Oid refobjectId)
289 {
290  long count = 0;
291  Relation depRel;
292  ScanKeyData key[2];
293  SysScanDesc scan;
294  HeapTuple tup;
295 
296  depRel = table_open(DependRelationId, RowExclusiveLock);
297 
298  ScanKeyInit(&key[0],
299  Anum_pg_depend_classid,
300  BTEqualStrategyNumber, F_OIDEQ,
301  ObjectIdGetDatum(classId));
302  ScanKeyInit(&key[1],
303  Anum_pg_depend_objid,
304  BTEqualStrategyNumber, F_OIDEQ,
305  ObjectIdGetDatum(objectId));
306 
307  scan = systable_beginscan(depRel, DependDependerIndexId, true,
308  NULL, 2, key);
309 
310  while (HeapTupleIsValid(tup = systable_getnext(scan)))
311  {
312  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
313 
314  if (depform->refclassid == refclassId &&
315  depform->refobjid == refobjectId &&
316  depform->deptype == deptype)
317  {
318  CatalogTupleDelete(depRel, &tup->t_self);
319  count++;
320  }
321  }
322 
323  systable_endscan(scan);
324 
325  table_close(depRel, RowExclusiveLock);
326 
327  return count;
328 }
329 
330 /*
331  * Adjust dependency record(s) to point to a different object of the same type
332  *
333  * classId/objectId specify the referencing object.
334  * refClassId/oldRefObjectId specify the old referenced object.
335  * newRefObjectId is the new referenced object (must be of class refClassId).
336  *
337  * Note the lack of objsubid parameters. If there are subobject references
338  * they will all be readjusted. Also, there is an expectation that we are
339  * dealing with NORMAL dependencies: if we have to replace an (implicit)
340  * dependency on a pinned object with an explicit dependency on an unpinned
341  * one, the new one will be NORMAL.
342  *
343  * Returns the number of records updated -- zero indicates a problem.
344  */
345 long
346 changeDependencyFor(Oid classId, Oid objectId,
347  Oid refClassId, Oid oldRefObjectId,
348  Oid newRefObjectId)
349 {
350  long count = 0;
351  Relation depRel;
352  ScanKeyData key[2];
353  SysScanDesc scan;
354  HeapTuple tup;
355  ObjectAddress objAddr;
356  ObjectAddress depAddr;
357  bool oldIsPinned;
358  bool newIsPinned;
359 
360  depRel = table_open(DependRelationId, RowExclusiveLock);
361 
362  /*
363  * Check to see if either oldRefObjectId or newRefObjectId is pinned.
364  * Pinned objects should not have any dependency entries pointing to them,
365  * so in these cases we should add or remove a pg_depend entry, or do
366  * nothing at all, rather than update an entry as in the normal case.
367  */
368  objAddr.classId = refClassId;
369  objAddr.objectId = oldRefObjectId;
370  objAddr.objectSubId = 0;
371 
372  oldIsPinned = isObjectPinned(&objAddr, depRel);
373 
374  objAddr.objectId = newRefObjectId;
375 
376  newIsPinned = isObjectPinned(&objAddr, depRel);
377 
378  if (oldIsPinned)
379  {
380  table_close(depRel, RowExclusiveLock);
381 
382  /*
383  * If both are pinned, we need do nothing. However, return 1 not 0,
384  * else callers will think this is an error case.
385  */
386  if (newIsPinned)
387  return 1;
388 
389  /*
390  * There is no old dependency record, but we should insert a new one.
391  * Assume a normal dependency is wanted.
392  */
393  depAddr.classId = classId;
394  depAddr.objectId = objectId;
395  depAddr.objectSubId = 0;
396  recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
397 
398  return 1;
399  }
400 
401  /* There should be existing dependency record(s), so search. */
402  ScanKeyInit(&key[0],
403  Anum_pg_depend_classid,
404  BTEqualStrategyNumber, F_OIDEQ,
405  ObjectIdGetDatum(classId));
406  ScanKeyInit(&key[1],
407  Anum_pg_depend_objid,
408  BTEqualStrategyNumber, F_OIDEQ,
409  ObjectIdGetDatum(objectId));
410 
411  scan = systable_beginscan(depRel, DependDependerIndexId, true,
412  NULL, 2, key);
413 
414  while (HeapTupleIsValid((tup = systable_getnext(scan))))
415  {
416  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
417 
418  if (depform->refclassid == refClassId &&
419  depform->refobjid == oldRefObjectId)
420  {
421  if (newIsPinned)
422  CatalogTupleDelete(depRel, &tup->t_self);
423  else
424  {
425  /* make a modifiable copy */
426  tup = heap_copytuple(tup);
427  depform = (Form_pg_depend) GETSTRUCT(tup);
428 
429  depform->refobjid = newRefObjectId;
430 
431  CatalogTupleUpdate(depRel, &tup->t_self, tup);
432 
433  heap_freetuple(tup);
434  }
435 
436  count++;
437  }
438  }
439 
440  systable_endscan(scan);
441 
442  table_close(depRel, RowExclusiveLock);
443 
444  return count;
445 }
446 
447 /*
448  * Adjust all dependency records to come from a different object of the same type
449  *
450  * classId/oldObjectId specify the old referencing object.
451  * newObjectId is the new referencing object (must be of class classId).
452  *
453  * Returns the number of records updated.
454  */
455 long
456 changeDependenciesOf(Oid classId, Oid oldObjectId,
457  Oid newObjectId)
458 {
459  long count = 0;
460  Relation depRel;
461  ScanKeyData key[2];
462  SysScanDesc scan;
463  HeapTuple tup;
464 
465  depRel = table_open(DependRelationId, RowExclusiveLock);
466 
467  ScanKeyInit(&key[0],
468  Anum_pg_depend_classid,
469  BTEqualStrategyNumber, F_OIDEQ,
470  ObjectIdGetDatum(classId));
471  ScanKeyInit(&key[1],
472  Anum_pg_depend_objid,
473  BTEqualStrategyNumber, F_OIDEQ,
474  ObjectIdGetDatum(oldObjectId));
475 
476  scan = systable_beginscan(depRel, DependDependerIndexId, true,
477  NULL, 2, key);
478 
479  while (HeapTupleIsValid((tup = systable_getnext(scan))))
480  {
481  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
482 
483  /* make a modifiable copy */
484  tup = heap_copytuple(tup);
485  depform = (Form_pg_depend) GETSTRUCT(tup);
486 
487  depform->objid = newObjectId;
488 
489  CatalogTupleUpdate(depRel, &tup->t_self, tup);
490 
491  heap_freetuple(tup);
492 
493  count++;
494  }
495 
496  systable_endscan(scan);
497 
498  table_close(depRel, RowExclusiveLock);
499 
500  return count;
501 }
502 
503 /*
504  * Adjust all dependency records to point to a different object of the same type
505  *
506  * refClassId/oldRefObjectId specify the old referenced object.
507  * newRefObjectId is the new referenced object (must be of class refClassId).
508  *
509  * Returns the number of records updated.
510  */
511 long
512 changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
513  Oid newRefObjectId)
514 {
515  long count = 0;
516  Relation depRel;
517  ScanKeyData key[2];
518  SysScanDesc scan;
519  HeapTuple tup;
520  ObjectAddress objAddr;
521  bool newIsPinned;
522 
523  depRel = table_open(DependRelationId, RowExclusiveLock);
524 
525  /*
526  * If oldRefObjectId is pinned, there won't be any dependency entries on
527  * it --- we can't cope in that case. (This isn't really worth expending
528  * code to fix, in current usage; it just means you can't rename stuff out
529  * of pg_catalog, which would likely be a bad move anyway.)
530  */
531  objAddr.classId = refClassId;
532  objAddr.objectId = oldRefObjectId;
533  objAddr.objectSubId = 0;
534 
535  if (isObjectPinned(&objAddr, depRel))
536  ereport(ERROR,
537  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
538  errmsg("cannot remove dependency on %s because it is a system object",
539  getObjectDescription(&objAddr))));
540 
541  /*
542  * We can handle adding a dependency on something pinned, though, since
543  * that just means deleting the dependency entry.
544  */
545  objAddr.objectId = newRefObjectId;
546 
547  newIsPinned = isObjectPinned(&objAddr, depRel);
548 
549  /* Now search for dependency records */
550  ScanKeyInit(&key[0],
551  Anum_pg_depend_refclassid,
552  BTEqualStrategyNumber, F_OIDEQ,
553  ObjectIdGetDatum(refClassId));
554  ScanKeyInit(&key[1],
555  Anum_pg_depend_refobjid,
556  BTEqualStrategyNumber, F_OIDEQ,
557  ObjectIdGetDatum(oldRefObjectId));
558 
559  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
560  NULL, 2, key);
561 
562  while (HeapTupleIsValid((tup = systable_getnext(scan))))
563  {
564  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
565 
566  if (newIsPinned)
567  CatalogTupleDelete(depRel, &tup->t_self);
568  else
569  {
570  /* make a modifiable copy */
571  tup = heap_copytuple(tup);
572  depform = (Form_pg_depend) GETSTRUCT(tup);
573 
574  depform->refobjid = newRefObjectId;
575 
576  CatalogTupleUpdate(depRel, &tup->t_self, tup);
577 
578  heap_freetuple(tup);
579  }
580 
581  count++;
582  }
583 
584  systable_endscan(scan);
585 
586  table_close(depRel, RowExclusiveLock);
587 
588  return count;
589 }
590 
591 /*
592  * isObjectPinned()
593  *
594  * Test if an object is required for basic database functionality.
595  * Caller must already have opened pg_depend.
596  *
597  * The passed subId, if any, is ignored; we assume that only whole objects
598  * are pinned (and that this implies pinning their components).
599  */
600 static bool
602 {
603  bool ret = false;
604  SysScanDesc scan;
605  HeapTuple tup;
606  ScanKeyData key[2];
607 
608  ScanKeyInit(&key[0],
609  Anum_pg_depend_refclassid,
610  BTEqualStrategyNumber, F_OIDEQ,
611  ObjectIdGetDatum(object->classId));
612 
613  ScanKeyInit(&key[1],
614  Anum_pg_depend_refobjid,
615  BTEqualStrategyNumber, F_OIDEQ,
616  ObjectIdGetDatum(object->objectId));
617 
618  scan = systable_beginscan(rel, DependReferenceIndexId, true,
619  NULL, 2, key);
620 
621  /*
622  * Since we won't generate additional pg_depend entries for pinned
623  * objects, there can be at most one entry referencing a pinned object.
624  * Hence, it's sufficient to look at the first returned tuple; we don't
625  * need to loop.
626  */
627  tup = systable_getnext(scan);
628  if (HeapTupleIsValid(tup))
629  {
630  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
631 
632  if (foundDep->deptype == DEPENDENCY_PIN)
633  ret = true;
634  }
635 
636  systable_endscan(scan);
637 
638  return ret;
639 }
640 
641 
642 /*
643  * Various special-purpose lookups and manipulations of pg_depend.
644  */
645 
646 
647 /*
648  * Find the extension containing the specified object, if any
649  *
650  * Returns the OID of the extension, or InvalidOid if the object does not
651  * belong to any extension.
652  *
653  * Extension membership is marked by an EXTENSION dependency from the object
654  * to the extension. Note that the result will be indeterminate if pg_depend
655  * contains links from this object to more than one extension ... but that
656  * should never happen.
657  */
658 Oid
659 getExtensionOfObject(Oid classId, Oid objectId)
660 {
661  Oid result = InvalidOid;
662  Relation depRel;
663  ScanKeyData key[2];
664  SysScanDesc scan;
665  HeapTuple tup;
666 
667  depRel = table_open(DependRelationId, AccessShareLock);
668 
669  ScanKeyInit(&key[0],
670  Anum_pg_depend_classid,
671  BTEqualStrategyNumber, F_OIDEQ,
672  ObjectIdGetDatum(classId));
673  ScanKeyInit(&key[1],
674  Anum_pg_depend_objid,
675  BTEqualStrategyNumber, F_OIDEQ,
676  ObjectIdGetDatum(objectId));
677 
678  scan = systable_beginscan(depRel, DependDependerIndexId, true,
679  NULL, 2, key);
680 
681  while (HeapTupleIsValid((tup = systable_getnext(scan))))
682  {
683  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
684 
685  if (depform->refclassid == ExtensionRelationId &&
686  depform->deptype == DEPENDENCY_EXTENSION)
687  {
688  result = depform->refobjid;
689  break; /* no need to keep scanning */
690  }
691  }
692 
693  systable_endscan(scan);
694 
695  table_close(depRel, AccessShareLock);
696 
697  return result;
698 }
699 
700 /*
701  * Return (possibly NIL) list of extensions that the given object depends on
702  * in DEPENDENCY_AUTO_EXTENSION mode.
703  */
704 List *
706 {
707  List *result = NIL;
708  Relation depRel;
709  ScanKeyData key[2];
710  SysScanDesc scan;
711  HeapTuple tup;
712 
713  depRel = table_open(DependRelationId, AccessShareLock);
714 
715  ScanKeyInit(&key[0],
716  Anum_pg_depend_classid,
717  BTEqualStrategyNumber, F_OIDEQ,
718  ObjectIdGetDatum(classId));
719  ScanKeyInit(&key[1],
720  Anum_pg_depend_objid,
721  BTEqualStrategyNumber, F_OIDEQ,
722  ObjectIdGetDatum(objectId));
723 
724  scan = systable_beginscan(depRel, DependDependerIndexId, true,
725  NULL, 2, key);
726 
727  while (HeapTupleIsValid((tup = systable_getnext(scan))))
728  {
729  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
730 
731  if (depform->refclassid == ExtensionRelationId &&
732  depform->deptype == DEPENDENCY_AUTO_EXTENSION)
733  result = lappend_oid(result, depform->refobjid);
734  }
735 
736  systable_endscan(scan);
737 
738  table_close(depRel, AccessShareLock);
739 
740  return result;
741 }
742 
743 /*
744  * Detect whether a sequence is marked as "owned" by a column
745  *
746  * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
747  * column. If we find one, store the identity of the owning column
748  * into *tableId and *colId and return true; else return false.
749  *
750  * Note: if there's more than one such pg_depend entry then you get
751  * a random one of them returned into the out parameters. This should
752  * not happen, though.
753  */
754 bool
755 sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
756 {
757  bool ret = false;
758  Relation depRel;
759  ScanKeyData key[2];
760  SysScanDesc scan;
761  HeapTuple tup;
762 
763  depRel = table_open(DependRelationId, AccessShareLock);
764 
765  ScanKeyInit(&key[0],
766  Anum_pg_depend_classid,
767  BTEqualStrategyNumber, F_OIDEQ,
768  ObjectIdGetDatum(RelationRelationId));
769  ScanKeyInit(&key[1],
770  Anum_pg_depend_objid,
771  BTEqualStrategyNumber, F_OIDEQ,
772  ObjectIdGetDatum(seqId));
773 
774  scan = systable_beginscan(depRel, DependDependerIndexId, true,
775  NULL, 2, key);
776 
777  while (HeapTupleIsValid((tup = systable_getnext(scan))))
778  {
779  Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
780 
781  if (depform->refclassid == RelationRelationId &&
782  depform->deptype == deptype)
783  {
784  *tableId = depform->refobjid;
785  *colId = depform->refobjsubid;
786  ret = true;
787  break; /* no need to keep scanning */
788  }
789  }
790 
791  systable_endscan(scan);
792 
793  table_close(depRel, AccessShareLock);
794 
795  return ret;
796 }
797 
798 /*
799  * Collect a list of OIDs of all sequences owned by the specified relation,
800  * and column if specified. If deptype is not zero, then only find sequences
801  * with the specified dependency type.
802  */
803 static List *
805 {
806  List *result = NIL;
807  Relation depRel;
808  ScanKeyData key[3];
809  SysScanDesc scan;
810  HeapTuple tup;
811 
812  depRel = table_open(DependRelationId, AccessShareLock);
813 
814  ScanKeyInit(&key[0],
815  Anum_pg_depend_refclassid,
816  BTEqualStrategyNumber, F_OIDEQ,
817  ObjectIdGetDatum(RelationRelationId));
818  ScanKeyInit(&key[1],
819  Anum_pg_depend_refobjid,
820  BTEqualStrategyNumber, F_OIDEQ,
821  ObjectIdGetDatum(relid));
822  if (attnum)
823  ScanKeyInit(&key[2],
824  Anum_pg_depend_refobjsubid,
825  BTEqualStrategyNumber, F_INT4EQ,
826  Int32GetDatum(attnum));
827 
828  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
829  NULL, attnum ? 3 : 2, key);
830 
831  while (HeapTupleIsValid(tup = systable_getnext(scan)))
832  {
833  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
834 
835  /*
836  * We assume any auto or internal dependency of a sequence on a column
837  * must be what we are looking for. (We need the relkind test because
838  * indexes can also have auto dependencies on columns.)
839  */
840  if (deprec->classid == RelationRelationId &&
841  deprec->objsubid == 0 &&
842  deprec->refobjsubid != 0 &&
843  (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
844  get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
845  {
846  if (!deptype || deprec->deptype == deptype)
847  result = lappend_oid(result, deprec->objid);
848  }
849  }
850 
851  systable_endscan(scan);
852 
853  table_close(depRel, AccessShareLock);
854 
855  return result;
856 }
857 
858 /*
859  * Collect a list of OIDs of all sequences owned (identity or serial) by the
860  * specified relation.
861  */
862 List *
864 {
865  return getOwnedSequences_internal(relid, 0, 0);
866 }
867 
868 /*
869  * Get owned identity sequence, error if not exactly one.
870  */
871 Oid
872 getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
873 {
874  List *seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
875 
876  if (list_length(seqlist) > 1)
877  elog(ERROR, "more than one owned sequence found");
878  else if (list_length(seqlist) < 1)
879  {
880  if (missing_ok)
881  return InvalidOid;
882  else
883  elog(ERROR, "no owned sequence found");
884  }
885 
886  return linitial_oid(seqlist);
887 }
888 
889 /*
890  * get_constraint_index
891  * Given the OID of a unique, primary-key, or exclusion constraint,
892  * return the OID of the underlying index.
893  *
894  * Return InvalidOid if the index couldn't be found; this suggests the
895  * given OID is bogus, but we leave it to caller to decide what to do.
896  */
897 Oid
899 {
900  Oid indexId = InvalidOid;
901  Relation depRel;
902  ScanKeyData key[3];
903  SysScanDesc scan;
904  HeapTuple tup;
905 
906  /* Search the dependency table for the dependent index */
907  depRel = table_open(DependRelationId, AccessShareLock);
908 
909  ScanKeyInit(&key[0],
910  Anum_pg_depend_refclassid,
911  BTEqualStrategyNumber, F_OIDEQ,
912  ObjectIdGetDatum(ConstraintRelationId));
913  ScanKeyInit(&key[1],
914  Anum_pg_depend_refobjid,
915  BTEqualStrategyNumber, F_OIDEQ,
916  ObjectIdGetDatum(constraintId));
917  ScanKeyInit(&key[2],
918  Anum_pg_depend_refobjsubid,
919  BTEqualStrategyNumber, F_INT4EQ,
920  Int32GetDatum(0));
921 
922  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
923  NULL, 3, key);
924 
925  while (HeapTupleIsValid(tup = systable_getnext(scan)))
926  {
927  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
928 
929  /*
930  * We assume any internal dependency of an index on the constraint
931  * must be what we are looking for.
932  */
933  if (deprec->classid == RelationRelationId &&
934  deprec->objsubid == 0 &&
935  deprec->deptype == DEPENDENCY_INTERNAL)
936  {
937  char relkind = get_rel_relkind(deprec->objid);
938 
939  /*
940  * This is pure paranoia; there shouldn't be any other relkinds
941  * dependent on a constraint.
942  */
943  if (relkind != RELKIND_INDEX &&
944  relkind != RELKIND_PARTITIONED_INDEX)
945  continue;
946 
947  indexId = deprec->objid;
948  break;
949  }
950  }
951 
952  systable_endscan(scan);
953  table_close(depRel, AccessShareLock);
954 
955  return indexId;
956 }
957 
958 /*
959  * get_index_constraint
960  * Given the OID of an index, return the OID of the owning unique,
961  * primary-key, or exclusion constraint, or InvalidOid if there
962  * is no owning constraint.
963  */
964 Oid
966 {
967  Oid constraintId = InvalidOid;
968  Relation depRel;
969  ScanKeyData key[3];
970  SysScanDesc scan;
971  HeapTuple tup;
972 
973  /* Search the dependency table for the index */
974  depRel = table_open(DependRelationId, AccessShareLock);
975 
976  ScanKeyInit(&key[0],
977  Anum_pg_depend_classid,
978  BTEqualStrategyNumber, F_OIDEQ,
979  ObjectIdGetDatum(RelationRelationId));
980  ScanKeyInit(&key[1],
981  Anum_pg_depend_objid,
982  BTEqualStrategyNumber, F_OIDEQ,
983  ObjectIdGetDatum(indexId));
984  ScanKeyInit(&key[2],
985  Anum_pg_depend_objsubid,
986  BTEqualStrategyNumber, F_INT4EQ,
987  Int32GetDatum(0));
988 
989  scan = systable_beginscan(depRel, DependDependerIndexId, true,
990  NULL, 3, key);
991 
992  while (HeapTupleIsValid(tup = systable_getnext(scan)))
993  {
994  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
995 
996  /*
997  * We assume any internal dependency on a constraint must be what we
998  * are looking for.
999  */
1000  if (deprec->refclassid == ConstraintRelationId &&
1001  deprec->refobjsubid == 0 &&
1002  deprec->deptype == DEPENDENCY_INTERNAL)
1003  {
1004  constraintId = deprec->refobjid;
1005  break;
1006  }
1007  }
1008 
1009  systable_endscan(scan);
1010  table_close(depRel, AccessShareLock);
1011 
1012  return constraintId;
1013 }
1014 
1015 /*
1016  * get_index_ref_constraints
1017  * Given the OID of an index, return the OID of all foreign key
1018  * constraints which reference the index.
1019  */
1020 List *
1022 {
1023  List *result = NIL;
1024  Relation depRel;
1025  ScanKeyData key[3];
1026  SysScanDesc scan;
1027  HeapTuple tup;
1028 
1029  /* Search the dependency table for the index */
1030  depRel = table_open(DependRelationId, AccessShareLock);
1031 
1032  ScanKeyInit(&key[0],
1033  Anum_pg_depend_refclassid,
1034  BTEqualStrategyNumber, F_OIDEQ,
1035  ObjectIdGetDatum(RelationRelationId));
1036  ScanKeyInit(&key[1],
1037  Anum_pg_depend_refobjid,
1038  BTEqualStrategyNumber, F_OIDEQ,
1039  ObjectIdGetDatum(indexId));
1040  ScanKeyInit(&key[2],
1041  Anum_pg_depend_refobjsubid,
1042  BTEqualStrategyNumber, F_INT4EQ,
1043  Int32GetDatum(0));
1044 
1045  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
1046  NULL, 3, key);
1047 
1048  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1049  {
1050  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
1051 
1052  /*
1053  * We assume any normal dependency from a constraint must be what we
1054  * are looking for.
1055  */
1056  if (deprec->classid == ConstraintRelationId &&
1057  deprec->objsubid == 0 &&
1058  deprec->deptype == DEPENDENCY_NORMAL)
1059  {
1060  result = lappend_oid(result, deprec->objid);
1061  }
1062  }
1063 
1064  systable_endscan(scan);
1065  table_close(depRel, AccessShareLock);
1066 
1067  return result;
1068 }
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:659
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:755
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1915
#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:804
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:872
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
#define OidIsValid(objectId)
Definition: c.h:644
long deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype, Oid refclassId, Oid refobjectId)
Definition: pg_depend.c:287
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:601
#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:965
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:863
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:456
#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:1021
#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:346
#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:898
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:512
List * getAutoExtensionsOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:705
int16 AttrNumber
Definition: attnum.h:21
#define BTEqualStrategyNumber
Definition: stratnum.h:31