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