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