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