LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_depend.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 271 278 97.5 %
Date: 2019-11-22 07:06:56 Functions: 17 17 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     1870016 : recordDependencyOn(const ObjectAddress *depender,
      44             :                    const ObjectAddress *referenced,
      45             :                    DependencyType behavior)
      46             : {
      47     1870016 :     recordMultipleDependencies(depender, referenced, 1, behavior);
      48     1870016 : }
      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     1956330 : 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     1956330 :     if (nreferenced <= 0)
      68      205648 :         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     1955580 :     if (IsBootstrapProcessingMode())
      75      204148 :         return;
      76             : 
      77     1751432 :     dependDesc = table_open(DependRelationId, RowExclusiveLock);
      78             : 
      79             :     /* Don't open indexes unless we need to make an update */
      80     1751432 :     indstate = NULL;
      81             : 
      82     1751432 :     memset(nulls, false, sizeof(nulls));
      83             : 
      84     4339162 :     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     2587730 :         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      717680 :             values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
      98      717680 :             values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
      99      717680 :             values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
     100             : 
     101      717680 :             values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
     102      717680 :             values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
     103      717680 :             values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
     104             : 
     105      717680 :             values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
     106             : 
     107      717680 :             tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
     108             : 
     109             :             /* fetch index info only when we know we need it */
     110      717680 :             if (indstate == NULL)
     111      584630 :                 indstate = CatalogOpenIndexes(dependDesc);
     112             : 
     113      717680 :             CatalogTupleInsertWithInfo(dependDesc, tup, indstate);
     114             : 
     115      717680 :             heap_freetuple(tup);
     116             :         }
     117             :     }
     118             : 
     119     1751432 :     if (indstate != NULL)
     120      584630 :         CatalogCloseIndexes(indstate);
     121             : 
     122     1751432 :     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      131408 : recordDependencyOnCurrentExtension(const ObjectAddress *object,
     139             :                                    bool isReplace)
     140             : {
     141             :     /* Only whole objects can be extension members */
     142             :     Assert(object->objectSubId == 0);
     143             : 
     144      131408 :     if (creating_extension)
     145             :     {
     146             :         ObjectAddress extension;
     147             : 
     148             :         /* Only need to check for existing membership if isReplace */
     149        7292 :         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        6550 :         extension.classId = ExtensionRelationId;
     170        6550 :         extension.objectId = CurrentExtensionObject;
     171        6550 :         extension.objectSubId = 0;
     172             : 
     173        6550 :         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       31640 : deleteDependencyRecordsFor(Oid classId, Oid objectId,
     191             :                            bool skipExtensionDeps)
     192             : {
     193       31640 :     long        count = 0;
     194             :     Relation    depRel;
     195             :     ScanKeyData key[2];
     196             :     SysScanDesc scan;
     197             :     HeapTuple   tup;
     198             : 
     199       31640 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     200             : 
     201       31640 :     ScanKeyInit(&key[0],
     202             :                 Anum_pg_depend_classid,
     203             :                 BTEqualStrategyNumber, F_OIDEQ,
     204             :                 ObjectIdGetDatum(classId));
     205       31640 :     ScanKeyInit(&key[1],
     206             :                 Anum_pg_depend_objid,
     207             :                 BTEqualStrategyNumber, F_OIDEQ,
     208             :                 ObjectIdGetDatum(objectId));
     209             : 
     210       31640 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     211             :                               NULL, 2, key);
     212             : 
     213       76200 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     214             :     {
     215       24564 :         if (skipExtensionDeps &&
     216       11644 :             ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
     217         742 :             continue;
     218             : 
     219       12178 :         CatalogTupleDelete(depRel, &tup->t_self);
     220       12178 :         count++;
     221             :     }
     222             : 
     223       31640 :     systable_endscan(scan);
     224             : 
     225       31640 :     table_close(depRel, RowExclusiveLock);
     226             : 
     227       31640 :     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        1018 : deleteDependencyRecordsForClass(Oid classId, Oid objectId,
     241             :                                 Oid refclassId, char deptype)
     242             : {
     243        1018 :     long        count = 0;
     244             :     Relation    depRel;
     245             :     ScanKeyData key[2];
     246             :     SysScanDesc scan;
     247             :     HeapTuple   tup;
     248             : 
     249        1018 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     250             : 
     251        1018 :     ScanKeyInit(&key[0],
     252             :                 Anum_pg_depend_classid,
     253             :                 BTEqualStrategyNumber, F_OIDEQ,
     254             :                 ObjectIdGetDatum(classId));
     255        1018 :     ScanKeyInit(&key[1],
     256             :                 Anum_pg_depend_objid,
     257             :                 BTEqualStrategyNumber, F_OIDEQ,
     258             :                 ObjectIdGetDatum(objectId));
     259             : 
     260        1018 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     261             :                               NULL, 2, key);
     262             : 
     263        3764 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     264             :     {
     265        1728 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     266             : 
     267        1728 :         if (depform->refclassid == refclassId && depform->deptype == deptype)
     268             :         {
     269         308 :             CatalogTupleDelete(depRel, &tup->t_self);
     270         308 :             count++;
     271             :         }
     272             :     }
     273             : 
     274        1018 :     systable_endscan(scan);
     275             : 
     276        1018 :     table_close(depRel, RowExclusiveLock);
     277             : 
     278        1018 :     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         128 : changeDependenciesOf(Oid classId, Oid oldObjectId,
     408             :                      Oid newObjectId)
     409             : {
     410         128 :     long        count = 0;
     411             :     Relation    depRel;
     412             :     ScanKeyData key[2];
     413             :     SysScanDesc scan;
     414             :     HeapTuple   tup;
     415             : 
     416         128 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     417             : 
     418         128 :     ScanKeyInit(&key[0],
     419             :                 Anum_pg_depend_classid,
     420             :                 BTEqualStrategyNumber, F_OIDEQ,
     421             :                 ObjectIdGetDatum(classId));
     422         128 :     ScanKeyInit(&key[1],
     423             :                 Anum_pg_depend_objid,
     424             :                 BTEqualStrategyNumber, F_OIDEQ,
     425             :                 ObjectIdGetDatum(oldObjectId));
     426             : 
     427         128 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     428             :                               NULL, 2, key);
     429             : 
     430         480 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     431             :     {
     432         224 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     433             : 
     434             :         /* make a modifiable copy */
     435         224 :         tup = heap_copytuple(tup);
     436         224 :         depform = (Form_pg_depend) GETSTRUCT(tup);
     437             : 
     438         224 :         depform->objid = newObjectId;
     439             : 
     440         224 :         CatalogTupleUpdate(depRel, &tup->t_self, tup);
     441             : 
     442         224 :         heap_freetuple(tup);
     443             : 
     444         224 :         count++;
     445             :     }
     446             : 
     447         128 :     systable_endscan(scan);
     448             : 
     449         128 :     table_close(depRel, RowExclusiveLock);
     450             : 
     451         128 :     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         128 : changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
     464             :                      Oid newRefObjectId)
     465             : {
     466         128 :     long        count = 0;
     467             :     Relation    depRel;
     468             :     ScanKeyData key[2];
     469             :     SysScanDesc scan;
     470             :     HeapTuple   tup;
     471             :     ObjectAddress objAddr;
     472             :     bool        newIsPinned;
     473             : 
     474         128 :     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         128 :     objAddr.classId = refClassId;
     483         128 :     objAddr.objectId = oldRefObjectId;
     484         128 :     objAddr.objectSubId = 0;
     485             : 
     486         128 :     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         128 :     objAddr.objectId = newRefObjectId;
     497             : 
     498         128 :     newIsPinned = isObjectPinned(&objAddr, depRel);
     499             : 
     500             :     /* Now search for dependency records */
     501         128 :     ScanKeyInit(&key[0],
     502             :                 Anum_pg_depend_refclassid,
     503             :                 BTEqualStrategyNumber, F_OIDEQ,
     504             :                 ObjectIdGetDatum(refClassId));
     505         128 :     ScanKeyInit(&key[1],
     506             :                 Anum_pg_depend_refobjid,
     507             :                 BTEqualStrategyNumber, F_OIDEQ,
     508             :                 ObjectIdGetDatum(oldRefObjectId));
     509             : 
     510         128 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     511             :                               NULL, 2, key);
     512             : 
     513         264 :     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         128 :     systable_endscan(scan);
     536             : 
     537         128 :     table_close(depRel, RowExclusiveLock);
     538             : 
     539         128 :     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     2588290 : isObjectPinned(const ObjectAddress *object, Relation rel)
     553             : {
     554     2588290 :     bool        ret = false;
     555             :     SysScanDesc scan;
     556             :     HeapTuple   tup;
     557             :     ScanKeyData key[2];
     558             : 
     559     2588290 :     ScanKeyInit(&key[0],
     560             :                 Anum_pg_depend_refclassid,
     561             :                 BTEqualStrategyNumber, F_OIDEQ,
     562     2588290 :                 ObjectIdGetDatum(object->classId));
     563             : 
     564     2588290 :     ScanKeyInit(&key[1],
     565             :                 Anum_pg_depend_refobjid,
     566             :                 BTEqualStrategyNumber, F_OIDEQ,
     567     2588290 :                 ObjectIdGetDatum(object->objectId));
     568             : 
     569     2588290 :     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     2588290 :     tup = systable_getnext(scan);
     579     2588290 :     if (HeapTupleIsValid(tup))
     580             :     {
     581     2448608 :         Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
     582             : 
     583     2448608 :         if (foundDep->deptype == DEPENDENCY_PIN)
     584     1870074 :             ret = true;
     585             :     }
     586             : 
     587     2588290 :     systable_endscan(scan);
     588             : 
     589     2588290 :     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         522 : sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
     664             : {
     665         522 :     bool        ret = false;
     666             :     Relation    depRel;
     667             :     ScanKeyData key[2];
     668             :     SysScanDesc scan;
     669             :     HeapTuple   tup;
     670             : 
     671         522 :     depRel = table_open(DependRelationId, AccessShareLock);
     672             : 
     673         522 :     ScanKeyInit(&key[0],
     674             :                 Anum_pg_depend_classid,
     675             :                 BTEqualStrategyNumber, F_OIDEQ,
     676             :                 ObjectIdGetDatum(RelationRelationId));
     677         522 :     ScanKeyInit(&key[1],
     678             :                 Anum_pg_depend_objid,
     679             :                 BTEqualStrategyNumber, F_OIDEQ,
     680             :                 ObjectIdGetDatum(seqId));
     681             : 
     682         522 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     683             :                               NULL, 2, key);
     684             : 
     685         522 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     686             :     {
     687         534 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     688             : 
     689         538 :         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         522 :     systable_endscan(scan);
     700             : 
     701         522 :     table_close(depRel, AccessShareLock);
     702             : 
     703         522 :     return ret;
     704             : }
     705             : 
     706             : /*
     707             :  * Collect a list of OIDs of all sequences owned by the specified relation,
     708             :  * and column if specified.  If deptype is not zero, then only find sequences
     709             :  * with the specified dependency type.
     710             :  */
     711             : static List *
     712         204 : getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
     713             : {
     714         204 :     List       *result = NIL;
     715             :     Relation    depRel;
     716             :     ScanKeyData key[3];
     717             :     SysScanDesc scan;
     718             :     HeapTuple   tup;
     719             : 
     720         204 :     depRel = table_open(DependRelationId, AccessShareLock);
     721             : 
     722         204 :     ScanKeyInit(&key[0],
     723             :                 Anum_pg_depend_refclassid,
     724             :                 BTEqualStrategyNumber, F_OIDEQ,
     725             :                 ObjectIdGetDatum(RelationRelationId));
     726         204 :     ScanKeyInit(&key[1],
     727             :                 Anum_pg_depend_refobjid,
     728             :                 BTEqualStrategyNumber, F_OIDEQ,
     729             :                 ObjectIdGetDatum(relid));
     730         204 :     if (attnum)
     731         186 :         ScanKeyInit(&key[2],
     732             :                     Anum_pg_depend_refobjsubid,
     733             :                     BTEqualStrategyNumber, F_INT4EQ,
     734             :                     Int32GetDatum(attnum));
     735             : 
     736         204 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     737             :                               NULL, attnum ? 3 : 2, key);
     738             : 
     739         684 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     740             :     {
     741         276 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     742             : 
     743             :         /*
     744             :          * We assume any auto or internal dependency of a sequence on a column
     745             :          * must be what we are looking for.  (We need the relkind test because
     746             :          * indexes can also have auto dependencies on columns.)
     747             :          */
     748         486 :         if (deprec->classid == RelationRelationId &&
     749         420 :             deprec->objsubid == 0 &&
     750         420 :             deprec->refobjsubid != 0 &&
     751         606 :             (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
     752         210 :             get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
     753             :         {
     754         210 :             if (!deptype || deprec->deptype == deptype)
     755         206 :                 result = lappend_oid(result, deprec->objid);
     756             :         }
     757             :     }
     758             : 
     759         204 :     systable_endscan(scan);
     760             : 
     761         204 :     table_close(depRel, AccessShareLock);
     762             : 
     763         204 :     return result;
     764             : }
     765             : 
     766             : /*
     767             :  * Collect a list of OIDs of all sequences owned (identity or serial) by the
     768             :  * specified relation.
     769             :  */
     770             : List *
     771          18 : getOwnedSequences(Oid relid)
     772             : {
     773          18 :     return getOwnedSequences_internal(relid, 0, 0);
     774             : }
     775             : 
     776             : /*
     777             :  * Get owned identity sequence, error if not exactly one.
     778             :  */
     779             : Oid
     780         186 : getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
     781             : {
     782         186 :     List       *seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
     783             : 
     784         186 :     if (list_length(seqlist) > 1)
     785           0 :         elog(ERROR, "more than one owned sequence found");
     786         186 :     else if (list_length(seqlist) < 1)
     787             :     {
     788           4 :         if (missing_ok)
     789           4 :             return InvalidOid;
     790             :         else
     791           0 :             elog(ERROR, "no owned sequence found");
     792             :     }
     793             : 
     794         182 :     return linitial_oid(seqlist);
     795             : }
     796             : 
     797             : /*
     798             :  * get_constraint_index
     799             :  *      Given the OID of a unique, primary-key, or exclusion constraint,
     800             :  *      return the OID of the underlying index.
     801             :  *
     802             :  * Return InvalidOid if the index couldn't be found; this suggests the
     803             :  * given OID is bogus, but we leave it to caller to decide what to do.
     804             :  */
     805             : Oid
     806        1236 : get_constraint_index(Oid constraintId)
     807             : {
     808        1236 :     Oid         indexId = InvalidOid;
     809             :     Relation    depRel;
     810             :     ScanKeyData key[3];
     811             :     SysScanDesc scan;
     812             :     HeapTuple   tup;
     813             : 
     814             :     /* Search the dependency table for the dependent index */
     815        1236 :     depRel = table_open(DependRelationId, AccessShareLock);
     816             : 
     817        1236 :     ScanKeyInit(&key[0],
     818             :                 Anum_pg_depend_refclassid,
     819             :                 BTEqualStrategyNumber, F_OIDEQ,
     820             :                 ObjectIdGetDatum(ConstraintRelationId));
     821        1236 :     ScanKeyInit(&key[1],
     822             :                 Anum_pg_depend_refobjid,
     823             :                 BTEqualStrategyNumber, F_OIDEQ,
     824             :                 ObjectIdGetDatum(constraintId));
     825        1236 :     ScanKeyInit(&key[2],
     826             :                 Anum_pg_depend_refobjsubid,
     827             :                 BTEqualStrategyNumber, F_INT4EQ,
     828             :                 Int32GetDatum(0));
     829             : 
     830        1236 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     831             :                               NULL, 3, key);
     832             : 
     833        1236 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     834             :     {
     835        1236 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     836             : 
     837             :         /*
     838             :          * We assume any internal dependency of an index on the constraint
     839             :          * must be what we are looking for.
     840             :          */
     841        2472 :         if (deprec->classid == RelationRelationId &&
     842        2472 :             deprec->objsubid == 0 &&
     843        1236 :             deprec->deptype == DEPENDENCY_INTERNAL)
     844             :         {
     845        1236 :             char        relkind = get_rel_relkind(deprec->objid);
     846             : 
     847             :             /*
     848             :              * This is pure paranoia; there shouldn't be any other relkinds
     849             :              * dependent on a constraint.
     850             :              */
     851        1236 :             if (relkind != RELKIND_INDEX &&
     852             :                 relkind != RELKIND_PARTITIONED_INDEX)
     853           0 :                 continue;
     854             : 
     855        1236 :             indexId = deprec->objid;
     856        1236 :             break;
     857             :         }
     858             :     }
     859             : 
     860        1236 :     systable_endscan(scan);
     861        1236 :     table_close(depRel, AccessShareLock);
     862             : 
     863        1236 :     return indexId;
     864             : }
     865             : 
     866             : /*
     867             :  * get_index_constraint
     868             :  *      Given the OID of an index, return the OID of the owning unique,
     869             :  *      primary-key, or exclusion constraint, or InvalidOid if there
     870             :  *      is no owning constraint.
     871             :  */
     872             : Oid
     873         924 : get_index_constraint(Oid indexId)
     874             : {
     875         924 :     Oid         constraintId = InvalidOid;
     876             :     Relation    depRel;
     877             :     ScanKeyData key[3];
     878             :     SysScanDesc scan;
     879             :     HeapTuple   tup;
     880             : 
     881             :     /* Search the dependency table for the index */
     882         924 :     depRel = table_open(DependRelationId, AccessShareLock);
     883             : 
     884         924 :     ScanKeyInit(&key[0],
     885             :                 Anum_pg_depend_classid,
     886             :                 BTEqualStrategyNumber, F_OIDEQ,
     887             :                 ObjectIdGetDatum(RelationRelationId));
     888         924 :     ScanKeyInit(&key[1],
     889             :                 Anum_pg_depend_objid,
     890             :                 BTEqualStrategyNumber, F_OIDEQ,
     891             :                 ObjectIdGetDatum(indexId));
     892         924 :     ScanKeyInit(&key[2],
     893             :                 Anum_pg_depend_objsubid,
     894             :                 BTEqualStrategyNumber, F_INT4EQ,
     895             :                 Int32GetDatum(0));
     896             : 
     897         924 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     898             :                               NULL, 3, key);
     899             : 
     900         924 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     901             :     {
     902        1336 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     903             : 
     904             :         /*
     905             :          * We assume any internal dependency on a constraint must be what we
     906             :          * are looking for.
     907             :          */
     908        1776 :         if (deprec->refclassid == ConstraintRelationId &&
     909         880 :             deprec->refobjsubid == 0 &&
     910         440 :             deprec->deptype == DEPENDENCY_INTERNAL)
     911             :         {
     912         440 :             constraintId = deprec->refobjid;
     913         440 :             break;
     914             :         }
     915             :     }
     916             : 
     917         924 :     systable_endscan(scan);
     918         924 :     table_close(depRel, AccessShareLock);
     919             : 
     920         924 :     return constraintId;
     921             : }
     922             : 
     923             : /*
     924             :  * get_index_ref_constraints
     925             :  *      Given the OID of an index, return the OID of all foreign key
     926             :  *      constraints which reference the index.
     927             :  */
     928             : List *
     929         128 : get_index_ref_constraints(Oid indexId)
     930             : {
     931         128 :     List       *result = NIL;
     932             :     Relation    depRel;
     933             :     ScanKeyData key[3];
     934             :     SysScanDesc scan;
     935             :     HeapTuple   tup;
     936             : 
     937             :     /* Search the dependency table for the index */
     938         128 :     depRel = table_open(DependRelationId, AccessShareLock);
     939             : 
     940         128 :     ScanKeyInit(&key[0],
     941             :                 Anum_pg_depend_refclassid,
     942             :                 BTEqualStrategyNumber, F_OIDEQ,
     943             :                 ObjectIdGetDatum(RelationRelationId));
     944         128 :     ScanKeyInit(&key[1],
     945             :                 Anum_pg_depend_refobjid,
     946             :                 BTEqualStrategyNumber, F_OIDEQ,
     947             :                 ObjectIdGetDatum(indexId));
     948         128 :     ScanKeyInit(&key[2],
     949             :                 Anum_pg_depend_refobjsubid,
     950             :                 BTEqualStrategyNumber, F_INT4EQ,
     951             :                 Int32GetDatum(0));
     952             : 
     953         128 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     954             :                               NULL, 3, key);
     955             : 
     956         264 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     957             :     {
     958           8 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     959             : 
     960             :         /*
     961             :          * We assume any normal dependency from a constraint must be what we
     962             :          * are looking for.
     963             :          */
     964          16 :         if (deprec->classid == ConstraintRelationId &&
     965          16 :             deprec->objsubid == 0 &&
     966           8 :             deprec->deptype == DEPENDENCY_NORMAL)
     967             :         {
     968           8 :             result = lappend_oid(result, deprec->objid);
     969             :         }
     970             :     }
     971             : 
     972         128 :     systable_endscan(scan);
     973         128 :     table_close(depRel, AccessShareLock);
     974             : 
     975         128 :     return result;
     976             : }

Generated by: LCOV version 1.13