LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_depend.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 266 273 97.4 %
Date: 2019-06-18 07:06:57 Functions: 16 16 100.0 %
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-2019, 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/htup_details.h"
      19             : #include "access/table.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             : 
      31             : 
      32             : static bool isObjectPinned(const ObjectAddress *object, Relation rel);
      33             : 
      34             : 
      35             : /*
      36             :  * Record a dependency between 2 objects via their respective objectAddress.
      37             :  * The first argument is the dependent object, the second the one it
      38             :  * references.
      39             :  *
      40             :  * This simply creates an entry in pg_depend, without any other processing.
      41             :  */
      42             : void
      43     1846918 : recordDependencyOn(const ObjectAddress *depender,
      44             :                    const ObjectAddress *referenced,
      45             :                    DependencyType behavior)
      46             : {
      47     1846918 :     recordMultipleDependencies(depender, referenced, 1, behavior);
      48     1846918 : }
      49             : 
      50             : /*
      51             :  * Record multiple dependencies (of the same kind) for a single dependent
      52             :  * object.  This has a little less overhead than recording each separately.
      53             :  */
      54             : void
      55     1929072 : recordMultipleDependencies(const ObjectAddress *depender,
      56             :                            const ObjectAddress *referenced,
      57             :                            int nreferenced,
      58             :                            DependencyType behavior)
      59             : {
      60             :     Relation    dependDesc;
      61             :     CatalogIndexState indstate;
      62             :     HeapTuple   tup;
      63             :     int         i;
      64             :     bool        nulls[Natts_pg_depend];
      65             :     Datum       values[Natts_pg_depend];
      66             : 
      67     1929072 :     if (nreferenced <= 0)
      68      202778 :         return;                 /* nothing to do */
      69             : 
      70             :     /*
      71             :      * During bootstrap, do nothing since pg_depend may not exist yet. initdb
      72             :      * will fill in appropriate pg_depend entries after bootstrap.
      73             :      */
      74     1928330 :     if (IsBootstrapProcessingMode())
      75      201294 :         return;
      76             : 
      77     1727036 :     dependDesc = table_open(DependRelationId, RowExclusiveLock);
      78             : 
      79             :     /* Don't open indexes unless we need to make an update */
      80     1727036 :     indstate = NULL;
      81             : 
      82     1727036 :     memset(nulls, false, sizeof(nulls));
      83             : 
      84     4275394 :     for (i = 0; i < nreferenced; i++, referenced++)
      85             :     {
      86             :         /*
      87             :          * If the referenced object is pinned by the system, there's no real
      88             :          * need to record dependencies on it.  This saves lots of space in
      89             :          * pg_depend, so it's worth the time taken to check.
      90             :          */
      91     2548358 :         if (!isObjectPinned(referenced, dependDesc))
      92             :         {
      93             :             /*
      94             :              * Record the Dependency.  Note we don't bother to check for
      95             :              * duplicate dependencies; there's no harm in them.
      96             :              */
      97      712336 :             values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
      98      712336 :             values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
      99      712336 :             values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
     100             : 
     101      712336 :             values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
     102      712336 :             values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
     103      712336 :             values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
     104             : 
     105      712336 :             values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
     106             : 
     107      712336 :             tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
     108             : 
     109             :             /* fetch index info only when we know we need it */
     110      712336 :             if (indstate == NULL)
     111      580886 :                 indstate = CatalogOpenIndexes(dependDesc);
     112             : 
     113      712336 :             CatalogTupleInsertWithInfo(dependDesc, tup, indstate);
     114             : 
     115      712336 :             heap_freetuple(tup);
     116             :         }
     117             :     }
     118             : 
     119     1727036 :     if (indstate != NULL)
     120      580886 :         CatalogCloseIndexes(indstate);
     121             : 
     122     1727036 :     table_close(dependDesc, RowExclusiveLock);
     123             : }
     124             : 
     125             : /*
     126             :  * If we are executing a CREATE EXTENSION operation, mark the given object
     127             :  * as being a member of the extension.  Otherwise, do nothing.
     128             :  *
     129             :  * This must be called during creation of any user-definable object type
     130             :  * that could be a member of an extension.
     131             :  *
     132             :  * If isReplace is true, the object already existed (or might have already
     133             :  * existed), so we must check for a pre-existing extension membership entry.
     134             :  * Passing false is a guarantee that the object is newly created, and so
     135             :  * could not already be a member of any extension.
     136             :  */
     137             : void
     138      126970 : recordDependencyOnCurrentExtension(const ObjectAddress *object,
     139             :                                    bool isReplace)
     140             : {
     141             :     /* Only whole objects can be extension members */
     142             :     Assert(object->objectSubId == 0);
     143             : 
     144      126970 :     if (creating_extension)
     145             :     {
     146             :         ObjectAddress extension;
     147             : 
     148             :         /* Only need to check for existing membership if isReplace */
     149        7260 :         if (isReplace)
     150             :         {
     151             :             Oid         oldext;
     152             : 
     153        1838 :             oldext = getExtensionOfObject(object->classId, object->objectId);
     154        1838 :             if (OidIsValid(oldext))
     155             :             {
     156             :                 /* If already a member of this extension, nothing to do */
     157         742 :                 if (oldext == CurrentExtensionObject)
     158        1484 :                     return;
     159             :                 /* Already a member of some other extension, so reject */
     160           0 :                 ereport(ERROR,
     161             :                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     162             :                          errmsg("%s is already a member of extension \"%s\"",
     163             :                                 getObjectDescription(object),
     164             :                                 get_extension_name(oldext))));
     165             :             }
     166             :         }
     167             : 
     168             :         /* OK, record it as a member of CurrentExtensionObject */
     169        6518 :         extension.classId = ExtensionRelationId;
     170        6518 :         extension.objectId = CurrentExtensionObject;
     171        6518 :         extension.objectSubId = 0;
     172             : 
     173        6518 :         recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
     174             :     }
     175             : }
     176             : 
     177             : /*
     178             :  * deleteDependencyRecordsFor -- delete all records with given depender
     179             :  * classId/objectId.  Returns the number of records deleted.
     180             :  *
     181             :  * This is used when redefining an existing object.  Links leading to the
     182             :  * object do not change, and links leading from it will be recreated
     183             :  * (possibly with some differences from before).
     184             :  *
     185             :  * If skipExtensionDeps is true, we do not delete any dependencies that
     186             :  * show that the given object is a member of an extension.  This avoids
     187             :  * needing a lot of extra logic to fetch and recreate that dependency.
     188             :  */
     189             : long
     190       28558 : deleteDependencyRecordsFor(Oid classId, Oid objectId,
     191             :                            bool skipExtensionDeps)
     192             : {
     193       28558 :     long        count = 0;
     194             :     Relation    depRel;
     195             :     ScanKeyData key[2];
     196             :     SysScanDesc scan;
     197             :     HeapTuple   tup;
     198             : 
     199       28558 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     200             : 
     201       28558 :     ScanKeyInit(&key[0],
     202             :                 Anum_pg_depend_classid,
     203             :                 BTEqualStrategyNumber, F_OIDEQ,
     204             :                 ObjectIdGetDatum(classId));
     205       28558 :     ScanKeyInit(&key[1],
     206             :                 Anum_pg_depend_objid,
     207             :                 BTEqualStrategyNumber, F_OIDEQ,
     208             :                 ObjectIdGetDatum(objectId));
     209             : 
     210       28558 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     211             :                               NULL, 2, key);
     212             : 
     213       69388 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     214             :     {
     215       23500 :         if (skipExtensionDeps &&
     216       11228 :             ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
     217         742 :             continue;
     218             : 
     219       11530 :         CatalogTupleDelete(depRel, &tup->t_self);
     220       11530 :         count++;
     221             :     }
     222             : 
     223       28558 :     systable_endscan(scan);
     224             : 
     225       28558 :     table_close(depRel, RowExclusiveLock);
     226             : 
     227       28558 :     return count;
     228             : }
     229             : 
     230             : /*
     231             :  * deleteDependencyRecordsForClass -- delete all records with given depender
     232             :  * classId/objectId, dependee classId, and deptype.
     233             :  * Returns the number of records deleted.
     234             :  *
     235             :  * This is a variant of deleteDependencyRecordsFor, useful when revoking
     236             :  * an object property that is expressed by a dependency record (such as
     237             :  * extension membership).
     238             :  */
     239             : long
     240         976 : deleteDependencyRecordsForClass(Oid classId, Oid objectId,
     241             :                                 Oid refclassId, char deptype)
     242             : {
     243         976 :     long        count = 0;
     244             :     Relation    depRel;
     245             :     ScanKeyData key[2];
     246             :     SysScanDesc scan;
     247             :     HeapTuple   tup;
     248             : 
     249         976 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     250             : 
     251         976 :     ScanKeyInit(&key[0],
     252             :                 Anum_pg_depend_classid,
     253             :                 BTEqualStrategyNumber, F_OIDEQ,
     254             :                 ObjectIdGetDatum(classId));
     255         976 :     ScanKeyInit(&key[1],
     256             :                 Anum_pg_depend_objid,
     257             :                 BTEqualStrategyNumber, F_OIDEQ,
     258             :                 ObjectIdGetDatum(objectId));
     259             : 
     260         976 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     261             :                               NULL, 2, key);
     262             : 
     263        3638 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     264             :     {
     265        1686 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     266             : 
     267        1686 :         if (depform->refclassid == refclassId && depform->deptype == deptype)
     268             :         {
     269         308 :             CatalogTupleDelete(depRel, &tup->t_self);
     270         308 :             count++;
     271             :         }
     272             :     }
     273             : 
     274         976 :     systable_endscan(scan);
     275             : 
     276         976 :     table_close(depRel, RowExclusiveLock);
     277             : 
     278         976 :     return count;
     279             : }
     280             : 
     281             : /*
     282             :  * Adjust dependency record(s) to point to a different object of the same type
     283             :  *
     284             :  * classId/objectId specify the referencing object.
     285             :  * refClassId/oldRefObjectId specify the old referenced object.
     286             :  * newRefObjectId is the new referenced object (must be of class refClassId).
     287             :  *
     288             :  * Note the lack of objsubid parameters.  If there are subobject references
     289             :  * they will all be readjusted.  Also, there is an expectation that we are
     290             :  * dealing with NORMAL dependencies: if we have to replace an (implicit)
     291             :  * dependency on a pinned object with an explicit dependency on an unpinned
     292             :  * one, the new one will be NORMAL.
     293             :  *
     294             :  * Returns the number of records updated -- zero indicates a problem.
     295             :  */
     296             : long
     297         152 : changeDependencyFor(Oid classId, Oid objectId,
     298             :                     Oid refClassId, Oid oldRefObjectId,
     299             :                     Oid newRefObjectId)
     300             : {
     301         152 :     long        count = 0;
     302             :     Relation    depRel;
     303             :     ScanKeyData key[2];
     304             :     SysScanDesc scan;
     305             :     HeapTuple   tup;
     306             :     ObjectAddress objAddr;
     307             :     ObjectAddress depAddr;
     308             :     bool        oldIsPinned;
     309             :     bool        newIsPinned;
     310             : 
     311         152 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     312             : 
     313             :     /*
     314             :      * Check to see if either oldRefObjectId or newRefObjectId is pinned.
     315             :      * Pinned objects should not have any dependency entries pointing to them,
     316             :      * so in these cases we should add or remove a pg_depend entry, or do
     317             :      * nothing at all, rather than update an entry as in the normal case.
     318             :      */
     319         152 :     objAddr.classId = refClassId;
     320         152 :     objAddr.objectId = oldRefObjectId;
     321         152 :     objAddr.objectSubId = 0;
     322             : 
     323         152 :     oldIsPinned = isObjectPinned(&objAddr, depRel);
     324             : 
     325         152 :     objAddr.objectId = newRefObjectId;
     326             : 
     327         152 :     newIsPinned = isObjectPinned(&objAddr, depRel);
     328             : 
     329         152 :     if (oldIsPinned)
     330             :     {
     331           8 :         table_close(depRel, RowExclusiveLock);
     332             : 
     333             :         /*
     334             :          * If both are pinned, we need do nothing.  However, return 1 not 0,
     335             :          * else callers will think this is an error case.
     336             :          */
     337           8 :         if (newIsPinned)
     338           0 :             return 1;
     339             : 
     340             :         /*
     341             :          * There is no old dependency record, but we should insert a new one.
     342             :          * Assume a normal dependency is wanted.
     343             :          */
     344           8 :         depAddr.classId = classId;
     345           8 :         depAddr.objectId = objectId;
     346           8 :         depAddr.objectSubId = 0;
     347           8 :         recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
     348             : 
     349           8 :         return 1;
     350             :     }
     351             : 
     352             :     /* There should be existing dependency record(s), so search. */
     353         144 :     ScanKeyInit(&key[0],
     354             :                 Anum_pg_depend_classid,
     355             :                 BTEqualStrategyNumber, F_OIDEQ,
     356             :                 ObjectIdGetDatum(classId));
     357         144 :     ScanKeyInit(&key[1],
     358             :                 Anum_pg_depend_objid,
     359             :                 BTEqualStrategyNumber, F_OIDEQ,
     360             :                 ObjectIdGetDatum(objectId));
     361             : 
     362         144 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     363             :                               NULL, 2, key);
     364             : 
     365         518 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     366             :     {
     367         230 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     368             : 
     369         374 :         if (depform->refclassid == refClassId &&
     370         144 :             depform->refobjid == oldRefObjectId)
     371             :         {
     372         144 :             if (newIsPinned)
     373          16 :                 CatalogTupleDelete(depRel, &tup->t_self);
     374             :             else
     375             :             {
     376             :                 /* make a modifiable copy */
     377         128 :                 tup = heap_copytuple(tup);
     378         128 :                 depform = (Form_pg_depend) GETSTRUCT(tup);
     379             : 
     380         128 :                 depform->refobjid = newRefObjectId;
     381             : 
     382         128 :                 CatalogTupleUpdate(depRel, &tup->t_self, tup);
     383             : 
     384         128 :                 heap_freetuple(tup);
     385             :             }
     386             : 
     387         144 :             count++;
     388             :         }
     389             :     }
     390             : 
     391         144 :     systable_endscan(scan);
     392             : 
     393         144 :     table_close(depRel, RowExclusiveLock);
     394             : 
     395         144 :     return count;
     396             : }
     397             : 
     398             : /*
     399             :  * Adjust all dependency records to come from a different object of the same type
     400             :  *
     401             :  * classId/oldObjectId specify the old referencing object.
     402             :  * newObjectId is the new referencing object (must be of class classId).
     403             :  *
     404             :  * Returns the number of records updated.
     405             :  */
     406             : long
     407         122 : changeDependenciesOf(Oid classId, Oid oldObjectId,
     408             :                      Oid newObjectId)
     409             : {
     410         122 :     long        count = 0;
     411             :     Relation    depRel;
     412             :     ScanKeyData key[2];
     413             :     SysScanDesc scan;
     414             :     HeapTuple   tup;
     415             : 
     416         122 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     417             : 
     418         122 :     ScanKeyInit(&key[0],
     419             :                 Anum_pg_depend_classid,
     420             :                 BTEqualStrategyNumber, F_OIDEQ,
     421             :                 ObjectIdGetDatum(classId));
     422         122 :     ScanKeyInit(&key[1],
     423             :                 Anum_pg_depend_objid,
     424             :                 BTEqualStrategyNumber, F_OIDEQ,
     425             :                 ObjectIdGetDatum(oldObjectId));
     426             : 
     427         122 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     428             :                               NULL, 2, key);
     429             : 
     430         476 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     431             :     {
     432         232 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     433             : 
     434             :         /* make a modifiable copy */
     435         232 :         tup = heap_copytuple(tup);
     436         232 :         depform = (Form_pg_depend) GETSTRUCT(tup);
     437             : 
     438         232 :         depform->objid = newObjectId;
     439             : 
     440         232 :         CatalogTupleUpdate(depRel, &tup->t_self, tup);
     441             : 
     442         232 :         heap_freetuple(tup);
     443             : 
     444         232 :         count++;
     445             :     }
     446             : 
     447         122 :     systable_endscan(scan);
     448             : 
     449         122 :     table_close(depRel, RowExclusiveLock);
     450             : 
     451         122 :     return count;
     452             : }
     453             : 
     454             : /*
     455             :  * Adjust all dependency records to point to a different object of the same type
     456             :  *
     457             :  * refClassId/oldRefObjectId specify the old referenced object.
     458             :  * newRefObjectId is the new referenced object (must be of class refClassId).
     459             :  *
     460             :  * Returns the number of records updated.
     461             :  */
     462             : long
     463         122 : changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
     464             :                      Oid newRefObjectId)
     465             : {
     466         122 :     long        count = 0;
     467             :     Relation    depRel;
     468             :     ScanKeyData key[2];
     469             :     SysScanDesc scan;
     470             :     HeapTuple   tup;
     471             :     ObjectAddress objAddr;
     472             :     bool        newIsPinned;
     473             : 
     474         122 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     475             : 
     476             :     /*
     477             :      * If oldRefObjectId is pinned, there won't be any dependency entries on
     478             :      * it --- we can't cope in that case.  (This isn't really worth expending
     479             :      * code to fix, in current usage; it just means you can't rename stuff out
     480             :      * of pg_catalog, which would likely be a bad move anyway.)
     481             :      */
     482         122 :     objAddr.classId = refClassId;
     483         122 :     objAddr.objectId = oldRefObjectId;
     484         122 :     objAddr.objectSubId = 0;
     485             : 
     486         122 :     if (isObjectPinned(&objAddr, depRel))
     487           0 :         ereport(ERROR,
     488             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     489             :                  errmsg("cannot remove dependency on %s because it is a system object",
     490             :                         getObjectDescription(&objAddr))));
     491             : 
     492             :     /*
     493             :      * We can handle adding a dependency on something pinned, though, since
     494             :      * that just means deleting the dependency entry.
     495             :      */
     496         122 :     objAddr.objectId = newRefObjectId;
     497             : 
     498         122 :     newIsPinned = isObjectPinned(&objAddr, depRel);
     499             : 
     500             :     /* Now search for dependency records */
     501         122 :     ScanKeyInit(&key[0],
     502             :                 Anum_pg_depend_refclassid,
     503             :                 BTEqualStrategyNumber, F_OIDEQ,
     504             :                 ObjectIdGetDatum(refClassId));
     505         122 :     ScanKeyInit(&key[1],
     506             :                 Anum_pg_depend_refobjid,
     507             :                 BTEqualStrategyNumber, F_OIDEQ,
     508             :                 ObjectIdGetDatum(oldRefObjectId));
     509             : 
     510         122 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     511             :                               NULL, 2, key);
     512             : 
     513         252 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     514             :     {
     515           8 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     516             : 
     517           8 :         if (newIsPinned)
     518           0 :             CatalogTupleDelete(depRel, &tup->t_self);
     519             :         else
     520             :         {
     521             :             /* make a modifiable copy */
     522           8 :             tup = heap_copytuple(tup);
     523           8 :             depform = (Form_pg_depend) GETSTRUCT(tup);
     524             : 
     525           8 :             depform->refobjid = newRefObjectId;
     526             : 
     527           8 :             CatalogTupleUpdate(depRel, &tup->t_self, tup);
     528             : 
     529           8 :             heap_freetuple(tup);
     530             :         }
     531             : 
     532           8 :         count++;
     533             :     }
     534             : 
     535         122 :     systable_endscan(scan);
     536             : 
     537         122 :     table_close(depRel, RowExclusiveLock);
     538             : 
     539         122 :     return count;
     540             : }
     541             : 
     542             : /*
     543             :  * isObjectPinned()
     544             :  *
     545             :  * Test if an object is required for basic database functionality.
     546             :  * Caller must already have opened pg_depend.
     547             :  *
     548             :  * The passed subId, if any, is ignored; we assume that only whole objects
     549             :  * are pinned (and that this implies pinning their components).
     550             :  */
     551             : static bool
     552     2548906 : isObjectPinned(const ObjectAddress *object, Relation rel)
     553             : {
     554     2548906 :     bool        ret = false;
     555             :     SysScanDesc scan;
     556             :     HeapTuple   tup;
     557             :     ScanKeyData key[2];
     558             : 
     559     2548906 :     ScanKeyInit(&key[0],
     560             :                 Anum_pg_depend_refclassid,
     561             :                 BTEqualStrategyNumber, F_OIDEQ,
     562     2548906 :                 ObjectIdGetDatum(object->classId));
     563             : 
     564     2548906 :     ScanKeyInit(&key[1],
     565             :                 Anum_pg_depend_refobjid,
     566             :                 BTEqualStrategyNumber, F_OIDEQ,
     567     2548906 :                 ObjectIdGetDatum(object->objectId));
     568             : 
     569     2548906 :     scan = systable_beginscan(rel, DependReferenceIndexId, true,
     570             :                               NULL, 2, key);
     571             : 
     572             :     /*
     573             :      * Since we won't generate additional pg_depend entries for pinned
     574             :      * objects, there can be at most one entry referencing a pinned object.
     575             :      * Hence, it's sufficient to look at the first returned tuple; we don't
     576             :      * need to loop.
     577             :      */
     578     2548906 :     tup = systable_getnext(scan);
     579     2548906 :     if (HeapTupleIsValid(tup))
     580             :     {
     581     2411802 :         Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
     582             : 
     583     2411802 :         if (foundDep->deptype == DEPENDENCY_PIN)
     584     1836046 :             ret = true;
     585             :     }
     586             : 
     587     2548906 :     systable_endscan(scan);
     588             : 
     589     2548906 :     return ret;
     590             : }
     591             : 
     592             : 
     593             : /*
     594             :  * Various special-purpose lookups and manipulations of pg_depend.
     595             :  */
     596             : 
     597             : 
     598             : /*
     599             :  * Find the extension containing the specified object, if any
     600             :  *
     601             :  * Returns the OID of the extension, or InvalidOid if the object does not
     602             :  * belong to any extension.
     603             :  *
     604             :  * Extension membership is marked by an EXTENSION dependency from the object
     605             :  * to the extension.  Note that the result will be indeterminate if pg_depend
     606             :  * contains links from this object to more than one extension ... but that
     607             :  * should never happen.
     608             :  */
     609             : Oid
     610        1982 : getExtensionOfObject(Oid classId, Oid objectId)
     611             : {
     612        1982 :     Oid         result = InvalidOid;
     613             :     Relation    depRel;
     614             :     ScanKeyData key[2];
     615             :     SysScanDesc scan;
     616             :     HeapTuple   tup;
     617             : 
     618        1982 :     depRel = table_open(DependRelationId, AccessShareLock);
     619             : 
     620        1982 :     ScanKeyInit(&key[0],
     621             :                 Anum_pg_depend_classid,
     622             :                 BTEqualStrategyNumber, F_OIDEQ,
     623             :                 ObjectIdGetDatum(classId));
     624        1982 :     ScanKeyInit(&key[1],
     625             :                 Anum_pg_depend_objid,
     626             :                 BTEqualStrategyNumber, F_OIDEQ,
     627             :                 ObjectIdGetDatum(objectId));
     628             : 
     629        1982 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     630             :                               NULL, 2, key);
     631             : 
     632        1982 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     633             :     {
     634        2690 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     635             : 
     636        3510 :         if (depform->refclassid == ExtensionRelationId &&
     637         820 :             depform->deptype == DEPENDENCY_EXTENSION)
     638             :         {
     639         820 :             result = depform->refobjid;
     640         820 :             break;              /* no need to keep scanning */
     641             :         }
     642             :     }
     643             : 
     644        1982 :     systable_endscan(scan);
     645             : 
     646        1982 :     table_close(depRel, AccessShareLock);
     647             : 
     648        1982 :     return result;
     649             : }
     650             : 
     651             : /*
     652             :  * Detect whether a sequence is marked as "owned" by a column
     653             :  *
     654             :  * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
     655             :  * column.  If we find one, store the identity of the owning column
     656             :  * into *tableId and *colId and return true; else return false.
     657             :  *
     658             :  * Note: if there's more than one such pg_depend entry then you get
     659             :  * a random one of them returned into the out parameters.  This should
     660             :  * not happen, though.
     661             :  */
     662             : bool
     663         492 : sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
     664             : {
     665         492 :     bool        ret = false;
     666             :     Relation    depRel;
     667             :     ScanKeyData key[2];
     668             :     SysScanDesc scan;
     669             :     HeapTuple   tup;
     670             : 
     671         492 :     depRel = table_open(DependRelationId, AccessShareLock);
     672             : 
     673         492 :     ScanKeyInit(&key[0],
     674             :                 Anum_pg_depend_classid,
     675             :                 BTEqualStrategyNumber, F_OIDEQ,
     676             :                 ObjectIdGetDatum(RelationRelationId));
     677         492 :     ScanKeyInit(&key[1],
     678             :                 Anum_pg_depend_objid,
     679             :                 BTEqualStrategyNumber, F_OIDEQ,
     680             :                 ObjectIdGetDatum(seqId));
     681             : 
     682         492 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     683             :                               NULL, 2, key);
     684             : 
     685         492 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     686             :     {
     687         504 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     688             : 
     689         508 :         if (depform->refclassid == RelationRelationId &&
     690           4 :             depform->deptype == deptype)
     691             :         {
     692           4 :             *tableId = depform->refobjid;
     693           4 :             *colId = depform->refobjsubid;
     694           4 :             ret = true;
     695           4 :             break;              /* no need to keep scanning */
     696             :         }
     697             :     }
     698             : 
     699         492 :     systable_endscan(scan);
     700             : 
     701         492 :     table_close(depRel, AccessShareLock);
     702             : 
     703         492 :     return ret;
     704             : }
     705             : 
     706             : /*
     707             :  * Collect a list of OIDs of all sequences owned by the specified relation,
     708             :  * and column if specified.
     709             :  */
     710             : List *
     711         200 : getOwnedSequences(Oid relid, AttrNumber attnum)
     712             : {
     713         200 :     List       *result = NIL;
     714             :     Relation    depRel;
     715             :     ScanKeyData key[3];
     716             :     SysScanDesc scan;
     717             :     HeapTuple   tup;
     718             : 
     719         200 :     depRel = table_open(DependRelationId, AccessShareLock);
     720             : 
     721         200 :     ScanKeyInit(&key[0],
     722             :                 Anum_pg_depend_refclassid,
     723             :                 BTEqualStrategyNumber, F_OIDEQ,
     724             :                 ObjectIdGetDatum(RelationRelationId));
     725         200 :     ScanKeyInit(&key[1],
     726             :                 Anum_pg_depend_refobjid,
     727             :                 BTEqualStrategyNumber, F_OIDEQ,
     728             :                 ObjectIdGetDatum(relid));
     729         200 :     if (attnum)
     730         182 :         ScanKeyInit(&key[2],
     731             :                     Anum_pg_depend_refobjsubid,
     732             :                     BTEqualStrategyNumber, F_INT4EQ,
     733             :                     Int32GetDatum(attnum));
     734             : 
     735         200 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     736             :                               NULL, attnum ? 3 : 2, key);
     737             : 
     738         668 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     739             :     {
     740         268 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     741             : 
     742             :         /*
     743             :          * We assume any auto or internal dependency of a sequence on a column
     744             :          * must be what we are looking for.  (We need the relkind test because
     745             :          * indexes can also have auto dependencies on columns.)
     746             :          */
     747         470 :         if (deprec->classid == RelationRelationId &&
     748         404 :             deprec->objsubid == 0 &&
     749         404 :             deprec->refobjsubid != 0 &&
     750         586 :             (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
     751         202 :             get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
     752             :         {
     753         202 :             result = lappend_oid(result, deprec->objid);
     754             :         }
     755             :     }
     756             : 
     757         200 :     systable_endscan(scan);
     758             : 
     759         200 :     table_close(depRel, AccessShareLock);
     760             : 
     761         200 :     return result;
     762             : }
     763             : 
     764             : /*
     765             :  * Get owned sequence, error if not exactly one.
     766             :  */
     767             : Oid
     768         166 : getOwnedSequence(Oid relid, AttrNumber attnum)
     769             : {
     770         166 :     List       *seqlist = getOwnedSequences(relid, attnum);
     771             : 
     772         166 :     if (list_length(seqlist) > 1)
     773           0 :         elog(ERROR, "more than one owned sequence found");
     774         166 :     else if (list_length(seqlist) < 1)
     775           0 :         elog(ERROR, "no owned sequence found");
     776             : 
     777         166 :     return linitial_oid(seqlist);
     778             : }
     779             : 
     780             : /*
     781             :  * get_constraint_index
     782             :  *      Given the OID of a unique, primary-key, or exclusion constraint,
     783             :  *      return the OID of the underlying index.
     784             :  *
     785             :  * Return InvalidOid if the index couldn't be found; this suggests the
     786             :  * given OID is bogus, but we leave it to caller to decide what to do.
     787             :  */
     788             : Oid
     789        1204 : get_constraint_index(Oid constraintId)
     790             : {
     791        1204 :     Oid         indexId = InvalidOid;
     792             :     Relation    depRel;
     793             :     ScanKeyData key[3];
     794             :     SysScanDesc scan;
     795             :     HeapTuple   tup;
     796             : 
     797             :     /* Search the dependency table for the dependent index */
     798        1204 :     depRel = table_open(DependRelationId, AccessShareLock);
     799             : 
     800        1204 :     ScanKeyInit(&key[0],
     801             :                 Anum_pg_depend_refclassid,
     802             :                 BTEqualStrategyNumber, F_OIDEQ,
     803             :                 ObjectIdGetDatum(ConstraintRelationId));
     804        1204 :     ScanKeyInit(&key[1],
     805             :                 Anum_pg_depend_refobjid,
     806             :                 BTEqualStrategyNumber, F_OIDEQ,
     807             :                 ObjectIdGetDatum(constraintId));
     808        1204 :     ScanKeyInit(&key[2],
     809             :                 Anum_pg_depend_refobjsubid,
     810             :                 BTEqualStrategyNumber, F_INT4EQ,
     811             :                 Int32GetDatum(0));
     812             : 
     813        1204 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     814             :                               NULL, 3, key);
     815             : 
     816        1204 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     817             :     {
     818        1204 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     819             : 
     820             :         /*
     821             :          * We assume any internal dependency of an index on the constraint
     822             :          * must be what we are looking for.
     823             :          */
     824        2408 :         if (deprec->classid == RelationRelationId &&
     825        2408 :             deprec->objsubid == 0 &&
     826        1204 :             deprec->deptype == DEPENDENCY_INTERNAL)
     827             :         {
     828        1204 :             char        relkind = get_rel_relkind(deprec->objid);
     829             : 
     830             :             /*
     831             :              * This is pure paranoia; there shouldn't be any other relkinds
     832             :              * dependent on a constraint.
     833             :              */
     834        1204 :             if (relkind != RELKIND_INDEX &&
     835             :                 relkind != RELKIND_PARTITIONED_INDEX)
     836           0 :                 continue;
     837             : 
     838        1204 :             indexId = deprec->objid;
     839        1204 :             break;
     840             :         }
     841             :     }
     842             : 
     843        1204 :     systable_endscan(scan);
     844        1204 :     table_close(depRel, AccessShareLock);
     845             : 
     846        1204 :     return indexId;
     847             : }
     848             : 
     849             : /*
     850             :  * get_index_constraint
     851             :  *      Given the OID of an index, return the OID of the owning unique,
     852             :  *      primary-key, or exclusion constraint, or InvalidOid if there
     853             :  *      is no owning constraint.
     854             :  */
     855             : Oid
     856         862 : get_index_constraint(Oid indexId)
     857             : {
     858         862 :     Oid         constraintId = InvalidOid;
     859             :     Relation    depRel;
     860             :     ScanKeyData key[3];
     861             :     SysScanDesc scan;
     862             :     HeapTuple   tup;
     863             : 
     864             :     /* Search the dependency table for the index */
     865         862 :     depRel = table_open(DependRelationId, AccessShareLock);
     866             : 
     867         862 :     ScanKeyInit(&key[0],
     868             :                 Anum_pg_depend_classid,
     869             :                 BTEqualStrategyNumber, F_OIDEQ,
     870             :                 ObjectIdGetDatum(RelationRelationId));
     871         862 :     ScanKeyInit(&key[1],
     872             :                 Anum_pg_depend_objid,
     873             :                 BTEqualStrategyNumber, F_OIDEQ,
     874             :                 ObjectIdGetDatum(indexId));
     875         862 :     ScanKeyInit(&key[2],
     876             :                 Anum_pg_depend_objsubid,
     877             :                 BTEqualStrategyNumber, F_INT4EQ,
     878             :                 Int32GetDatum(0));
     879             : 
     880         862 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     881             :                               NULL, 3, key);
     882             : 
     883         862 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     884             :     {
     885        1256 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     886             : 
     887             :         /*
     888             :          * We assume any internal dependency on a constraint must be what we
     889             :          * are looking for.
     890             :          */
     891        1672 :         if (deprec->refclassid == ConstraintRelationId &&
     892         832 :             deprec->refobjsubid == 0 &&
     893         416 :             deprec->deptype == DEPENDENCY_INTERNAL)
     894             :         {
     895         416 :             constraintId = deprec->refobjid;
     896         416 :             break;
     897             :         }
     898             :     }
     899             : 
     900         862 :     systable_endscan(scan);
     901         862 :     table_close(depRel, AccessShareLock);
     902             : 
     903         862 :     return constraintId;
     904             : }
     905             : 
     906             : /*
     907             :  * get_index_ref_constraints
     908             :  *      Given the OID of an index, return the OID of all foreign key
     909             :  *      constraints which reference the index.
     910             :  */
     911             : List *
     912         122 : get_index_ref_constraints(Oid indexId)
     913             : {
     914         122 :     List       *result = NIL;
     915             :     Relation    depRel;
     916             :     ScanKeyData key[3];
     917             :     SysScanDesc scan;
     918             :     HeapTuple   tup;
     919             : 
     920             :     /* Search the dependency table for the index */
     921         122 :     depRel = table_open(DependRelationId, AccessShareLock);
     922             : 
     923         122 :     ScanKeyInit(&key[0],
     924             :                 Anum_pg_depend_refclassid,
     925             :                 BTEqualStrategyNumber, F_OIDEQ,
     926             :                 ObjectIdGetDatum(RelationRelationId));
     927         122 :     ScanKeyInit(&key[1],
     928             :                 Anum_pg_depend_refobjid,
     929             :                 BTEqualStrategyNumber, F_OIDEQ,
     930             :                 ObjectIdGetDatum(indexId));
     931         122 :     ScanKeyInit(&key[2],
     932             :                 Anum_pg_depend_refobjsubid,
     933             :                 BTEqualStrategyNumber, F_INT4EQ,
     934             :                 Int32GetDatum(0));
     935             : 
     936         122 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     937             :                               NULL, 3, key);
     938             : 
     939         252 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     940             :     {
     941           8 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     942             : 
     943             :         /*
     944             :          * We assume any normal dependency from a constraint must be what we
     945             :          * are looking for.
     946             :          */
     947          16 :         if (deprec->classid == ConstraintRelationId &&
     948          16 :             deprec->objsubid == 0 &&
     949           8 :             deprec->deptype == DEPENDENCY_NORMAL)
     950             :         {
     951           8 :             result = lappend_oid(result, deprec->objid);
     952             :         }
     953             :     }
     954             : 
     955         122 :     systable_endscan(scan);
     956         122 :     table_close(depRel, AccessShareLock);
     957             : 
     958         122 :     return result;
     959             : }

Generated by: LCOV version 1.13