1 /*-------------------------------------------------------------------------
2 *
3 * pg_depend.c
4 * routines to support manipulation of the pg_depend relation
5 *
6 * Portions Copyright (c) 1996-2018, 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/heapam.h"
19 #include "access/htup_details.h"
20 #include "catalog/dependency.h"
21 #include "catalog/indexing.h"
22 #include "catalog/pg_constraint.h"
23 #include "catalog/pg_depend.h"
24 #include "catalog/pg_extension.h"
25 #include "commands/extension.h"
26 #include "miscadmin.h"
27 #include "utils/fmgroids.h"
28 #include "utils/lsyscache.h"
29 #include "utils/rel.h"
30 #include "utils/tqual.h"
31
32
33 static bool isObjectPinned(const ObjectAddress *object, Relation rel);
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
recordDependencyOn(const ObjectAddress * depender,const ObjectAddress * referenced,DependencyType behavior)44 recordDependencyOn(const ObjectAddress *depender,
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
recordMultipleDependencies(const ObjectAddress * depender,const ObjectAddress * referenced,int nreferenced,DependencyType behavior)56 recordMultipleDependencies(const ObjectAddress *depender,
57 const ObjectAddress *referenced,
58 int nreferenced,
59 DependencyType behavior)
60 {
61 Relation dependDesc;
62 CatalogIndexState indstate;
63 HeapTuple tup;
64 int i;
65 bool nulls[Natts_pg_depend];
66 Datum values[Natts_pg_depend];
67
68 if (nreferenced <= 0)
69 return; /* nothing to do */
70
71 /*
72 * During bootstrap, do nothing since pg_depend may not exist yet. initdb
73 * will fill in appropriate pg_depend entries after bootstrap.
74 */
75 if (IsBootstrapProcessingMode())
76 return;
77
78 dependDesc = heap_open(DependRelationId, RowExclusiveLock);
79
80 /* Don't open indexes unless we need to make an update */
81 indstate = NULL;
82
83 memset(nulls, false, sizeof(nulls));
84
85 for (i = 0; i < nreferenced; i++, referenced++)
86 {
87 /*
88 * If the referenced object is pinned by the system, there's no real
89 * need to record dependencies on it. This saves lots of space in
90 * pg_depend, so it's worth the time taken to check.
91 */
92 if (!isObjectPinned(referenced, dependDesc))
93 {
94 /*
95 * Record the Dependency. Note we don't bother to check for
96 * duplicate dependencies; there's no harm in them.
97 */
98 values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
99 values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
100 values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
101
102 values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
103 values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
104 values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
105
106 values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
107
108 tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
109
110 /* fetch index info only when we know we need it */
111 if (indstate == NULL)
112 indstate = CatalogOpenIndexes(dependDesc);
113
114 CatalogTupleInsertWithInfo(dependDesc, tup, indstate);
115
116 heap_freetuple(tup);
117 }
118 }
119
120 if (indstate != NULL)
121 CatalogCloseIndexes(indstate);
122
123 heap_close(dependDesc, RowExclusiveLock);
124 }
125
126 /*
127 * If we are executing a CREATE EXTENSION operation, mark the given object
128 * as being a member of the extension. Otherwise, do nothing.
129 *
130 * This must be called during creation of any user-definable object type
131 * that could be a member of an extension.
132 *
133 * If isReplace is true, the object already existed (or might have already
134 * existed), so we must check for a pre-existing extension membership entry.
135 * Passing false is a guarantee that the object is newly created, and so
136 * could not already be a member of any extension.
137 */
138 void
recordDependencyOnCurrentExtension(const ObjectAddress * object,bool isReplace)139 recordDependencyOnCurrentExtension(const ObjectAddress *object,
140 bool isReplace)
141 {
142 /* Only whole objects can be extension members */
143 Assert(object->objectSubId == 0);
144
145 if (creating_extension)
146 {
147 ObjectAddress extension;
148
149 /* Only need to check for existing membership if isReplace */
150 if (isReplace)
151 {
152 Oid oldext;
153
154 oldext = getExtensionOfObject(object->classId, object->objectId);
155 if (OidIsValid(oldext))
156 {
157 /* If already a member of this extension, nothing to do */
158 if (oldext == CurrentExtensionObject)
159 return;
160 /* Already a member of some other extension, so reject */
161 ereport(ERROR,
162 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
163 errmsg("%s is already a member of extension \"%s\"",
164 getObjectDescription(object),
165 get_extension_name(oldext))));
166 }
167 }
168
169 /* OK, record it as a member of CurrentExtensionObject */
170 extension.classId = ExtensionRelationId;
171 extension.objectId = CurrentExtensionObject;
172 extension.objectSubId = 0;
173
174 recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
175 }
176 }
177
178 /*
179 * deleteDependencyRecordsFor -- delete all records with given depender
180 * classId/objectId. Returns the number of records deleted.
181 *
182 * This is used when redefining an existing object. Links leading to the
183 * object do not change, and links leading from it will be recreated
184 * (possibly with some differences from before).
185 *
186 * If skipExtensionDeps is true, we do not delete any dependencies that
187 * show that the given object is a member of an extension. This avoids
188 * needing a lot of extra logic to fetch and recreate that dependency.
189 */
190 long
deleteDependencyRecordsFor(Oid classId,Oid objectId,bool skipExtensionDeps)191 deleteDependencyRecordsFor(Oid classId, Oid objectId,
192 bool skipExtensionDeps)
193 {
194 long count = 0;
195 Relation depRel;
196 ScanKeyData key[2];
197 SysScanDesc scan;
198 HeapTuple tup;
199
200 depRel = heap_open(DependRelationId, RowExclusiveLock);
201
202 ScanKeyInit(&key[0],
203 Anum_pg_depend_classid,
204 BTEqualStrategyNumber, F_OIDEQ,
205 ObjectIdGetDatum(classId));
206 ScanKeyInit(&key[1],
207 Anum_pg_depend_objid,
208 BTEqualStrategyNumber, F_OIDEQ,
209 ObjectIdGetDatum(objectId));
210
211 scan = systable_beginscan(depRel, DependDependerIndexId, true,
212 NULL, 2, key);
213
214 while (HeapTupleIsValid(tup = systable_getnext(scan)))
215 {
216 if (skipExtensionDeps &&
217 ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
218 continue;
219
220 CatalogTupleDelete(depRel, &tup->t_self);
221 count++;
222 }
223
224 systable_endscan(scan);
225
226 heap_close(depRel, RowExclusiveLock);
227
228 return count;
229 }
230
231 /*
232 * deleteDependencyRecordsForClass -- delete all records with given depender
233 * classId/objectId, dependee classId, and deptype.
234 * Returns the number of records deleted.
235 *
236 * This is a variant of deleteDependencyRecordsFor, useful when revoking
237 * an object property that is expressed by a dependency record (such as
238 * extension membership).
239 */
240 long
deleteDependencyRecordsForClass(Oid classId,Oid objectId,Oid refclassId,char deptype)241 deleteDependencyRecordsForClass(Oid classId, Oid objectId,
242 Oid refclassId, char deptype)
243 {
244 long count = 0;
245 Relation depRel;
246 ScanKeyData key[2];
247 SysScanDesc scan;
248 HeapTuple tup;
249
250 depRel = heap_open(DependRelationId, RowExclusiveLock);
251
252 ScanKeyInit(&key[0],
253 Anum_pg_depend_classid,
254 BTEqualStrategyNumber, F_OIDEQ,
255 ObjectIdGetDatum(classId));
256 ScanKeyInit(&key[1],
257 Anum_pg_depend_objid,
258 BTEqualStrategyNumber, F_OIDEQ,
259 ObjectIdGetDatum(objectId));
260
261 scan = systable_beginscan(depRel, DependDependerIndexId, true,
262 NULL, 2, key);
263
264 while (HeapTupleIsValid(tup = systable_getnext(scan)))
265 {
266 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
267
268 if (depform->refclassid == refclassId && depform->deptype == deptype)
269 {
270 CatalogTupleDelete(depRel, &tup->t_self);
271 count++;
272 }
273 }
274
275 systable_endscan(scan);
276
277 heap_close(depRel, RowExclusiveLock);
278
279 return count;
280 }
281
282 /*
283 * Adjust dependency record(s) to point to a different object of the same type
284 *
285 * classId/objectId specify the referencing object.
286 * refClassId/oldRefObjectId specify the old referenced object.
287 * newRefObjectId is the new referenced object (must be of class refClassId).
288 *
289 * Note the lack of objsubid parameters. If there are subobject references
290 * they will all be readjusted.
291 *
292 * Returns the number of records updated.
293 */
294 long
changeDependencyFor(Oid classId,Oid objectId,Oid refClassId,Oid oldRefObjectId,Oid newRefObjectId)295 changeDependencyFor(Oid classId, Oid objectId,
296 Oid refClassId, Oid oldRefObjectId,
297 Oid newRefObjectId)
298 {
299 long count = 0;
300 Relation depRel;
301 ScanKeyData key[2];
302 SysScanDesc scan;
303 HeapTuple tup;
304 ObjectAddress objAddr;
305 bool newIsPinned;
306
307 depRel = heap_open(DependRelationId, RowExclusiveLock);
308
309 /*
310 * If oldRefObjectId is pinned, there won't be any dependency entries on
311 * it --- we can't cope in that case. (This isn't really worth expending
312 * code to fix, in current usage; it just means you can't rename stuff out
313 * of pg_catalog, which would likely be a bad move anyway.)
314 */
315 objAddr.classId = refClassId;
316 objAddr.objectId = oldRefObjectId;
317 objAddr.objectSubId = 0;
318
319 if (isObjectPinned(&objAddr, depRel))
320 ereport(ERROR,
321 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
322 errmsg("cannot remove dependency on %s because it is a system object",
323 getObjectDescription(&objAddr))));
324
325 /*
326 * We can handle adding a dependency on something pinned, though, since
327 * that just means deleting the dependency entry.
328 */
329 objAddr.objectId = newRefObjectId;
330
331 newIsPinned = isObjectPinned(&objAddr, depRel);
332
333 /* Now search for dependency records */
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 &&
351 depform->refobjid == oldRefObjectId)
352 {
353 if (newIsPinned)
354 CatalogTupleDelete(depRel, &tup->t_self);
355 else
356 {
357 /* make a modifiable copy */
358 tup = heap_copytuple(tup);
359 depform = (Form_pg_depend) GETSTRUCT(tup);
360
361 depform->refobjid = newRefObjectId;
362
363 CatalogTupleUpdate(depRel, &tup->t_self, tup);
364
365 heap_freetuple(tup);
366 }
367
368 count++;
369 }
370 }
371
372 systable_endscan(scan);
373
374 heap_close(depRel, RowExclusiveLock);
375
376 return count;
377 }
378
379 /*
380 * isObjectPinned()
381 *
382 * Test if an object is required for basic database functionality.
383 * Caller must already have opened pg_depend.
384 *
385 * The passed subId, if any, is ignored; we assume that only whole objects
386 * are pinned (and that this implies pinning their components).
387 */
388 static bool
isObjectPinned(const ObjectAddress * object,Relation rel)389 isObjectPinned(const ObjectAddress *object, Relation rel)
390 {
391 bool ret = false;
392 SysScanDesc scan;
393 HeapTuple tup;
394 ScanKeyData key[2];
395
396 ScanKeyInit(&key[0],
397 Anum_pg_depend_refclassid,
398 BTEqualStrategyNumber, F_OIDEQ,
399 ObjectIdGetDatum(object->classId));
400
401 ScanKeyInit(&key[1],
402 Anum_pg_depend_refobjid,
403 BTEqualStrategyNumber, F_OIDEQ,
404 ObjectIdGetDatum(object->objectId));
405
406 scan = systable_beginscan(rel, DependReferenceIndexId, true,
407 NULL, 2, key);
408
409 /*
410 * Since we won't generate additional pg_depend entries for pinned
411 * objects, there can be at most one entry referencing a pinned object.
412 * Hence, it's sufficient to look at the first returned tuple; we don't
413 * need to loop.
414 */
415 tup = systable_getnext(scan);
416 if (HeapTupleIsValid(tup))
417 {
418 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
419
420 if (foundDep->deptype == DEPENDENCY_PIN)
421 ret = true;
422 }
423
424 systable_endscan(scan);
425
426 return ret;
427 }
428
429
430 /*
431 * Various special-purpose lookups and manipulations of pg_depend.
432 */
433
434
435 /*
436 * Find the extension containing the specified object, if any
437 *
438 * Returns the OID of the extension, or InvalidOid if the object does not
439 * belong to any extension.
440 *
441 * Extension membership is marked by an EXTENSION dependency from the object
442 * to the extension. Note that the result will be indeterminate if pg_depend
443 * contains links from this object to more than one extension ... but that
444 * should never happen.
445 */
446 Oid
getExtensionOfObject(Oid classId,Oid objectId)447 getExtensionOfObject(Oid classId, Oid objectId)
448 {
449 Oid result = InvalidOid;
450 Relation depRel;
451 ScanKeyData key[2];
452 SysScanDesc scan;
453 HeapTuple tup;
454
455 depRel = heap_open(DependRelationId, AccessShareLock);
456
457 ScanKeyInit(&key[0],
458 Anum_pg_depend_classid,
459 BTEqualStrategyNumber, F_OIDEQ,
460 ObjectIdGetDatum(classId));
461 ScanKeyInit(&key[1],
462 Anum_pg_depend_objid,
463 BTEqualStrategyNumber, F_OIDEQ,
464 ObjectIdGetDatum(objectId));
465
466 scan = systable_beginscan(depRel, DependDependerIndexId, true,
467 NULL, 2, key);
468
469 while (HeapTupleIsValid((tup = systable_getnext(scan))))
470 {
471 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
472
473 if (depform->refclassid == ExtensionRelationId &&
474 depform->deptype == DEPENDENCY_EXTENSION)
475 {
476 result = depform->refobjid;
477 break; /* no need to keep scanning */
478 }
479 }
480
481 systable_endscan(scan);
482
483 heap_close(depRel, AccessShareLock);
484
485 return result;
486 }
487
488 /*
489 * Return (possibly NIL) list of extensions that the given object depends on
490 * in DEPENDENCY_AUTO_EXTENSION mode.
491 */
492 List *
getAutoExtensionsOfObject(Oid classId,Oid objectId)493 getAutoExtensionsOfObject(Oid classId, Oid objectId)
494 {
495 List *result = NIL;
496 Relation depRel;
497 ScanKeyData key[2];
498 SysScanDesc scan;
499 HeapTuple tup;
500
501 depRel = heap_open(DependRelationId, AccessShareLock);
502
503 ScanKeyInit(&key[0],
504 Anum_pg_depend_classid,
505 BTEqualStrategyNumber, F_OIDEQ,
506 ObjectIdGetDatum(classId));
507 ScanKeyInit(&key[1],
508 Anum_pg_depend_objid,
509 BTEqualStrategyNumber, F_OIDEQ,
510 ObjectIdGetDatum(objectId));
511
512 scan = systable_beginscan(depRel, DependDependerIndexId, true,
513 NULL, 2, key);
514
515 while (HeapTupleIsValid((tup = systable_getnext(scan))))
516 {
517 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
518
519 if (depform->refclassid == ExtensionRelationId &&
520 depform->deptype == DEPENDENCY_AUTO_EXTENSION)
521 result = lappend_oid(result, depform->refobjid);
522 }
523
524 systable_endscan(scan);
525
526 heap_close(depRel, AccessShareLock);
527
528 return result;
529 }
530
531 /*
532 * Detect whether a sequence is marked as "owned" by a column
533 *
534 * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
535 * column. If we find one, store the identity of the owning column
536 * into *tableId and *colId and return true; else return false.
537 *
538 * Note: if there's more than one such pg_depend entry then you get
539 * a random one of them returned into the out parameters. This should
540 * not happen, though.
541 */
542 bool
sequenceIsOwned(Oid seqId,char deptype,Oid * tableId,int32 * colId)543 sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
544 {
545 bool ret = false;
546 Relation depRel;
547 ScanKeyData key[2];
548 SysScanDesc scan;
549 HeapTuple tup;
550
551 depRel = heap_open(DependRelationId, AccessShareLock);
552
553 ScanKeyInit(&key[0],
554 Anum_pg_depend_classid,
555 BTEqualStrategyNumber, F_OIDEQ,
556 ObjectIdGetDatum(RelationRelationId));
557 ScanKeyInit(&key[1],
558 Anum_pg_depend_objid,
559 BTEqualStrategyNumber, F_OIDEQ,
560 ObjectIdGetDatum(seqId));
561
562 scan = systable_beginscan(depRel, DependDependerIndexId, true,
563 NULL, 2, key);
564
565 while (HeapTupleIsValid((tup = systable_getnext(scan))))
566 {
567 Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
568
569 if (depform->refclassid == RelationRelationId &&
570 depform->deptype == deptype)
571 {
572 *tableId = depform->refobjid;
573 *colId = depform->refobjsubid;
574 ret = true;
575 break; /* no need to keep scanning */
576 }
577 }
578
579 systable_endscan(scan);
580
581 heap_close(depRel, AccessShareLock);
582
583 return ret;
584 }
585
586 /*
587 * Collect a list of OIDs of all sequences owned by the specified relation,
588 * and column if specified.
589 */
590 List *
getOwnedSequences(Oid relid,AttrNumber attnum)591 getOwnedSequences(Oid relid, AttrNumber attnum)
592 {
593 List *result = NIL;
594 Relation depRel;
595 ScanKeyData key[3];
596 SysScanDesc scan;
597 HeapTuple tup;
598
599 depRel = heap_open(DependRelationId, AccessShareLock);
600
601 ScanKeyInit(&key[0],
602 Anum_pg_depend_refclassid,
603 BTEqualStrategyNumber, F_OIDEQ,
604 ObjectIdGetDatum(RelationRelationId));
605 ScanKeyInit(&key[1],
606 Anum_pg_depend_refobjid,
607 BTEqualStrategyNumber, F_OIDEQ,
608 ObjectIdGetDatum(relid));
609 if (attnum)
610 ScanKeyInit(&key[2],
611 Anum_pg_depend_refobjsubid,
612 BTEqualStrategyNumber, F_INT4EQ,
613 Int32GetDatum(attnum));
614
615 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
616 NULL, attnum ? 3 : 2, key);
617
618 while (HeapTupleIsValid(tup = systable_getnext(scan)))
619 {
620 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
621
622 /*
623 * We assume any auto or internal dependency of a sequence on a column
624 * must be what we are looking for. (We need the relkind test because
625 * indexes can also have auto dependencies on columns.)
626 */
627 if (deprec->classid == RelationRelationId &&
628 deprec->objsubid == 0 &&
629 deprec->refobjsubid != 0 &&
630 (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
631 get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
632 {
633 result = lappend_oid(result, deprec->objid);
634 }
635 }
636
637 systable_endscan(scan);
638
639 heap_close(depRel, AccessShareLock);
640
641 return result;
642 }
643
644 /*
645 * Get owned sequence, error if not exactly one.
646 */
647 Oid
getOwnedSequence(Oid relid,AttrNumber attnum)648 getOwnedSequence(Oid relid, AttrNumber attnum)
649 {
650 List *seqlist = getOwnedSequences(relid, attnum);
651
652 if (list_length(seqlist) > 1)
653 elog(ERROR, "more than one owned sequence found");
654 else if (list_length(seqlist) < 1)
655 elog(ERROR, "no owned sequence found");
656
657 return linitial_oid(seqlist);
658 }
659
660 /*
661 * get_constraint_index
662 * Given the OID of a unique, primary-key, or exclusion constraint,
663 * return the OID of the underlying index.
664 *
665 * Return InvalidOid if the index couldn't be found; this suggests the
666 * given OID is bogus, but we leave it to caller to decide what to do.
667 */
668 Oid
get_constraint_index(Oid constraintId)669 get_constraint_index(Oid constraintId)
670 {
671 Oid indexId = InvalidOid;
672 Relation depRel;
673 ScanKeyData key[3];
674 SysScanDesc scan;
675 HeapTuple tup;
676
677 /* Search the dependency table for the dependent index */
678 depRel = heap_open(DependRelationId, AccessShareLock);
679
680 ScanKeyInit(&key[0],
681 Anum_pg_depend_refclassid,
682 BTEqualStrategyNumber, F_OIDEQ,
683 ObjectIdGetDatum(ConstraintRelationId));
684 ScanKeyInit(&key[1],
685 Anum_pg_depend_refobjid,
686 BTEqualStrategyNumber, F_OIDEQ,
687 ObjectIdGetDatum(constraintId));
688 ScanKeyInit(&key[2],
689 Anum_pg_depend_refobjsubid,
690 BTEqualStrategyNumber, F_INT4EQ,
691 Int32GetDatum(0));
692
693 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
694 NULL, 3, key);
695
696 while (HeapTupleIsValid(tup = systable_getnext(scan)))
697 {
698 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
699
700 /*
701 * We assume any internal dependency of an index on the constraint
702 * must be what we are looking for.
703 */
704 if (deprec->classid == RelationRelationId &&
705 deprec->objsubid == 0 &&
706 deprec->deptype == DEPENDENCY_INTERNAL)
707 {
708 char relkind = get_rel_relkind(deprec->objid);
709
710 /*
711 * This is pure paranoia; there shouldn't be any other relkinds
712 * dependent on a constraint.
713 */
714 if (relkind != RELKIND_INDEX &&
715 relkind != RELKIND_PARTITIONED_INDEX)
716 continue;
717
718 indexId = deprec->objid;
719 break;
720 }
721 }
722
723 systable_endscan(scan);
724 heap_close(depRel, AccessShareLock);
725
726 return indexId;
727 }
728
729 /*
730 * get_index_constraint
731 * Given the OID of an index, return the OID of the owning unique,
732 * primary-key, or exclusion constraint, or InvalidOid if there
733 * is no owning constraint.
734 */
735 Oid
get_index_constraint(Oid indexId)736 get_index_constraint(Oid indexId)
737 {
738 Oid constraintId = InvalidOid;
739 Relation depRel;
740 ScanKeyData key[3];
741 SysScanDesc scan;
742 HeapTuple tup;
743
744 /* Search the dependency table for the index */
745 depRel = heap_open(DependRelationId, AccessShareLock);
746
747 ScanKeyInit(&key[0],
748 Anum_pg_depend_classid,
749 BTEqualStrategyNumber, F_OIDEQ,
750 ObjectIdGetDatum(RelationRelationId));
751 ScanKeyInit(&key[1],
752 Anum_pg_depend_objid,
753 BTEqualStrategyNumber, F_OIDEQ,
754 ObjectIdGetDatum(indexId));
755 ScanKeyInit(&key[2],
756 Anum_pg_depend_objsubid,
757 BTEqualStrategyNumber, F_INT4EQ,
758 Int32GetDatum(0));
759
760 scan = systable_beginscan(depRel, DependDependerIndexId, true,
761 NULL, 3, key);
762
763 while (HeapTupleIsValid(tup = systable_getnext(scan)))
764 {
765 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
766
767 /*
768 * We assume any internal dependency on a constraint must be what we
769 * are looking for.
770 */
771 if (deprec->refclassid == ConstraintRelationId &&
772 deprec->refobjsubid == 0 &&
773 deprec->deptype == DEPENDENCY_INTERNAL)
774 {
775 constraintId = deprec->refobjid;
776 break;
777 }
778 }
779
780 systable_endscan(scan);
781 heap_close(depRel, AccessShareLock);
782
783 return constraintId;
784 }
785