Header And Logo

PostgreSQL
| The world's most advanced open source database.

pg_depend.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pg_depend.c
00004  *    routines to support manipulation of the pg_depend relation
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/catalog/pg_depend.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include "access/genam.h"
00018 #include "access/heapam.h"
00019 #include "access/htup_details.h"
00020 #include "catalog/dependency.h"
00021 #include "catalog/indexing.h"
00022 #include "catalog/pg_constraint.h"
00023 #include "catalog/pg_depend.h"
00024 #include "catalog/pg_extension.h"
00025 #include "commands/extension.h"
00026 #include "miscadmin.h"
00027 #include "utils/fmgroids.h"
00028 #include "utils/lsyscache.h"
00029 #include "utils/rel.h"
00030 #include "utils/tqual.h"
00031 
00032 
00033 static bool isObjectPinned(const ObjectAddress *object, Relation rel);
00034 
00035 
00036 /*
00037  * Record a dependency between 2 objects via their respective objectAddress.
00038  * The first argument is the dependent object, the second the one it
00039  * references.
00040  *
00041  * This simply creates an entry in pg_depend, without any other processing.
00042  */
00043 void
00044 recordDependencyOn(const ObjectAddress *depender,
00045                    const ObjectAddress *referenced,
00046                    DependencyType behavior)
00047 {
00048     recordMultipleDependencies(depender, referenced, 1, behavior);
00049 }
00050 
00051 /*
00052  * Record multiple dependencies (of the same kind) for a single dependent
00053  * object.  This has a little less overhead than recording each separately.
00054  */
00055 void
00056 recordMultipleDependencies(const ObjectAddress *depender,
00057                            const ObjectAddress *referenced,
00058                            int nreferenced,
00059                            DependencyType behavior)
00060 {
00061     Relation    dependDesc;
00062     CatalogIndexState indstate;
00063     HeapTuple   tup;
00064     int         i;
00065     bool        nulls[Natts_pg_depend];
00066     Datum       values[Natts_pg_depend];
00067 
00068     if (nreferenced <= 0)
00069         return;                 /* nothing to do */
00070 
00071     /*
00072      * During bootstrap, do nothing since pg_depend may not exist yet. initdb
00073      * will fill in appropriate pg_depend entries after bootstrap.
00074      */
00075     if (IsBootstrapProcessingMode())
00076         return;
00077 
00078     dependDesc = heap_open(DependRelationId, RowExclusiveLock);
00079 
00080     /* Don't open indexes unless we need to make an update */
00081     indstate = NULL;
00082 
00083     memset(nulls, false, sizeof(nulls));
00084 
00085     for (i = 0; i < nreferenced; i++, referenced++)
00086     {
00087         /*
00088          * If the referenced object is pinned by the system, there's no real
00089          * need to record dependencies on it.  This saves lots of space in
00090          * pg_depend, so it's worth the time taken to check.
00091          */
00092         if (!isObjectPinned(referenced, dependDesc))
00093         {
00094             /*
00095              * Record the Dependency.  Note we don't bother to check for
00096              * duplicate dependencies; there's no harm in them.
00097              */
00098             values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
00099             values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
00100             values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
00101 
00102             values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
00103             values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
00104             values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
00105 
00106             values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
00107 
00108             tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
00109 
00110             simple_heap_insert(dependDesc, tup);
00111 
00112             /* keep indexes current */
00113             if (indstate == NULL)
00114                 indstate = CatalogOpenIndexes(dependDesc);
00115 
00116             CatalogIndexInsert(indstate, tup);
00117 
00118             heap_freetuple(tup);
00119         }
00120     }
00121 
00122     if (indstate != NULL)
00123         CatalogCloseIndexes(indstate);
00124 
00125     heap_close(dependDesc, RowExclusiveLock);
00126 }
00127 
00128 /*
00129  * If we are executing a CREATE EXTENSION operation, mark the given object
00130  * as being a member of the extension.  Otherwise, do nothing.
00131  *
00132  * This must be called during creation of any user-definable object type
00133  * that could be a member of an extension.
00134  *
00135  * If isReplace is true, the object already existed (or might have already
00136  * existed), so we must check for a pre-existing extension membership entry.
00137  * Passing false is a guarantee that the object is newly created, and so
00138  * could not already be a member of any extension.
00139  */
00140 void
00141 recordDependencyOnCurrentExtension(const ObjectAddress *object,
00142                                    bool isReplace)
00143 {
00144     /* Only whole objects can be extension members */
00145     Assert(object->objectSubId == 0);
00146 
00147     if (creating_extension)
00148     {
00149         ObjectAddress extension;
00150 
00151         /* Only need to check for existing membership if isReplace */
00152         if (isReplace)
00153         {
00154             Oid         oldext;
00155 
00156             oldext = getExtensionOfObject(object->classId, object->objectId);
00157             if (OidIsValid(oldext))
00158             {
00159                 /* If already a member of this extension, nothing to do */
00160                 if (oldext == CurrentExtensionObject)
00161                     return;
00162                 /* Already a member of some other extension, so reject */
00163                 ereport(ERROR,
00164                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00165                          errmsg("%s is already a member of extension \"%s\"",
00166                                 getObjectDescription(object),
00167                                 get_extension_name(oldext))));
00168             }
00169         }
00170 
00171         /* OK, record it as a member of CurrentExtensionObject */
00172         extension.classId = ExtensionRelationId;
00173         extension.objectId = CurrentExtensionObject;
00174         extension.objectSubId = 0;
00175 
00176         recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
00177     }
00178 }
00179 
00180 /*
00181  * deleteDependencyRecordsFor -- delete all records with given depender
00182  * classId/objectId.  Returns the number of records deleted.
00183  *
00184  * This is used when redefining an existing object.  Links leading to the
00185  * object do not change, and links leading from it will be recreated
00186  * (possibly with some differences from before).
00187  *
00188  * If skipExtensionDeps is true, we do not delete any dependencies that
00189  * show that the given object is a member of an extension.  This avoids
00190  * needing a lot of extra logic to fetch and recreate that dependency.
00191  */
00192 long
00193 deleteDependencyRecordsFor(Oid classId, Oid objectId,
00194                            bool skipExtensionDeps)
00195 {
00196     long        count = 0;
00197     Relation    depRel;
00198     ScanKeyData key[2];
00199     SysScanDesc scan;
00200     HeapTuple   tup;
00201 
00202     depRel = heap_open(DependRelationId, RowExclusiveLock);
00203 
00204     ScanKeyInit(&key[0],
00205                 Anum_pg_depend_classid,
00206                 BTEqualStrategyNumber, F_OIDEQ,
00207                 ObjectIdGetDatum(classId));
00208     ScanKeyInit(&key[1],
00209                 Anum_pg_depend_objid,
00210                 BTEqualStrategyNumber, F_OIDEQ,
00211                 ObjectIdGetDatum(objectId));
00212 
00213     scan = systable_beginscan(depRel, DependDependerIndexId, true,
00214                               SnapshotNow, 2, key);
00215 
00216     while (HeapTupleIsValid(tup = systable_getnext(scan)))
00217     {
00218         if (skipExtensionDeps &&
00219           ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
00220             continue;
00221 
00222         simple_heap_delete(depRel, &tup->t_self);
00223         count++;
00224     }
00225 
00226     systable_endscan(scan);
00227 
00228     heap_close(depRel, RowExclusiveLock);
00229 
00230     return count;
00231 }
00232 
00233 /*
00234  * deleteDependencyRecordsForClass -- delete all records with given depender
00235  * classId/objectId, dependee classId, and deptype.
00236  * Returns the number of records deleted.
00237  *
00238  * This is a variant of deleteDependencyRecordsFor, useful when revoking
00239  * an object property that is expressed by a dependency record (such as
00240  * extension membership).
00241  */
00242 long
00243 deleteDependencyRecordsForClass(Oid classId, Oid objectId,
00244                                 Oid refclassId, char deptype)
00245 {
00246     long        count = 0;
00247     Relation    depRel;
00248     ScanKeyData key[2];
00249     SysScanDesc scan;
00250     HeapTuple   tup;
00251 
00252     depRel = heap_open(DependRelationId, RowExclusiveLock);
00253 
00254     ScanKeyInit(&key[0],
00255                 Anum_pg_depend_classid,
00256                 BTEqualStrategyNumber, F_OIDEQ,
00257                 ObjectIdGetDatum(classId));
00258     ScanKeyInit(&key[1],
00259                 Anum_pg_depend_objid,
00260                 BTEqualStrategyNumber, F_OIDEQ,
00261                 ObjectIdGetDatum(objectId));
00262 
00263     scan = systable_beginscan(depRel, DependDependerIndexId, true,
00264                               SnapshotNow, 2, key);
00265 
00266     while (HeapTupleIsValid(tup = systable_getnext(scan)))
00267     {
00268         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
00269 
00270         if (depform->refclassid == refclassId && depform->deptype == deptype)
00271         {
00272             simple_heap_delete(depRel, &tup->t_self);
00273             count++;
00274         }
00275     }
00276 
00277     systable_endscan(scan);
00278 
00279     heap_close(depRel, RowExclusiveLock);
00280 
00281     return count;
00282 }
00283 
00284 /*
00285  * Adjust dependency record(s) to point to a different object of the same type
00286  *
00287  * classId/objectId specify the referencing object.
00288  * refClassId/oldRefObjectId specify the old referenced object.
00289  * newRefObjectId is the new referenced object (must be of class refClassId).
00290  *
00291  * Note the lack of objsubid parameters.  If there are subobject references
00292  * they will all be readjusted.
00293  *
00294  * Returns the number of records updated.
00295  */
00296 long
00297 changeDependencyFor(Oid classId, Oid objectId,
00298                     Oid refClassId, Oid oldRefObjectId,
00299                     Oid newRefObjectId)
00300 {
00301     long        count = 0;
00302     Relation    depRel;
00303     ScanKeyData key[2];
00304     SysScanDesc scan;
00305     HeapTuple   tup;
00306     ObjectAddress objAddr;
00307     bool        newIsPinned;
00308 
00309     depRel = heap_open(DependRelationId, RowExclusiveLock);
00310 
00311     /*
00312      * If oldRefObjectId is pinned, there won't be any dependency entries on
00313      * it --- we can't cope in that case.  (This isn't really worth expending
00314      * code to fix, in current usage; it just means you can't rename stuff out
00315      * of pg_catalog, which would likely be a bad move anyway.)
00316      */
00317     objAddr.classId = refClassId;
00318     objAddr.objectId = oldRefObjectId;
00319     objAddr.objectSubId = 0;
00320 
00321     if (isObjectPinned(&objAddr, depRel))
00322         ereport(ERROR,
00323                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00324         errmsg("cannot remove dependency on %s because it is a system object",
00325                getObjectDescription(&objAddr))));
00326 
00327     /*
00328      * We can handle adding a dependency on something pinned, though, since
00329      * that just means deleting the dependency entry.
00330      */
00331     objAddr.objectId = newRefObjectId;
00332 
00333     newIsPinned = isObjectPinned(&objAddr, depRel);
00334 
00335     /* Now search for dependency records */
00336     ScanKeyInit(&key[0],
00337                 Anum_pg_depend_classid,
00338                 BTEqualStrategyNumber, F_OIDEQ,
00339                 ObjectIdGetDatum(classId));
00340     ScanKeyInit(&key[1],
00341                 Anum_pg_depend_objid,
00342                 BTEqualStrategyNumber, F_OIDEQ,
00343                 ObjectIdGetDatum(objectId));
00344 
00345     scan = systable_beginscan(depRel, DependDependerIndexId, true,
00346                               SnapshotNow, 2, key);
00347 
00348     while (HeapTupleIsValid((tup = systable_getnext(scan))))
00349     {
00350         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
00351 
00352         if (depform->refclassid == refClassId &&
00353             depform->refobjid == oldRefObjectId)
00354         {
00355             if (newIsPinned)
00356                 simple_heap_delete(depRel, &tup->t_self);
00357             else
00358             {
00359                 /* make a modifiable copy */
00360                 tup = heap_copytuple(tup);
00361                 depform = (Form_pg_depend) GETSTRUCT(tup);
00362 
00363                 depform->refobjid = newRefObjectId;
00364 
00365                 simple_heap_update(depRel, &tup->t_self, tup);
00366                 CatalogUpdateIndexes(depRel, tup);
00367 
00368                 heap_freetuple(tup);
00369             }
00370 
00371             count++;
00372         }
00373     }
00374 
00375     systable_endscan(scan);
00376 
00377     heap_close(depRel, RowExclusiveLock);
00378 
00379     return count;
00380 }
00381 
00382 /*
00383  * isObjectPinned()
00384  *
00385  * Test if an object is required for basic database functionality.
00386  * Caller must already have opened pg_depend.
00387  *
00388  * The passed subId, if any, is ignored; we assume that only whole objects
00389  * are pinned (and that this implies pinning their components).
00390  */
00391 static bool
00392 isObjectPinned(const ObjectAddress *object, Relation rel)
00393 {
00394     bool        ret = false;
00395     SysScanDesc scan;
00396     HeapTuple   tup;
00397     ScanKeyData key[2];
00398 
00399     ScanKeyInit(&key[0],
00400                 Anum_pg_depend_refclassid,
00401                 BTEqualStrategyNumber, F_OIDEQ,
00402                 ObjectIdGetDatum(object->classId));
00403 
00404     ScanKeyInit(&key[1],
00405                 Anum_pg_depend_refobjid,
00406                 BTEqualStrategyNumber, F_OIDEQ,
00407                 ObjectIdGetDatum(object->objectId));
00408 
00409     scan = systable_beginscan(rel, DependReferenceIndexId, true,
00410                               SnapshotNow, 2, key);
00411 
00412     /*
00413      * Since we won't generate additional pg_depend entries for pinned
00414      * objects, there can be at most one entry referencing a pinned object.
00415      * Hence, it's sufficient to look at the first returned tuple; we don't
00416      * need to loop.
00417      */
00418     tup = systable_getnext(scan);
00419     if (HeapTupleIsValid(tup))
00420     {
00421         Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
00422 
00423         if (foundDep->deptype == DEPENDENCY_PIN)
00424             ret = true;
00425     }
00426 
00427     systable_endscan(scan);
00428 
00429     return ret;
00430 }
00431 
00432 
00433 /*
00434  * Various special-purpose lookups and manipulations of pg_depend.
00435  */
00436 
00437 
00438 /*
00439  * Find the extension containing the specified object, if any
00440  *
00441  * Returns the OID of the extension, or InvalidOid if the object does not
00442  * belong to any extension.
00443  *
00444  * Extension membership is marked by an EXTENSION dependency from the object
00445  * to the extension.  Note that the result will be indeterminate if pg_depend
00446  * contains links from this object to more than one extension ... but that
00447  * should never happen.
00448  */
00449 Oid
00450 getExtensionOfObject(Oid classId, Oid objectId)
00451 {
00452     Oid         result = InvalidOid;
00453     Relation    depRel;
00454     ScanKeyData key[2];
00455     SysScanDesc scan;
00456     HeapTuple   tup;
00457 
00458     depRel = heap_open(DependRelationId, AccessShareLock);
00459 
00460     ScanKeyInit(&key[0],
00461                 Anum_pg_depend_classid,
00462                 BTEqualStrategyNumber, F_OIDEQ,
00463                 ObjectIdGetDatum(classId));
00464     ScanKeyInit(&key[1],
00465                 Anum_pg_depend_objid,
00466                 BTEqualStrategyNumber, F_OIDEQ,
00467                 ObjectIdGetDatum(objectId));
00468 
00469     scan = systable_beginscan(depRel, DependDependerIndexId, true,
00470                               SnapshotNow, 2, key);
00471 
00472     while (HeapTupleIsValid((tup = systable_getnext(scan))))
00473     {
00474         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
00475 
00476         if (depform->refclassid == ExtensionRelationId &&
00477             depform->deptype == DEPENDENCY_EXTENSION)
00478         {
00479             result = depform->refobjid;
00480             break;              /* no need to keep scanning */
00481         }
00482     }
00483 
00484     systable_endscan(scan);
00485 
00486     heap_close(depRel, AccessShareLock);
00487 
00488     return result;
00489 }
00490 
00491 /*
00492  * Detect whether a sequence is marked as "owned" by a column
00493  *
00494  * An ownership marker is an AUTO dependency from the sequence to the
00495  * column.  If we find one, store the identity of the owning column
00496  * into *tableId and *colId and return TRUE; else return FALSE.
00497  *
00498  * Note: if there's more than one such pg_depend entry then you get
00499  * a random one of them returned into the out parameters.  This should
00500  * not happen, though.
00501  */
00502 bool
00503 sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
00504 {
00505     bool        ret = false;
00506     Relation    depRel;
00507     ScanKeyData key[2];
00508     SysScanDesc scan;
00509     HeapTuple   tup;
00510 
00511     depRel = heap_open(DependRelationId, AccessShareLock);
00512 
00513     ScanKeyInit(&key[0],
00514                 Anum_pg_depend_classid,
00515                 BTEqualStrategyNumber, F_OIDEQ,
00516                 ObjectIdGetDatum(RelationRelationId));
00517     ScanKeyInit(&key[1],
00518                 Anum_pg_depend_objid,
00519                 BTEqualStrategyNumber, F_OIDEQ,
00520                 ObjectIdGetDatum(seqId));
00521 
00522     scan = systable_beginscan(depRel, DependDependerIndexId, true,
00523                               SnapshotNow, 2, key);
00524 
00525     while (HeapTupleIsValid((tup = systable_getnext(scan))))
00526     {
00527         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
00528 
00529         if (depform->refclassid == RelationRelationId &&
00530             depform->deptype == DEPENDENCY_AUTO)
00531         {
00532             *tableId = depform->refobjid;
00533             *colId = depform->refobjsubid;
00534             ret = true;
00535             break;              /* no need to keep scanning */
00536         }
00537     }
00538 
00539     systable_endscan(scan);
00540 
00541     heap_close(depRel, AccessShareLock);
00542 
00543     return ret;
00544 }
00545 
00546 /*
00547  * Remove any existing "owned" markers for the specified sequence.
00548  *
00549  * Note: we don't provide a special function to install an "owned"
00550  * marker; just use recordDependencyOn().
00551  */
00552 void
00553 markSequenceUnowned(Oid seqId)
00554 {
00555     deleteDependencyRecordsForClass(RelationRelationId, seqId,
00556                                     RelationRelationId, DEPENDENCY_AUTO);
00557 }
00558 
00559 /*
00560  * Collect a list of OIDs of all sequences owned by the specified relation.
00561  */
00562 List *
00563 getOwnedSequences(Oid relid)
00564 {
00565     List       *result = NIL;
00566     Relation    depRel;
00567     ScanKeyData key[2];
00568     SysScanDesc scan;
00569     HeapTuple   tup;
00570 
00571     depRel = heap_open(DependRelationId, AccessShareLock);
00572 
00573     ScanKeyInit(&key[0],
00574                 Anum_pg_depend_refclassid,
00575                 BTEqualStrategyNumber, F_OIDEQ,
00576                 ObjectIdGetDatum(RelationRelationId));
00577     ScanKeyInit(&key[1],
00578                 Anum_pg_depend_refobjid,
00579                 BTEqualStrategyNumber, F_OIDEQ,
00580                 ObjectIdGetDatum(relid));
00581 
00582     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
00583                               SnapshotNow, 2, key);
00584 
00585     while (HeapTupleIsValid(tup = systable_getnext(scan)))
00586     {
00587         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
00588 
00589         /*
00590          * We assume any auto dependency of a sequence on a column must be
00591          * what we are looking for.  (We need the relkind test because indexes
00592          * can also have auto dependencies on columns.)
00593          */
00594         if (deprec->classid == RelationRelationId &&
00595             deprec->objsubid == 0 &&
00596             deprec->refobjsubid != 0 &&
00597             deprec->deptype == DEPENDENCY_AUTO &&
00598             get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
00599         {
00600             result = lappend_oid(result, deprec->objid);
00601         }
00602     }
00603 
00604     systable_endscan(scan);
00605 
00606     heap_close(depRel, AccessShareLock);
00607 
00608     return result;
00609 }
00610 
00611 
00612 /*
00613  * get_constraint_index
00614  *      Given the OID of a unique or primary-key constraint, return the
00615  *      OID of the underlying unique index.
00616  *
00617  * Return InvalidOid if the index couldn't be found; this suggests the
00618  * given OID is bogus, but we leave it to caller to decide what to do.
00619  */
00620 Oid
00621 get_constraint_index(Oid constraintId)
00622 {
00623     Oid         indexId = InvalidOid;
00624     Relation    depRel;
00625     ScanKeyData key[3];
00626     SysScanDesc scan;
00627     HeapTuple   tup;
00628 
00629     /* Search the dependency table for the dependent index */
00630     depRel = heap_open(DependRelationId, AccessShareLock);
00631 
00632     ScanKeyInit(&key[0],
00633                 Anum_pg_depend_refclassid,
00634                 BTEqualStrategyNumber, F_OIDEQ,
00635                 ObjectIdGetDatum(ConstraintRelationId));
00636     ScanKeyInit(&key[1],
00637                 Anum_pg_depend_refobjid,
00638                 BTEqualStrategyNumber, F_OIDEQ,
00639                 ObjectIdGetDatum(constraintId));
00640     ScanKeyInit(&key[2],
00641                 Anum_pg_depend_refobjsubid,
00642                 BTEqualStrategyNumber, F_INT4EQ,
00643                 Int32GetDatum(0));
00644 
00645     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
00646                               SnapshotNow, 3, key);
00647 
00648     while (HeapTupleIsValid(tup = systable_getnext(scan)))
00649     {
00650         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
00651 
00652         /*
00653          * We assume any internal dependency of an index on the constraint
00654          * must be what we are looking for.  (The relkind test is just
00655          * paranoia; there shouldn't be any such dependencies otherwise.)
00656          */
00657         if (deprec->classid == RelationRelationId &&
00658             deprec->objsubid == 0 &&
00659             deprec->deptype == DEPENDENCY_INTERNAL &&
00660             get_rel_relkind(deprec->objid) == RELKIND_INDEX)
00661         {
00662             indexId = deprec->objid;
00663             break;
00664         }
00665     }
00666 
00667     systable_endscan(scan);
00668     heap_close(depRel, AccessShareLock);
00669 
00670     return indexId;
00671 }
00672 
00673 /*
00674  * get_index_constraint
00675  *      Given the OID of an index, return the OID of the owning unique or
00676  *      primary-key constraint, or InvalidOid if no such constraint.
00677  */
00678 Oid
00679 get_index_constraint(Oid indexId)
00680 {
00681     Oid         constraintId = InvalidOid;
00682     Relation    depRel;
00683     ScanKeyData key[3];
00684     SysScanDesc scan;
00685     HeapTuple   tup;
00686 
00687     /* Search the dependency table for the index */
00688     depRel = heap_open(DependRelationId, AccessShareLock);
00689 
00690     ScanKeyInit(&key[0],
00691                 Anum_pg_depend_classid,
00692                 BTEqualStrategyNumber, F_OIDEQ,
00693                 ObjectIdGetDatum(RelationRelationId));
00694     ScanKeyInit(&key[1],
00695                 Anum_pg_depend_objid,
00696                 BTEqualStrategyNumber, F_OIDEQ,
00697                 ObjectIdGetDatum(indexId));
00698     ScanKeyInit(&key[2],
00699                 Anum_pg_depend_objsubid,
00700                 BTEqualStrategyNumber, F_INT4EQ,
00701                 Int32GetDatum(0));
00702 
00703     scan = systable_beginscan(depRel, DependDependerIndexId, true,
00704                               SnapshotNow, 3, key);
00705 
00706     while (HeapTupleIsValid(tup = systable_getnext(scan)))
00707     {
00708         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
00709 
00710         /*
00711          * We assume any internal dependency on a constraint must be what we
00712          * are looking for.
00713          */
00714         if (deprec->refclassid == ConstraintRelationId &&
00715             deprec->refobjsubid == 0 &&
00716             deprec->deptype == DEPENDENCY_INTERNAL)
00717         {
00718             constraintId = deprec->refobjid;
00719             break;
00720         }
00721     }
00722 
00723     systable_endscan(scan);
00724     heap_close(depRel, AccessShareLock);
00725 
00726     return constraintId;
00727 }