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