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