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