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