Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_depend.c
4 : * routines to support manipulation of the pg_depend relation
5 : *
6 : * Portions Copyright (c) 1996-2017, 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
44 52029 : recordDependencyOn(const ObjectAddress *depender,
45 : const ObjectAddress *referenced,
46 : DependencyType behavior)
47 : {
48 52029 : recordMultipleDependencies(depender, referenced, 1, behavior);
49 52029 : }
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
56 53411 : 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 53411 : if (nreferenced <= 0)
69 619 : 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 53320 : if (IsBootstrapProcessingMode())
76 437 : return;
77 :
78 52883 : dependDesc = heap_open(DependRelationId, RowExclusiveLock);
79 :
80 : /* Don't open indexes unless we need to make an update */
81 52883 : indstate = NULL;
82 :
83 52883 : memset(nulls, false, sizeof(nulls));
84 :
85 110888 : 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 58005 : 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 18134 : values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
99 18134 : values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
100 18134 : values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
101 :
102 18134 : values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
103 18134 : values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
104 18134 : values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
105 :
106 18134 : values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
107 :
108 18134 : tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
109 :
110 : /* fetch index info only when we know we need it */
111 18134 : if (indstate == NULL)
112 16674 : indstate = CatalogOpenIndexes(dependDesc);
113 :
114 18134 : CatalogTupleInsertWithInfo(dependDesc, tup, indstate);
115 :
116 18134 : heap_freetuple(tup);
117 : }
118 : }
119 :
120 52883 : if (indstate != NULL)
121 16674 : CatalogCloseIndexes(indstate);
122 :
123 52883 : 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
139 3683 : recordDependencyOnCurrentExtension(const ObjectAddress *object,
140 : bool isReplace)
141 : {
142 : /* Only whole objects can be extension members */
143 3683 : Assert(object->objectSubId == 0);
144 :
145 3683 : if (creating_extension)
146 : {
147 : ObjectAddress extension;
148 :
149 : /* Only need to check for existing membership if isReplace */
150 4 : if (isReplace)
151 : {
152 : Oid oldext;
153 :
154 0 : oldext = getExtensionOfObject(object->classId, object->objectId);
155 0 : if (OidIsValid(oldext))
156 : {
157 : /* If already a member of this extension, nothing to do */
158 0 : if (oldext == CurrentExtensionObject)
159 0 : return;
160 : /* Already a member of some other extension, so reject */
161 0 : 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 4 : extension.classId = ExtensionRelationId;
171 4 : extension.objectId = CurrentExtensionObject;
172 4 : extension.objectSubId = 0;
173 :
174 4 : 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
191 340 : deleteDependencyRecordsFor(Oid classId, Oid objectId,
192 : bool skipExtensionDeps)
193 : {
194 340 : long count = 0;
195 : Relation depRel;
196 : ScanKeyData key[2];
197 : SysScanDesc scan;
198 : HeapTuple tup;
199 :
200 340 : depRel = heap_open(DependRelationId, RowExclusiveLock);
201 :
202 340 : ScanKeyInit(&key[0],
203 : Anum_pg_depend_classid,
204 : BTEqualStrategyNumber, F_OIDEQ,
205 : ObjectIdGetDatum(classId));
206 340 : ScanKeyInit(&key[1],
207 : Anum_pg_depend_objid,
208 : BTEqualStrategyNumber, F_OIDEQ,
209 : ObjectIdGetDatum(objectId));
210 :
211 340 : scan = systable_beginscan(depRel, DependDependerIndexId, true,
212 : NULL, 2, key);
213 :
214 1126 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
215 : {
216 684 : if (skipExtensionDeps &&
217 238 : ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
218 0 : continue;
219 :
220 446 : CatalogTupleDelete(depRel, &tup->t_self);
221 446 : count++;
222 : }
223 :
224 340 : systable_endscan(scan);
225 :
226 340 : heap_close(depRel, RowExclusiveLock);
227 :
228 340 : 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
241 83 : deleteDependencyRecordsForClass(Oid classId, Oid objectId,
242 : Oid refclassId, char deptype)
243 : {
244 83 : long count = 0;
245 : Relation depRel;
246 : ScanKeyData key[2];
247 : SysScanDesc scan;
248 : HeapTuple tup;
249 :
250 83 : depRel = heap_open(DependRelationId, RowExclusiveLock);
251 :
252 83 : ScanKeyInit(&key[0],
253 : Anum_pg_depend_classid,
254 : BTEqualStrategyNumber, F_OIDEQ,
255 : ObjectIdGetDatum(classId));
256 83 : ScanKeyInit(&key[1],
257 : Anum_pg_depend_objid,
258 : BTEqualStrategyNumber, F_OIDEQ,
259 : ObjectIdGetDatum(objectId));
260 :
261 83 : scan = systable_beginscan(depRel, DependDependerIndexId, true,
262 : NULL, 2, key);
263 :
264 251 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
265 : {
266 85 : Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
267 :
268 85 : if (depform->refclassid == refclassId && depform->deptype == deptype)
269 : {
270 6 : CatalogTupleDelete(depRel, &tup->t_self);
271 6 : count++;
272 : }
273 : }
274 :
275 83 : systable_endscan(scan);
276 :
277 83 : heap_close(depRel, RowExclusiveLock);
278 :
279 83 : 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
295 34 : changeDependencyFor(Oid classId, Oid objectId,
296 : Oid refClassId, Oid oldRefObjectId,
297 : Oid newRefObjectId)
298 : {
299 34 : long count = 0;
300 : Relation depRel;
301 : ScanKeyData key[2];
302 : SysScanDesc scan;
303 : HeapTuple tup;
304 : ObjectAddress objAddr;
305 : bool newIsPinned;
306 :
307 34 : 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 34 : objAddr.classId = refClassId;
316 34 : objAddr.objectId = oldRefObjectId;
317 34 : objAddr.objectSubId = 0;
318 :
319 34 : if (isObjectPinned(&objAddr, depRel))
320 1 : 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 33 : objAddr.objectId = newRefObjectId;
330 :
331 33 : newIsPinned = isObjectPinned(&objAddr, depRel);
332 :
333 : /* Now search for dependency records */
334 33 : ScanKeyInit(&key[0],
335 : Anum_pg_depend_classid,
336 : BTEqualStrategyNumber, F_OIDEQ,
337 : ObjectIdGetDatum(classId));
338 33 : ScanKeyInit(&key[1],
339 : Anum_pg_depend_objid,
340 : BTEqualStrategyNumber, F_OIDEQ,
341 : ObjectIdGetDatum(objectId));
342 :
343 33 : scan = systable_beginscan(depRel, DependDependerIndexId, true,
344 : NULL, 2, key);
345 :
346 121 : while (HeapTupleIsValid((tup = systable_getnext(scan))))
347 : {
348 55 : Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
349 :
350 88 : if (depform->refclassid == refClassId &&
351 33 : depform->refobjid == oldRefObjectId)
352 : {
353 33 : if (newIsPinned)
354 2 : CatalogTupleDelete(depRel, &tup->t_self);
355 : else
356 : {
357 : /* make a modifiable copy */
358 31 : tup = heap_copytuple(tup);
359 31 : depform = (Form_pg_depend) GETSTRUCT(tup);
360 :
361 31 : depform->refobjid = newRefObjectId;
362 :
363 31 : CatalogTupleUpdate(depRel, &tup->t_self, tup);
364 :
365 31 : heap_freetuple(tup);
366 : }
367 :
368 33 : count++;
369 : }
370 : }
371 :
372 33 : systable_endscan(scan);
373 :
374 33 : heap_close(depRel, RowExclusiveLock);
375 :
376 33 : 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
389 58072 : isObjectPinned(const ObjectAddress *object, Relation rel)
390 : {
391 58072 : bool ret = false;
392 : SysScanDesc scan;
393 : HeapTuple tup;
394 : ScanKeyData key[2];
395 :
396 58072 : ScanKeyInit(&key[0],
397 : Anum_pg_depend_refclassid,
398 : BTEqualStrategyNumber, F_OIDEQ,
399 58072 : ObjectIdGetDatum(object->classId));
400 :
401 58072 : ScanKeyInit(&key[1],
402 : Anum_pg_depend_refobjid,
403 : BTEqualStrategyNumber, F_OIDEQ,
404 58072 : ObjectIdGetDatum(object->objectId));
405 :
406 58072 : 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 58072 : tup = systable_getnext(scan);
416 58072 : if (HeapTupleIsValid(tup))
417 : {
418 51972 : Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
419 :
420 51972 : if (foundDep->deptype == DEPENDENCY_PIN)
421 39874 : ret = true;
422 : }
423 :
424 58072 : systable_endscan(scan);
425 :
426 58072 : 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
447 0 : getExtensionOfObject(Oid classId, Oid objectId)
448 : {
449 0 : Oid result = InvalidOid;
450 : Relation depRel;
451 : ScanKeyData key[2];
452 : SysScanDesc scan;
453 : HeapTuple tup;
454 :
455 0 : depRel = heap_open(DependRelationId, AccessShareLock);
456 :
457 0 : ScanKeyInit(&key[0],
458 : Anum_pg_depend_classid,
459 : BTEqualStrategyNumber, F_OIDEQ,
460 : ObjectIdGetDatum(classId));
461 0 : ScanKeyInit(&key[1],
462 : Anum_pg_depend_objid,
463 : BTEqualStrategyNumber, F_OIDEQ,
464 : ObjectIdGetDatum(objectId));
465 :
466 0 : scan = systable_beginscan(depRel, DependDependerIndexId, true,
467 : NULL, 2, key);
468 :
469 0 : while (HeapTupleIsValid((tup = systable_getnext(scan))))
470 : {
471 0 : Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
472 :
473 0 : if (depform->refclassid == ExtensionRelationId &&
474 0 : depform->deptype == DEPENDENCY_EXTENSION)
475 : {
476 0 : result = depform->refobjid;
477 0 : break; /* no need to keep scanning */
478 : }
479 : }
480 :
481 0 : systable_endscan(scan);
482 :
483 0 : heap_close(depRel, AccessShareLock);
484 :
485 0 : return result;
486 : }
487 :
488 : /*
489 : * Detect whether a sequence is marked as "owned" by a column
490 : *
491 : * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
492 : * column. If we find one, store the identity of the owning column
493 : * into *tableId and *colId and return TRUE; else return FALSE.
494 : *
495 : * Note: if there's more than one such pg_depend entry then you get
496 : * a random one of them returned into the out parameters. This should
497 : * not happen, though.
498 : */
499 : bool
500 64 : sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
501 : {
502 64 : bool ret = false;
503 : Relation depRel;
504 : ScanKeyData key[2];
505 : SysScanDesc scan;
506 : HeapTuple tup;
507 :
508 64 : depRel = heap_open(DependRelationId, AccessShareLock);
509 :
510 64 : ScanKeyInit(&key[0],
511 : Anum_pg_depend_classid,
512 : BTEqualStrategyNumber, F_OIDEQ,
513 : ObjectIdGetDatum(RelationRelationId));
514 64 : ScanKeyInit(&key[1],
515 : Anum_pg_depend_objid,
516 : BTEqualStrategyNumber, F_OIDEQ,
517 : ObjectIdGetDatum(seqId));
518 :
519 64 : scan = systable_beginscan(depRel, DependDependerIndexId, true,
520 : NULL, 2, key);
521 :
522 64 : while (HeapTupleIsValid((tup = systable_getnext(scan))))
523 : {
524 64 : Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
525 :
526 65 : if (depform->refclassid == RelationRelationId &&
527 1 : depform->deptype == deptype)
528 : {
529 1 : *tableId = depform->refobjid;
530 1 : *colId = depform->refobjsubid;
531 1 : ret = true;
532 1 : break; /* no need to keep scanning */
533 : }
534 : }
535 :
536 64 : systable_endscan(scan);
537 :
538 64 : heap_close(depRel, AccessShareLock);
539 :
540 64 : return ret;
541 : }
542 :
543 : /*
544 : * Collect a list of OIDs of all sequences owned by the specified relation,
545 : * and column if specified.
546 : */
547 : List *
548 42 : getOwnedSequences(Oid relid, AttrNumber attnum)
549 : {
550 42 : List *result = NIL;
551 : Relation depRel;
552 : ScanKeyData key[3];
553 : SysScanDesc scan;
554 : HeapTuple tup;
555 :
556 42 : depRel = heap_open(DependRelationId, AccessShareLock);
557 :
558 42 : ScanKeyInit(&key[0],
559 : Anum_pg_depend_refclassid,
560 : BTEqualStrategyNumber, F_OIDEQ,
561 : ObjectIdGetDatum(RelationRelationId));
562 42 : ScanKeyInit(&key[1],
563 : Anum_pg_depend_refobjid,
564 : BTEqualStrategyNumber, F_OIDEQ,
565 : ObjectIdGetDatum(relid));
566 42 : if (attnum)
567 39 : ScanKeyInit(&key[2],
568 : Anum_pg_depend_refobjsubid,
569 : BTEqualStrategyNumber, F_INT4EQ,
570 : Int32GetDatum(attnum));
571 :
572 42 : scan = systable_beginscan(depRel, DependReferenceIndexId, true,
573 : NULL, attnum ? 3 : 2, key);
574 :
575 139 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
576 : {
577 55 : Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
578 :
579 : /*
580 : * We assume any auto or internal dependency of a sequence on a column
581 : * must be what we are looking for. (We need the relkind test because
582 : * indexes can also have auto dependencies on columns.)
583 : */
584 98 : if (deprec->classid == RelationRelationId &&
585 86 : deprec->objsubid == 0 &&
586 86 : deprec->refobjsubid != 0 &&
587 125 : (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
588 43 : get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
589 : {
590 43 : result = lappend_oid(result, deprec->objid);
591 : }
592 : }
593 :
594 42 : systable_endscan(scan);
595 :
596 42 : heap_close(depRel, AccessShareLock);
597 :
598 42 : return result;
599 : }
600 :
601 : /*
602 : * Get owned sequence, error if not exactly one.
603 : */
604 : Oid
605 35 : getOwnedSequence(Oid relid, AttrNumber attnum)
606 : {
607 35 : List *seqlist = getOwnedSequences(relid, attnum);
608 :
609 35 : if (list_length(seqlist) > 1)
610 0 : elog(ERROR, "more than one owned sequence found");
611 35 : else if (list_length(seqlist) < 1)
612 0 : elog(ERROR, "no owned sequence found");
613 :
614 35 : return linitial_oid(seqlist);
615 : }
616 :
617 : /*
618 : * get_constraint_index
619 : * Given the OID of a unique or primary-key constraint, return the
620 : * OID of the underlying unique index.
621 : *
622 : * Return InvalidOid if the index couldn't be found; this suggests the
623 : * given OID is bogus, but we leave it to caller to decide what to do.
624 : */
625 : Oid
626 46 : get_constraint_index(Oid constraintId)
627 : {
628 46 : Oid indexId = InvalidOid;
629 : Relation depRel;
630 : ScanKeyData key[3];
631 : SysScanDesc scan;
632 : HeapTuple tup;
633 :
634 : /* Search the dependency table for the dependent index */
635 46 : depRel = heap_open(DependRelationId, AccessShareLock);
636 :
637 46 : ScanKeyInit(&key[0],
638 : Anum_pg_depend_refclassid,
639 : BTEqualStrategyNumber, F_OIDEQ,
640 : ObjectIdGetDatum(ConstraintRelationId));
641 46 : ScanKeyInit(&key[1],
642 : Anum_pg_depend_refobjid,
643 : BTEqualStrategyNumber, F_OIDEQ,
644 : ObjectIdGetDatum(constraintId));
645 46 : ScanKeyInit(&key[2],
646 : Anum_pg_depend_refobjsubid,
647 : BTEqualStrategyNumber, F_INT4EQ,
648 : Int32GetDatum(0));
649 :
650 46 : scan = systable_beginscan(depRel, DependReferenceIndexId, true,
651 : NULL, 3, key);
652 :
653 46 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
654 : {
655 50 : Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
656 :
657 : /*
658 : * We assume any internal dependency of an index on the constraint
659 : * must be what we are looking for. (The relkind test is just
660 : * paranoia; there shouldn't be any such dependencies otherwise.)
661 : */
662 96 : if (deprec->classid == RelationRelationId &&
663 92 : deprec->objsubid == 0 &&
664 92 : deprec->deptype == DEPENDENCY_INTERNAL &&
665 46 : get_rel_relkind(deprec->objid) == RELKIND_INDEX)
666 : {
667 46 : indexId = deprec->objid;
668 46 : break;
669 : }
670 : }
671 :
672 46 : systable_endscan(scan);
673 46 : heap_close(depRel, AccessShareLock);
674 :
675 46 : return indexId;
676 : }
677 :
678 : /*
679 : * get_index_constraint
680 : * Given the OID of an index, return the OID of the owning unique or
681 : * primary-key constraint, or InvalidOid if no such constraint.
682 : */
683 : Oid
684 55 : get_index_constraint(Oid indexId)
685 : {
686 55 : Oid constraintId = InvalidOid;
687 : Relation depRel;
688 : ScanKeyData key[3];
689 : SysScanDesc scan;
690 : HeapTuple tup;
691 :
692 : /* Search the dependency table for the index */
693 55 : depRel = heap_open(DependRelationId, AccessShareLock);
694 :
695 55 : ScanKeyInit(&key[0],
696 : Anum_pg_depend_classid,
697 : BTEqualStrategyNumber, F_OIDEQ,
698 : ObjectIdGetDatum(RelationRelationId));
699 55 : ScanKeyInit(&key[1],
700 : Anum_pg_depend_objid,
701 : BTEqualStrategyNumber, F_OIDEQ,
702 : ObjectIdGetDatum(indexId));
703 55 : ScanKeyInit(&key[2],
704 : Anum_pg_depend_objsubid,
705 : BTEqualStrategyNumber, F_INT4EQ,
706 : Int32GetDatum(0));
707 :
708 55 : scan = systable_beginscan(depRel, DependDependerIndexId, true,
709 : NULL, 3, key);
710 :
711 55 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
712 : {
713 101 : Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
714 :
715 : /*
716 : * We assume any internal dependency on a constraint must be what we
717 : * are looking for.
718 : */
719 108 : if (deprec->refclassid == ConstraintRelationId &&
720 14 : deprec->refobjsubid == 0 &&
721 7 : deprec->deptype == DEPENDENCY_INTERNAL)
722 : {
723 7 : constraintId = deprec->refobjid;
724 7 : break;
725 : }
726 : }
727 :
728 55 : systable_endscan(scan);
729 55 : heap_close(depRel, AccessShareLock);
730 :
731 55 : return constraintId;
732 : }
|