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