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