LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_depend.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 301 308 97.7 %
Date: 2020-06-05 19:06:29 Functions: 19 19 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-2020, 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     2055352 : recordDependencyOn(const ObjectAddress *depender,
      44             :                    const ObjectAddress *referenced,
      45             :                    DependencyType behavior)
      46             : {
      47     2055352 :     recordMultipleDependencies(depender, referenced, 1, behavior);
      48     2055352 : }
      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     2153258 : 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     2153258 :     if (nreferenced <= 0)
      68      222756 :         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     2152462 :     if (IsBootstrapProcessingMode())
      75      221960 :         return;
      76             : 
      77     1930502 :     dependDesc = table_open(DependRelationId, RowExclusiveLock);
      78             : 
      79             :     /* Don't open indexes unless we need to make an update */
      80     1930502 :     indstate = NULL;
      81             : 
      82     1930502 :     memset(nulls, false, sizeof(nulls));
      83             : 
      84     4795898 :     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     2865396 :         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      787708 :             values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
      98      787708 :             values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
      99      787708 :             values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
     100             : 
     101      787708 :             values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
     102      787708 :             values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
     103      787708 :             values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
     104             : 
     105      787708 :             values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
     106             : 
     107      787708 :             tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
     108             : 
     109             :             /* fetch index info only when we know we need it */
     110      787708 :             if (indstate == NULL)
     111      639642 :                 indstate = CatalogOpenIndexes(dependDesc);
     112             : 
     113      787708 :             CatalogTupleInsertWithInfo(dependDesc, tup, indstate);
     114             : 
     115      787708 :             heap_freetuple(tup);
     116             :         }
     117             :     }
     118             : 
     119     1930502 :     if (indstate != NULL)
     120      639642 :         CatalogCloseIndexes(indstate);
     121             : 
     122     1930502 :     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      145722 : recordDependencyOnCurrentExtension(const ObjectAddress *object,
     139             :                                    bool isReplace)
     140             : {
     141             :     /* Only whole objects can be extension members */
     142             :     Assert(object->objectSubId == 0);
     143             : 
     144      145722 :     if (creating_extension)
     145             :     {
     146             :         ObjectAddress extension;
     147             : 
     148             :         /* Only need to check for existing membership if isReplace */
     149        7832 :         if (isReplace)
     150             :         {
     151             :             Oid         oldext;
     152             : 
     153        2118 :             oldext = getExtensionOfObject(object->classId, object->objectId);
     154        2118 :             if (OidIsValid(oldext))
     155             :             {
     156             :                 /* If already a member of this extension, nothing to do */
     157        1022 :                 if (oldext == CurrentExtensionObject)
     158        1022 :                     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        6810 :         extension.classId = ExtensionRelationId;
     170        6810 :         extension.objectId = CurrentExtensionObject;
     171        6810 :         extension.objectSubId = 0;
     172             : 
     173        6810 :         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       36164 : deleteDependencyRecordsFor(Oid classId, Oid objectId,
     191             :                            bool skipExtensionDeps)
     192             : {
     193       36164 :     long        count = 0;
     194             :     Relation    depRel;
     195             :     ScanKeyData key[2];
     196             :     SysScanDesc scan;
     197             :     HeapTuple   tup;
     198             : 
     199       36164 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     200             : 
     201       36164 :     ScanKeyInit(&key[0],
     202             :                 Anum_pg_depend_classid,
     203             :                 BTEqualStrategyNumber, F_OIDEQ,
     204             :                 ObjectIdGetDatum(classId));
     205       36164 :     ScanKeyInit(&key[1],
     206             :                 Anum_pg_depend_objid,
     207             :                 BTEqualStrategyNumber, F_OIDEQ,
     208             :                 ObjectIdGetDatum(objectId));
     209             : 
     210       36164 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     211             :                               NULL, 2, key);
     212             : 
     213       51110 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     214             :     {
     215       14946 :         if (skipExtensionDeps &&
     216       13858 :             ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
     217        1022 :             continue;
     218             : 
     219       13924 :         CatalogTupleDelete(depRel, &tup->t_self);
     220       13924 :         count++;
     221             :     }
     222             : 
     223       36164 :     systable_endscan(scan);
     224             : 
     225       36164 :     table_close(depRel, RowExclusiveLock);
     226             : 
     227       36164 :     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        1162 : deleteDependencyRecordsForClass(Oid classId, Oid objectId,
     241             :                                 Oid refclassId, char deptype)
     242             : {
     243        1162 :     long        count = 0;
     244             :     Relation    depRel;
     245             :     ScanKeyData key[2];
     246             :     SysScanDesc scan;
     247             :     HeapTuple   tup;
     248             : 
     249        1162 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     250             : 
     251        1162 :     ScanKeyInit(&key[0],
     252             :                 Anum_pg_depend_classid,
     253             :                 BTEqualStrategyNumber, F_OIDEQ,
     254             :                 ObjectIdGetDatum(classId));
     255        1162 :     ScanKeyInit(&key[1],
     256             :                 Anum_pg_depend_objid,
     257             :                 BTEqualStrategyNumber, F_OIDEQ,
     258             :                 ObjectIdGetDatum(objectId));
     259             : 
     260        1162 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     261             :                               NULL, 2, key);
     262             : 
     263        3176 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     264             :     {
     265        2014 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     266             : 
     267        2014 :         if (depform->refclassid == refclassId && depform->deptype == deptype)
     268             :         {
     269         380 :             CatalogTupleDelete(depRel, &tup->t_self);
     270         380 :             count++;
     271             :         }
     272             :     }
     273             : 
     274        1162 :     systable_endscan(scan);
     275             : 
     276        1162 :     table_close(depRel, RowExclusiveLock);
     277             : 
     278        1162 :     return count;
     279             : }
     280             : 
     281             : /*
     282             :  * deleteDependencyRecordsForSpecific -- delete all records with given depender
     283             :  * classId/objectId, dependee classId/objectId, of the given deptype.
     284             :  * Returns the number of records deleted.
     285             :  */
     286             : long
     287           8 : deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
     288             :                                    Oid refclassId, Oid refobjectId)
     289             : {
     290           8 :     long        count = 0;
     291             :     Relation    depRel;
     292             :     ScanKeyData key[2];
     293             :     SysScanDesc scan;
     294             :     HeapTuple   tup;
     295             : 
     296           8 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     297             : 
     298           8 :     ScanKeyInit(&key[0],
     299             :                 Anum_pg_depend_classid,
     300             :                 BTEqualStrategyNumber, F_OIDEQ,
     301             :                 ObjectIdGetDatum(classId));
     302           8 :     ScanKeyInit(&key[1],
     303             :                 Anum_pg_depend_objid,
     304             :                 BTEqualStrategyNumber, F_OIDEQ,
     305             :                 ObjectIdGetDatum(objectId));
     306             : 
     307           8 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     308             :                               NULL, 2, key);
     309             : 
     310          28 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     311             :     {
     312          20 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     313             : 
     314          20 :         if (depform->refclassid == refclassId &&
     315           8 :             depform->refobjid == refobjectId &&
     316           8 :             depform->deptype == deptype)
     317             :         {
     318           8 :             CatalogTupleDelete(depRel, &tup->t_self);
     319           8 :             count++;
     320             :         }
     321             :     }
     322             : 
     323           8 :     systable_endscan(scan);
     324             : 
     325           8 :     table_close(depRel, RowExclusiveLock);
     326             : 
     327           8 :     return count;
     328             : }
     329             : 
     330             : /*
     331             :  * Adjust dependency record(s) to point to a different object of the same type
     332             :  *
     333             :  * classId/objectId specify the referencing object.
     334             :  * refClassId/oldRefObjectId specify the old referenced object.
     335             :  * newRefObjectId is the new referenced object (must be of class refClassId).
     336             :  *
     337             :  * Note the lack of objsubid parameters.  If there are subobject references
     338             :  * they will all be readjusted.  Also, there is an expectation that we are
     339             :  * dealing with NORMAL dependencies: if we have to replace an (implicit)
     340             :  * dependency on a pinned object with an explicit dependency on an unpinned
     341             :  * one, the new one will be NORMAL.
     342             :  *
     343             :  * Returns the number of records updated -- zero indicates a problem.
     344             :  */
     345             : long
     346         154 : changeDependencyFor(Oid classId, Oid objectId,
     347             :                     Oid refClassId, Oid oldRefObjectId,
     348             :                     Oid newRefObjectId)
     349             : {
     350         154 :     long        count = 0;
     351             :     Relation    depRel;
     352             :     ScanKeyData key[2];
     353             :     SysScanDesc scan;
     354             :     HeapTuple   tup;
     355             :     ObjectAddress objAddr;
     356             :     ObjectAddress depAddr;
     357             :     bool        oldIsPinned;
     358             :     bool        newIsPinned;
     359             : 
     360         154 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     361             : 
     362             :     /*
     363             :      * Check to see if either oldRefObjectId or newRefObjectId is pinned.
     364             :      * Pinned objects should not have any dependency entries pointing to them,
     365             :      * so in these cases we should add or remove a pg_depend entry, or do
     366             :      * nothing at all, rather than update an entry as in the normal case.
     367             :      */
     368         154 :     objAddr.classId = refClassId;
     369         154 :     objAddr.objectId = oldRefObjectId;
     370         154 :     objAddr.objectSubId = 0;
     371             : 
     372         154 :     oldIsPinned = isObjectPinned(&objAddr, depRel);
     373             : 
     374         154 :     objAddr.objectId = newRefObjectId;
     375             : 
     376         154 :     newIsPinned = isObjectPinned(&objAddr, depRel);
     377             : 
     378         154 :     if (oldIsPinned)
     379             :     {
     380          10 :         table_close(depRel, RowExclusiveLock);
     381             : 
     382             :         /*
     383             :          * If both are pinned, we need do nothing.  However, return 1 not 0,
     384             :          * else callers will think this is an error case.
     385             :          */
     386          10 :         if (newIsPinned)
     387           0 :             return 1;
     388             : 
     389             :         /*
     390             :          * There is no old dependency record, but we should insert a new one.
     391             :          * Assume a normal dependency is wanted.
     392             :          */
     393          10 :         depAddr.classId = classId;
     394          10 :         depAddr.objectId = objectId;
     395          10 :         depAddr.objectSubId = 0;
     396          10 :         recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
     397             : 
     398          10 :         return 1;
     399             :     }
     400             : 
     401             :     /* There should be existing dependency record(s), so search. */
     402         144 :     ScanKeyInit(&key[0],
     403             :                 Anum_pg_depend_classid,
     404             :                 BTEqualStrategyNumber, F_OIDEQ,
     405             :                 ObjectIdGetDatum(classId));
     406         144 :     ScanKeyInit(&key[1],
     407             :                 Anum_pg_depend_objid,
     408             :                 BTEqualStrategyNumber, F_OIDEQ,
     409             :                 ObjectIdGetDatum(objectId));
     410             : 
     411         144 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     412             :                               NULL, 2, key);
     413             : 
     414         374 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     415             :     {
     416         230 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     417             : 
     418         230 :         if (depform->refclassid == refClassId &&
     419         144 :             depform->refobjid == oldRefObjectId)
     420             :         {
     421         144 :             if (newIsPinned)
     422          16 :                 CatalogTupleDelete(depRel, &tup->t_self);
     423             :             else
     424             :             {
     425             :                 /* make a modifiable copy */
     426         128 :                 tup = heap_copytuple(tup);
     427         128 :                 depform = (Form_pg_depend) GETSTRUCT(tup);
     428             : 
     429         128 :                 depform->refobjid = newRefObjectId;
     430             : 
     431         128 :                 CatalogTupleUpdate(depRel, &tup->t_self, tup);
     432             : 
     433         128 :                 heap_freetuple(tup);
     434             :             }
     435             : 
     436         144 :             count++;
     437             :         }
     438             :     }
     439             : 
     440         144 :     systable_endscan(scan);
     441             : 
     442         144 :     table_close(depRel, RowExclusiveLock);
     443             : 
     444         144 :     return count;
     445             : }
     446             : 
     447             : /*
     448             :  * Adjust all dependency records to come from a different object of the same type
     449             :  *
     450             :  * classId/oldObjectId specify the old referencing object.
     451             :  * newObjectId is the new referencing object (must be of class classId).
     452             :  *
     453             :  * Returns the number of records updated.
     454             :  */
     455             : long
     456         272 : changeDependenciesOf(Oid classId, Oid oldObjectId,
     457             :                      Oid newObjectId)
     458             : {
     459         272 :     long        count = 0;
     460             :     Relation    depRel;
     461             :     ScanKeyData key[2];
     462             :     SysScanDesc scan;
     463             :     HeapTuple   tup;
     464             : 
     465         272 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     466             : 
     467         272 :     ScanKeyInit(&key[0],
     468             :                 Anum_pg_depend_classid,
     469             :                 BTEqualStrategyNumber, F_OIDEQ,
     470             :                 ObjectIdGetDatum(classId));
     471         272 :     ScanKeyInit(&key[1],
     472             :                 Anum_pg_depend_objid,
     473             :                 BTEqualStrategyNumber, F_OIDEQ,
     474             :                 ObjectIdGetDatum(oldObjectId));
     475             : 
     476         272 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     477             :                               NULL, 2, key);
     478             : 
     479         704 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     480             :     {
     481         432 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     482             : 
     483             :         /* make a modifiable copy */
     484         432 :         tup = heap_copytuple(tup);
     485         432 :         depform = (Form_pg_depend) GETSTRUCT(tup);
     486             : 
     487         432 :         depform->objid = newObjectId;
     488             : 
     489         432 :         CatalogTupleUpdate(depRel, &tup->t_self, tup);
     490             : 
     491         432 :         heap_freetuple(tup);
     492             : 
     493         432 :         count++;
     494             :     }
     495             : 
     496         272 :     systable_endscan(scan);
     497             : 
     498         272 :     table_close(depRel, RowExclusiveLock);
     499             : 
     500         272 :     return count;
     501             : }
     502             : 
     503             : /*
     504             :  * Adjust all dependency records to point to a different object of the same type
     505             :  *
     506             :  * refClassId/oldRefObjectId specify the old referenced object.
     507             :  * newRefObjectId is the new referenced object (must be of class refClassId).
     508             :  *
     509             :  * Returns the number of records updated.
     510             :  */
     511             : long
     512         272 : changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
     513             :                      Oid newRefObjectId)
     514             : {
     515         272 :     long        count = 0;
     516             :     Relation    depRel;
     517             :     ScanKeyData key[2];
     518             :     SysScanDesc scan;
     519             :     HeapTuple   tup;
     520             :     ObjectAddress objAddr;
     521             :     bool        newIsPinned;
     522             : 
     523         272 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     524             : 
     525             :     /*
     526             :      * If oldRefObjectId is pinned, there won't be any dependency entries on
     527             :      * it --- we can't cope in that case.  (This isn't really worth expending
     528             :      * code to fix, in current usage; it just means you can't rename stuff out
     529             :      * of pg_catalog, which would likely be a bad move anyway.)
     530             :      */
     531         272 :     objAddr.classId = refClassId;
     532         272 :     objAddr.objectId = oldRefObjectId;
     533         272 :     objAddr.objectSubId = 0;
     534             : 
     535         272 :     if (isObjectPinned(&objAddr, depRel))
     536           0 :         ereport(ERROR,
     537             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     538             :                  errmsg("cannot remove dependency on %s because it is a system object",
     539             :                         getObjectDescription(&objAddr))));
     540             : 
     541             :     /*
     542             :      * We can handle adding a dependency on something pinned, though, since
     543             :      * that just means deleting the dependency entry.
     544             :      */
     545         272 :     objAddr.objectId = newRefObjectId;
     546             : 
     547         272 :     newIsPinned = isObjectPinned(&objAddr, depRel);
     548             : 
     549             :     /* Now search for dependency records */
     550         272 :     ScanKeyInit(&key[0],
     551             :                 Anum_pg_depend_refclassid,
     552             :                 BTEqualStrategyNumber, F_OIDEQ,
     553             :                 ObjectIdGetDatum(refClassId));
     554         272 :     ScanKeyInit(&key[1],
     555             :                 Anum_pg_depend_refobjid,
     556             :                 BTEqualStrategyNumber, F_OIDEQ,
     557             :                 ObjectIdGetDatum(oldRefObjectId));
     558             : 
     559         272 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     560             :                               NULL, 2, key);
     561             : 
     562         280 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     563             :     {
     564           8 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     565             : 
     566           8 :         if (newIsPinned)
     567           0 :             CatalogTupleDelete(depRel, &tup->t_self);
     568             :         else
     569             :         {
     570             :             /* make a modifiable copy */
     571           8 :             tup = heap_copytuple(tup);
     572           8 :             depform = (Form_pg_depend) GETSTRUCT(tup);
     573             : 
     574           8 :             depform->refobjid = newRefObjectId;
     575             : 
     576           8 :             CatalogTupleUpdate(depRel, &tup->t_self, tup);
     577             : 
     578           8 :             heap_freetuple(tup);
     579             :         }
     580             : 
     581           8 :         count++;
     582             :     }
     583             : 
     584         272 :     systable_endscan(scan);
     585             : 
     586         272 :     table_close(depRel, RowExclusiveLock);
     587             : 
     588         272 :     return count;
     589             : }
     590             : 
     591             : /*
     592             :  * isObjectPinned()
     593             :  *
     594             :  * Test if an object is required for basic database functionality.
     595             :  * Caller must already have opened pg_depend.
     596             :  *
     597             :  * The passed subId, if any, is ignored; we assume that only whole objects
     598             :  * are pinned (and that this implies pinning their components).
     599             :  */
     600             : static bool
     601     2866248 : isObjectPinned(const ObjectAddress *object, Relation rel)
     602             : {
     603     2866248 :     bool        ret = false;
     604             :     SysScanDesc scan;
     605             :     HeapTuple   tup;
     606             :     ScanKeyData key[2];
     607             : 
     608     2866248 :     ScanKeyInit(&key[0],
     609             :                 Anum_pg_depend_refclassid,
     610             :                 BTEqualStrategyNumber, F_OIDEQ,
     611     2866248 :                 ObjectIdGetDatum(object->classId));
     612             : 
     613     2866248 :     ScanKeyInit(&key[1],
     614             :                 Anum_pg_depend_refobjid,
     615             :                 BTEqualStrategyNumber, F_OIDEQ,
     616     2866248 :                 ObjectIdGetDatum(object->objectId));
     617             : 
     618     2866248 :     scan = systable_beginscan(rel, DependReferenceIndexId, true,
     619             :                               NULL, 2, key);
     620             : 
     621             :     /*
     622             :      * Since we won't generate additional pg_depend entries for pinned
     623             :      * objects, there can be at most one entry referencing a pinned object.
     624             :      * Hence, it's sufficient to look at the first returned tuple; we don't
     625             :      * need to loop.
     626             :      */
     627     2866248 :     tup = systable_getnext(scan);
     628     2866248 :     if (HeapTupleIsValid(tup))
     629             :     {
     630     2715554 :         Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
     631             : 
     632     2715554 :         if (foundDep->deptype == DEPENDENCY_PIN)
     633     2077714 :             ret = true;
     634             :     }
     635             : 
     636     2866248 :     systable_endscan(scan);
     637             : 
     638     2866248 :     return ret;
     639             : }
     640             : 
     641             : 
     642             : /*
     643             :  * Various special-purpose lookups and manipulations of pg_depend.
     644             :  */
     645             : 
     646             : 
     647             : /*
     648             :  * Find the extension containing the specified object, if any
     649             :  *
     650             :  * Returns the OID of the extension, or InvalidOid if the object does not
     651             :  * belong to any extension.
     652             :  *
     653             :  * Extension membership is marked by an EXTENSION dependency from the object
     654             :  * to the extension.  Note that the result will be indeterminate if pg_depend
     655             :  * contains links from this object to more than one extension ... but that
     656             :  * should never happen.
     657             :  */
     658             : Oid
     659        2270 : getExtensionOfObject(Oid classId, Oid objectId)
     660             : {
     661        2270 :     Oid         result = InvalidOid;
     662             :     Relation    depRel;
     663             :     ScanKeyData key[2];
     664             :     SysScanDesc scan;
     665             :     HeapTuple   tup;
     666             : 
     667        2270 :     depRel = table_open(DependRelationId, AccessShareLock);
     668             : 
     669        2270 :     ScanKeyInit(&key[0],
     670             :                 Anum_pg_depend_classid,
     671             :                 BTEqualStrategyNumber, F_OIDEQ,
     672             :                 ObjectIdGetDatum(classId));
     673        2270 :     ScanKeyInit(&key[1],
     674             :                 Anum_pg_depend_objid,
     675             :                 BTEqualStrategyNumber, F_OIDEQ,
     676             :                 ObjectIdGetDatum(objectId));
     677             : 
     678        2270 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     679             :                               NULL, 2, key);
     680             : 
     681        4722 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     682             :     {
     683        3560 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     684             : 
     685        3560 :         if (depform->refclassid == ExtensionRelationId &&
     686        1108 :             depform->deptype == DEPENDENCY_EXTENSION)
     687             :         {
     688        1108 :             result = depform->refobjid;
     689        1108 :             break;              /* no need to keep scanning */
     690             :         }
     691             :     }
     692             : 
     693        2270 :     systable_endscan(scan);
     694             : 
     695        2270 :     table_close(depRel, AccessShareLock);
     696             : 
     697        2270 :     return result;
     698             : }
     699             : 
     700             : /*
     701             :  * Return (possibly NIL) list of extensions that the given object depends on
     702             :  * in DEPENDENCY_AUTO_EXTENSION mode.
     703             :  */
     704             : List *
     705          38 : getAutoExtensionsOfObject(Oid classId, Oid objectId)
     706             : {
     707          38 :     List       *result = NIL;
     708             :     Relation    depRel;
     709             :     ScanKeyData key[2];
     710             :     SysScanDesc scan;
     711             :     HeapTuple   tup;
     712             : 
     713          38 :     depRel = table_open(DependRelationId, AccessShareLock);
     714             : 
     715          38 :     ScanKeyInit(&key[0],
     716             :                 Anum_pg_depend_classid,
     717             :                 BTEqualStrategyNumber, F_OIDEQ,
     718             :                 ObjectIdGetDatum(classId));
     719          38 :     ScanKeyInit(&key[1],
     720             :                 Anum_pg_depend_objid,
     721             :                 BTEqualStrategyNumber, F_OIDEQ,
     722             :                 ObjectIdGetDatum(objectId));
     723             : 
     724          38 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     725             :                               NULL, 2, key);
     726             : 
     727          96 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     728             :     {
     729          58 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     730             : 
     731          58 :         if (depform->refclassid == ExtensionRelationId &&
     732           2 :             depform->deptype == DEPENDENCY_AUTO_EXTENSION)
     733           2 :             result = lappend_oid(result, depform->refobjid);
     734             :     }
     735             : 
     736          38 :     systable_endscan(scan);
     737             : 
     738          38 :     table_close(depRel, AccessShareLock);
     739             : 
     740          38 :     return result;
     741             : }
     742             : 
     743             : /*
     744             :  * Detect whether a sequence is marked as "owned" by a column
     745             :  *
     746             :  * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
     747             :  * column.  If we find one, store the identity of the owning column
     748             :  * into *tableId and *colId and return true; else return false.
     749             :  *
     750             :  * Note: if there's more than one such pg_depend entry then you get
     751             :  * a random one of them returned into the out parameters.  This should
     752             :  * not happen, though.
     753             :  */
     754             : bool
     755         526 : sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
     756             : {
     757         526 :     bool        ret = false;
     758             :     Relation    depRel;
     759             :     ScanKeyData key[2];
     760             :     SysScanDesc scan;
     761             :     HeapTuple   tup;
     762             : 
     763         526 :     depRel = table_open(DependRelationId, AccessShareLock);
     764             : 
     765         526 :     ScanKeyInit(&key[0],
     766             :                 Anum_pg_depend_classid,
     767             :                 BTEqualStrategyNumber, F_OIDEQ,
     768             :                 ObjectIdGetDatum(RelationRelationId));
     769         526 :     ScanKeyInit(&key[1],
     770             :                 Anum_pg_depend_objid,
     771             :                 BTEqualStrategyNumber, F_OIDEQ,
     772             :                 ObjectIdGetDatum(seqId));
     773             : 
     774         526 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     775             :                               NULL, 2, key);
     776             : 
     777        1060 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     778             :     {
     779         538 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     780             : 
     781         538 :         if (depform->refclassid == RelationRelationId &&
     782           4 :             depform->deptype == deptype)
     783             :         {
     784           4 :             *tableId = depform->refobjid;
     785           4 :             *colId = depform->refobjsubid;
     786           4 :             ret = true;
     787           4 :             break;              /* no need to keep scanning */
     788             :         }
     789             :     }
     790             : 
     791         526 :     systable_endscan(scan);
     792             : 
     793         526 :     table_close(depRel, AccessShareLock);
     794             : 
     795         526 :     return ret;
     796             : }
     797             : 
     798             : /*
     799             :  * Collect a list of OIDs of all sequences owned by the specified relation,
     800             :  * and column if specified.  If deptype is not zero, then only find sequences
     801             :  * with the specified dependency type.
     802             :  */
     803             : static List *
     804         236 : getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
     805             : {
     806         236 :     List       *result = NIL;
     807             :     Relation    depRel;
     808             :     ScanKeyData key[3];
     809             :     SysScanDesc scan;
     810             :     HeapTuple   tup;
     811             : 
     812         236 :     depRel = table_open(DependRelationId, AccessShareLock);
     813             : 
     814         236 :     ScanKeyInit(&key[0],
     815             :                 Anum_pg_depend_refclassid,
     816             :                 BTEqualStrategyNumber, F_OIDEQ,
     817             :                 ObjectIdGetDatum(RelationRelationId));
     818         236 :     ScanKeyInit(&key[1],
     819             :                 Anum_pg_depend_refobjid,
     820             :                 BTEqualStrategyNumber, F_OIDEQ,
     821             :                 ObjectIdGetDatum(relid));
     822         236 :     if (attnum)
     823         218 :         ScanKeyInit(&key[2],
     824             :                     Anum_pg_depend_refobjsubid,
     825             :                     BTEqualStrategyNumber, F_INT4EQ,
     826             :                     Int32GetDatum(attnum));
     827             : 
     828         236 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     829             :                               NULL, attnum ? 3 : 2, key);
     830             : 
     831         540 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     832             :     {
     833         304 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     834             : 
     835             :         /*
     836             :          * We assume any auto or internal dependency of a sequence on a column
     837             :          * must be what we are looking for.  (We need the relkind test because
     838             :          * indexes can also have auto dependencies on columns.)
     839             :          */
     840         304 :         if (deprec->classid == RelationRelationId &&
     841         238 :             deprec->objsubid == 0 &&
     842         238 :             deprec->refobjsubid != 0 &&
     843         476 :             (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
     844         238 :             get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
     845             :         {
     846         238 :             if (!deptype || deprec->deptype == deptype)
     847         234 :                 result = lappend_oid(result, deprec->objid);
     848             :         }
     849             :     }
     850             : 
     851         236 :     systable_endscan(scan);
     852             : 
     853         236 :     table_close(depRel, AccessShareLock);
     854             : 
     855         236 :     return result;
     856             : }
     857             : 
     858             : /*
     859             :  * Collect a list of OIDs of all sequences owned (identity or serial) by the
     860             :  * specified relation.
     861             :  */
     862             : List *
     863          18 : getOwnedSequences(Oid relid)
     864             : {
     865          18 :     return getOwnedSequences_internal(relid, 0, 0);
     866             : }
     867             : 
     868             : /*
     869             :  * Get owned identity sequence, error if not exactly one.
     870             :  */
     871             : Oid
     872         218 : getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
     873             : {
     874         218 :     List       *seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
     875             : 
     876         218 :     if (list_length(seqlist) > 1)
     877           0 :         elog(ERROR, "more than one owned sequence found");
     878         218 :     else if (list_length(seqlist) < 1)
     879             :     {
     880           8 :         if (missing_ok)
     881           8 :             return InvalidOid;
     882             :         else
     883           0 :             elog(ERROR, "no owned sequence found");
     884             :     }
     885             : 
     886         210 :     return linitial_oid(seqlist);
     887             : }
     888             : 
     889             : /*
     890             :  * get_constraint_index
     891             :  *      Given the OID of a unique, primary-key, or exclusion constraint,
     892             :  *      return the OID of the underlying index.
     893             :  *
     894             :  * Return InvalidOid if the index couldn't be found; this suggests the
     895             :  * given OID is bogus, but we leave it to caller to decide what to do.
     896             :  */
     897             : Oid
     898        1564 : get_constraint_index(Oid constraintId)
     899             : {
     900        1564 :     Oid         indexId = InvalidOid;
     901             :     Relation    depRel;
     902             :     ScanKeyData key[3];
     903             :     SysScanDesc scan;
     904             :     HeapTuple   tup;
     905             : 
     906             :     /* Search the dependency table for the dependent index */
     907        1564 :     depRel = table_open(DependRelationId, AccessShareLock);
     908             : 
     909        1564 :     ScanKeyInit(&key[0],
     910             :                 Anum_pg_depend_refclassid,
     911             :                 BTEqualStrategyNumber, F_OIDEQ,
     912             :                 ObjectIdGetDatum(ConstraintRelationId));
     913        1564 :     ScanKeyInit(&key[1],
     914             :                 Anum_pg_depend_refobjid,
     915             :                 BTEqualStrategyNumber, F_OIDEQ,
     916             :                 ObjectIdGetDatum(constraintId));
     917        1564 :     ScanKeyInit(&key[2],
     918             :                 Anum_pg_depend_refobjsubid,
     919             :                 BTEqualStrategyNumber, F_INT4EQ,
     920             :                 Int32GetDatum(0));
     921             : 
     922        1564 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     923             :                               NULL, 3, key);
     924             : 
     925        1648 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     926             :     {
     927        1572 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     928             : 
     929             :         /*
     930             :          * We assume any internal dependency of an index on the constraint
     931             :          * must be what we are looking for.
     932             :          */
     933        1572 :         if (deprec->classid == RelationRelationId &&
     934        1488 :             deprec->objsubid == 0 &&
     935        1488 :             deprec->deptype == DEPENDENCY_INTERNAL)
     936             :         {
     937        1488 :             char        relkind = get_rel_relkind(deprec->objid);
     938             : 
     939             :             /*
     940             :              * This is pure paranoia; there shouldn't be any other relkinds
     941             :              * dependent on a constraint.
     942             :              */
     943        1488 :             if (relkind != RELKIND_INDEX &&
     944             :                 relkind != RELKIND_PARTITIONED_INDEX)
     945           0 :                 continue;
     946             : 
     947        1488 :             indexId = deprec->objid;
     948        1488 :             break;
     949             :         }
     950             :     }
     951             : 
     952        1564 :     systable_endscan(scan);
     953        1564 :     table_close(depRel, AccessShareLock);
     954             : 
     955        1564 :     return indexId;
     956             : }
     957             : 
     958             : /*
     959             :  * get_index_constraint
     960             :  *      Given the OID of an index, return the OID of the owning unique,
     961             :  *      primary-key, or exclusion constraint, or InvalidOid if there
     962             :  *      is no owning constraint.
     963             :  */
     964             : Oid
     965        1040 : get_index_constraint(Oid indexId)
     966             : {
     967        1040 :     Oid         constraintId = InvalidOid;
     968             :     Relation    depRel;
     969             :     ScanKeyData key[3];
     970             :     SysScanDesc scan;
     971             :     HeapTuple   tup;
     972             : 
     973             :     /* Search the dependency table for the index */
     974        1040 :     depRel = table_open(DependRelationId, AccessShareLock);
     975             : 
     976        1040 :     ScanKeyInit(&key[0],
     977             :                 Anum_pg_depend_classid,
     978             :                 BTEqualStrategyNumber, F_OIDEQ,
     979             :                 ObjectIdGetDatum(RelationRelationId));
     980        1040 :     ScanKeyInit(&key[1],
     981             :                 Anum_pg_depend_objid,
     982             :                 BTEqualStrategyNumber, F_OIDEQ,
     983             :                 ObjectIdGetDatum(indexId));
     984        1040 :     ScanKeyInit(&key[2],
     985             :                 Anum_pg_depend_objsubid,
     986             :                 BTEqualStrategyNumber, F_INT4EQ,
     987             :                 Int32GetDatum(0));
     988             : 
     989        1040 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     990             :                               NULL, 3, key);
     991             : 
     992        1972 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     993             :     {
     994        1448 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     995             : 
     996             :         /*
     997             :          * We assume any internal dependency on a constraint must be what we
     998             :          * are looking for.
     999             :          */
    1000        1448 :         if (deprec->refclassid == ConstraintRelationId &&
    1001         516 :             deprec->refobjsubid == 0 &&
    1002         516 :             deprec->deptype == DEPENDENCY_INTERNAL)
    1003             :         {
    1004         516 :             constraintId = deprec->refobjid;
    1005         516 :             break;
    1006             :         }
    1007             :     }
    1008             : 
    1009        1040 :     systable_endscan(scan);
    1010        1040 :     table_close(depRel, AccessShareLock);
    1011             : 
    1012        1040 :     return constraintId;
    1013             : }
    1014             : 
    1015             : /*
    1016             :  * get_index_ref_constraints
    1017             :  *      Given the OID of an index, return the OID of all foreign key
    1018             :  *      constraints which reference the index.
    1019             :  */
    1020             : List *
    1021         136 : get_index_ref_constraints(Oid indexId)
    1022             : {
    1023         136 :     List       *result = NIL;
    1024             :     Relation    depRel;
    1025             :     ScanKeyData key[3];
    1026             :     SysScanDesc scan;
    1027             :     HeapTuple   tup;
    1028             : 
    1029             :     /* Search the dependency table for the index */
    1030         136 :     depRel = table_open(DependRelationId, AccessShareLock);
    1031             : 
    1032         136 :     ScanKeyInit(&key[0],
    1033             :                 Anum_pg_depend_refclassid,
    1034             :                 BTEqualStrategyNumber, F_OIDEQ,
    1035             :                 ObjectIdGetDatum(RelationRelationId));
    1036         136 :     ScanKeyInit(&key[1],
    1037             :                 Anum_pg_depend_refobjid,
    1038             :                 BTEqualStrategyNumber, F_OIDEQ,
    1039             :                 ObjectIdGetDatum(indexId));
    1040         136 :     ScanKeyInit(&key[2],
    1041             :                 Anum_pg_depend_refobjsubid,
    1042             :                 BTEqualStrategyNumber, F_INT4EQ,
    1043             :                 Int32GetDatum(0));
    1044             : 
    1045         136 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
    1046             :                               NULL, 3, key);
    1047             : 
    1048         144 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
    1049             :     {
    1050           8 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
    1051             : 
    1052             :         /*
    1053             :          * We assume any normal dependency from a constraint must be what we
    1054             :          * are looking for.
    1055             :          */
    1056           8 :         if (deprec->classid == ConstraintRelationId &&
    1057           8 :             deprec->objsubid == 0 &&
    1058           8 :             deprec->deptype == DEPENDENCY_NORMAL)
    1059             :         {
    1060           8 :             result = lappend_oid(result, deprec->objid);
    1061             :         }
    1062             :     }
    1063             : 
    1064         136 :     systable_endscan(scan);
    1065         136 :     table_close(depRel, AccessShareLock);
    1066             : 
    1067         136 :     return result;
    1068             : }

Generated by: LCOV version 1.13