LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_depend.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 182 205 88.8 %
Date: 2017-09-29 13:40:31 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.11