LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_depend.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 293 299 98.0 %
Date: 2023-05-30 17:15:13 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-2023, 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/catalog.h"
      21             : #include "catalog/dependency.h"
      22             : #include "catalog/indexing.h"
      23             : #include "catalog/pg_constraint.h"
      24             : #include "catalog/pg_depend.h"
      25             : #include "catalog/pg_extension.h"
      26             : #include "commands/extension.h"
      27             : #include "miscadmin.h"
      28             : #include "utils/fmgroids.h"
      29             : #include "utils/lsyscache.h"
      30             : #include "utils/rel.h"
      31             : 
      32             : 
      33             : static bool isObjectPinned(const ObjectAddress *object);
      34             : 
      35             : 
      36             : /*
      37             :  * Record a dependency between 2 objects via their respective objectAddress.
      38             :  * The first argument is the dependent object, the second the one it
      39             :  * references.
      40             :  *
      41             :  * This simply creates an entry in pg_depend, without any other processing.
      42             :  */
      43             : void
      44     2868792 : recordDependencyOn(const ObjectAddress *depender,
      45             :                    const ObjectAddress *referenced,
      46             :                    DependencyType behavior)
      47             : {
      48     2868792 :     recordMultipleDependencies(depender, referenced, 1, behavior);
      49     2868792 : }
      50             : 
      51             : /*
      52             :  * Record multiple dependencies (of the same kind) for a single dependent
      53             :  * object.  This has a little less overhead than recording each separately.
      54             :  */
      55             : void
      56     3785466 : recordMultipleDependencies(const ObjectAddress *depender,
      57             :                            const ObjectAddress *referenced,
      58             :                            int nreferenced,
      59             :                            DependencyType behavior)
      60             : {
      61             :     Relation    dependDesc;
      62             :     CatalogIndexState indstate;
      63             :     TupleTableSlot **slot;
      64             :     int         i,
      65             :                 max_slots,
      66             :                 slot_init_count,
      67             :                 slot_stored_count;
      68             : 
      69     3785466 :     if (nreferenced <= 0)
      70       79704 :         return;                 /* nothing to do */
      71             : 
      72             :     /*
      73             :      * During bootstrap, do nothing since pg_depend may not exist yet.
      74             :      *
      75             :      * Objects created during bootstrap are most likely pinned, and the few
      76             :      * that are not do not have dependencies on each other, so that there
      77             :      * would be no need to make a pg_depend entry anyway.
      78             :      */
      79     3705762 :     if (IsBootstrapProcessingMode())
      80      403596 :         return;
      81             : 
      82     3302166 :     dependDesc = table_open(DependRelationId, RowExclusiveLock);
      83             : 
      84             :     /*
      85             :      * Allocate the slots to use, but delay costly initialization until we
      86             :      * know that they will be used.
      87             :      */
      88     3302166 :     max_slots = Min(nreferenced,
      89             :                     MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_depend));
      90     3302166 :     slot = palloc(sizeof(TupleTableSlot *) * max_slots);
      91             : 
      92             :     /* Don't open indexes unless we need to make an update */
      93     3302166 :     indstate = NULL;
      94             : 
      95             :     /* number of slots currently storing tuples */
      96     3302166 :     slot_stored_count = 0;
      97             :     /* number of slots currently initialized */
      98     3302166 :     slot_init_count = 0;
      99     9831156 :     for (i = 0; i < nreferenced; i++, referenced++)
     100             :     {
     101             :         /*
     102             :          * If the referenced object is pinned by the system, there's no real
     103             :          * need to record dependencies on it.  This saves lots of space in
     104             :          * pg_depend, so it's worth the time taken to check.
     105             :          */
     106     6528990 :         if (isObjectPinned(referenced))
     107     5164906 :             continue;
     108             : 
     109     1364084 :         if (slot_init_count < max_slots)
     110             :         {
     111     1364084 :             slot[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc),
     112             :                                                                &TTSOpsHeapTuple);
     113     1364084 :             slot_init_count++;
     114             :         }
     115             : 
     116     1364084 :         ExecClearTuple(slot[slot_stored_count]);
     117             : 
     118             :         /*
     119             :          * Record the dependency.  Note we don't bother to check for duplicate
     120             :          * dependencies; there's no harm in them.
     121             :          */
     122     1364084 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
     123     1364084 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
     124     1364084 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
     125     1364084 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
     126     1364084 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
     127     1364084 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
     128     1364084 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
     129             : 
     130     1364084 :         memset(slot[slot_stored_count]->tts_isnull, false,
     131     1364084 :                slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
     132             : 
     133     1364084 :         ExecStoreVirtualTuple(slot[slot_stored_count]);
     134     1364084 :         slot_stored_count++;
     135             : 
     136             :         /* If slots are full, insert a batch of tuples */
     137     1364084 :         if (slot_stored_count == max_slots)
     138             :         {
     139             :             /* fetch index info only when we know we need it */
     140      949636 :             if (indstate == NULL)
     141      949636 :                 indstate = CatalogOpenIndexes(dependDesc);
     142             : 
     143      949636 :             CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
     144             :                                              indstate);
     145      949636 :             slot_stored_count = 0;
     146             :         }
     147             :     }
     148             : 
     149             :     /* Insert any tuples left in the buffer */
     150     3302166 :     if (slot_stored_count > 0)
     151             :     {
     152             :         /* fetch index info only when we know we need it */
     153      163602 :         if (indstate == NULL)
     154      163602 :             indstate = CatalogOpenIndexes(dependDesc);
     155             : 
     156      163602 :         CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
     157             :                                          indstate);
     158             :     }
     159             : 
     160     3302166 :     if (indstate != NULL)
     161     1113238 :         CatalogCloseIndexes(indstate);
     162             : 
     163     3302166 :     table_close(dependDesc, RowExclusiveLock);
     164             : 
     165             :     /* Drop only the number of slots used */
     166     4666250 :     for (i = 0; i < slot_init_count; i++)
     167     1364084 :         ExecDropSingleTupleTableSlot(slot[i]);
     168     3302166 :     pfree(slot);
     169             : }
     170             : 
     171             : /*
     172             :  * If we are executing a CREATE EXTENSION operation, mark the given object
     173             :  * as being a member of the extension, or check that it already is one.
     174             :  * Otherwise, do nothing.
     175             :  *
     176             :  * This must be called during creation of any user-definable object type
     177             :  * that could be a member of an extension.
     178             :  *
     179             :  * isReplace must be true if the object already existed, and false if it is
     180             :  * newly created.  In the former case we insist that it already be a member
     181             :  * of the current extension.  In the latter case we can skip checking whether
     182             :  * it is already a member of any extension.
     183             :  *
     184             :  * Note: isReplace = true is typically used when updating an object in
     185             :  * CREATE OR REPLACE and similar commands.  We used to allow the target
     186             :  * object to not already be an extension member, instead silently absorbing
     187             :  * it into the current extension.  However, this was both error-prone
     188             :  * (extensions might accidentally overwrite free-standing objects) and
     189             :  * a security hazard (since the object would retain its previous ownership).
     190             :  */
     191             : void
     192      764828 : recordDependencyOnCurrentExtension(const ObjectAddress *object,
     193             :                                    bool isReplace)
     194             : {
     195             :     /* Only whole objects can be extension members */
     196             :     Assert(object->objectSubId == 0);
     197             : 
     198      764828 :     if (creating_extension)
     199             :     {
     200             :         ObjectAddress extension;
     201             : 
     202             :         /* Only need to check for existing membership if isReplace */
     203        9602 :         if (isReplace)
     204             :         {
     205             :             Oid         oldext;
     206             : 
     207             :             /*
     208             :              * Side note: these catalog lookups are safe only because the
     209             :              * object is a pre-existing one.  In the not-isReplace case, the
     210             :              * caller has most likely not yet done a CommandCounterIncrement
     211             :              * that would make the new object visible.
     212             :              */
     213         634 :             oldext = getExtensionOfObject(object->classId, object->objectId);
     214         634 :             if (OidIsValid(oldext))
     215             :             {
     216             :                 /* If already a member of this extension, nothing to do */
     217         626 :                 if (oldext == CurrentExtensionObject)
     218         626 :                     return;
     219             :                 /* Already a member of some other extension, so reject */
     220           0 :                 ereport(ERROR,
     221             :                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     222             :                          errmsg("%s is already a member of extension \"%s\"",
     223             :                                 getObjectDescription(object, false),
     224             :                                 get_extension_name(oldext))));
     225             :             }
     226             :             /* It's a free-standing object, so reject */
     227           8 :             ereport(ERROR,
     228             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     229             :                      errmsg("%s is not a member of extension \"%s\"",
     230             :                             getObjectDescription(object, false),
     231             :                             get_extension_name(CurrentExtensionObject)),
     232             :                      errdetail("An extension is not allowed to replace an object that it does not own.")));
     233             :         }
     234             : 
     235             :         /* OK, record it as a member of CurrentExtensionObject */
     236        8968 :         extension.classId = ExtensionRelationId;
     237        8968 :         extension.objectId = CurrentExtensionObject;
     238        8968 :         extension.objectSubId = 0;
     239             : 
     240        8968 :         recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
     241             :     }
     242             : }
     243             : 
     244             : /*
     245             :  * If we are executing a CREATE EXTENSION operation, check that the given
     246             :  * object is a member of the extension, and throw an error if it isn't.
     247             :  * Otherwise, do nothing.
     248             :  *
     249             :  * This must be called whenever a CREATE IF NOT EXISTS operation (for an
     250             :  * object type that can be an extension member) has found that an object of
     251             :  * the desired name already exists.  It is insecure for an extension to use
     252             :  * IF NOT EXISTS except when the conflicting object is already an extension
     253             :  * member; otherwise a hostile user could substitute an object with arbitrary
     254             :  * properties.
     255             :  */
     256             : void
     257         138 : checkMembershipInCurrentExtension(const ObjectAddress *object)
     258             : {
     259             :     /*
     260             :      * This is actually the same condition tested in
     261             :      * recordDependencyOnCurrentExtension; but we want to issue a
     262             :      * differently-worded error, and anyway it would be pretty confusing to
     263             :      * call recordDependencyOnCurrentExtension in these circumstances.
     264             :      */
     265             : 
     266             :     /* Only whole objects can be extension members */
     267             :     Assert(object->objectSubId == 0);
     268             : 
     269         138 :     if (creating_extension)
     270             :     {
     271             :         Oid         oldext;
     272             : 
     273          28 :         oldext = getExtensionOfObject(object->classId, object->objectId);
     274             :         /* If already a member of this extension, OK */
     275          28 :         if (oldext == CurrentExtensionObject)
     276          14 :             return;
     277             :         /* Else complain */
     278          14 :         ereport(ERROR,
     279             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     280             :                  errmsg("%s is not a member of extension \"%s\"",
     281             :                         getObjectDescription(object, false),
     282             :                         get_extension_name(CurrentExtensionObject)),
     283             :                  errdetail("An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.")));
     284             :     }
     285             : }
     286             : 
     287             : /*
     288             :  * deleteDependencyRecordsFor -- delete all records with given depender
     289             :  * classId/objectId.  Returns the number of records deleted.
     290             :  *
     291             :  * This is used when redefining an existing object.  Links leading to the
     292             :  * object do not change, and links leading from it will be recreated
     293             :  * (possibly with some differences from before).
     294             :  *
     295             :  * If skipExtensionDeps is true, we do not delete any dependencies that
     296             :  * show that the given object is a member of an extension.  This avoids
     297             :  * needing a lot of extra logic to fetch and recreate that dependency.
     298             :  */
     299             : long
     300       99850 : deleteDependencyRecordsFor(Oid classId, Oid objectId,
     301             :                            bool skipExtensionDeps)
     302             : {
     303       99850 :     long        count = 0;
     304             :     Relation    depRel;
     305             :     ScanKeyData key[2];
     306             :     SysScanDesc scan;
     307             :     HeapTuple   tup;
     308             : 
     309       99850 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     310             : 
     311       99850 :     ScanKeyInit(&key[0],
     312             :                 Anum_pg_depend_classid,
     313             :                 BTEqualStrategyNumber, F_OIDEQ,
     314             :                 ObjectIdGetDatum(classId));
     315       99850 :     ScanKeyInit(&key[1],
     316             :                 Anum_pg_depend_objid,
     317             :                 BTEqualStrategyNumber, F_OIDEQ,
     318             :                 ObjectIdGetDatum(objectId));
     319             : 
     320       99850 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     321             :                               NULL, 2, key);
     322             : 
     323      125276 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     324             :     {
     325       25426 :         if (skipExtensionDeps &&
     326       23664 :             ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
     327        1094 :             continue;
     328             : 
     329       24332 :         CatalogTupleDelete(depRel, &tup->t_self);
     330       24332 :         count++;
     331             :     }
     332             : 
     333       99850 :     systable_endscan(scan);
     334             : 
     335       99850 :     table_close(depRel, RowExclusiveLock);
     336             : 
     337       99850 :     return count;
     338             : }
     339             : 
     340             : /*
     341             :  * deleteDependencyRecordsForClass -- delete all records with given depender
     342             :  * classId/objectId, dependee classId, and deptype.
     343             :  * Returns the number of records deleted.
     344             :  *
     345             :  * This is a variant of deleteDependencyRecordsFor, useful when revoking
     346             :  * an object property that is expressed by a dependency record (such as
     347             :  * extension membership).
     348             :  */
     349             : long
     350       68658 : deleteDependencyRecordsForClass(Oid classId, Oid objectId,
     351             :                                 Oid refclassId, char deptype)
     352             : {
     353       68658 :     long        count = 0;
     354             :     Relation    depRel;
     355             :     ScanKeyData key[2];
     356             :     SysScanDesc scan;
     357             :     HeapTuple   tup;
     358             : 
     359       68658 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     360             : 
     361       68658 :     ScanKeyInit(&key[0],
     362             :                 Anum_pg_depend_classid,
     363             :                 BTEqualStrategyNumber, F_OIDEQ,
     364             :                 ObjectIdGetDatum(classId));
     365       68658 :     ScanKeyInit(&key[1],
     366             :                 Anum_pg_depend_objid,
     367             :                 BTEqualStrategyNumber, F_OIDEQ,
     368             :                 ObjectIdGetDatum(objectId));
     369             : 
     370       68658 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     371             :                               NULL, 2, key);
     372             : 
     373       73216 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     374             :     {
     375        4558 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     376             : 
     377        4558 :         if (depform->refclassid == refclassId && depform->deptype == deptype)
     378             :         {
     379         872 :             CatalogTupleDelete(depRel, &tup->t_self);
     380         872 :             count++;
     381             :         }
     382             :     }
     383             : 
     384       68658 :     systable_endscan(scan);
     385             : 
     386       68658 :     table_close(depRel, RowExclusiveLock);
     387             : 
     388       68658 :     return count;
     389             : }
     390             : 
     391             : /*
     392             :  * deleteDependencyRecordsForSpecific -- delete all records with given depender
     393             :  * classId/objectId, dependee classId/objectId, of the given deptype.
     394             :  * Returns the number of records deleted.
     395             :  */
     396             : long
     397           8 : deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
     398             :                                    Oid refclassId, Oid refobjectId)
     399             : {
     400           8 :     long        count = 0;
     401             :     Relation    depRel;
     402             :     ScanKeyData key[2];
     403             :     SysScanDesc scan;
     404             :     HeapTuple   tup;
     405             : 
     406           8 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     407             : 
     408           8 :     ScanKeyInit(&key[0],
     409             :                 Anum_pg_depend_classid,
     410             :                 BTEqualStrategyNumber, F_OIDEQ,
     411             :                 ObjectIdGetDatum(classId));
     412           8 :     ScanKeyInit(&key[1],
     413             :                 Anum_pg_depend_objid,
     414             :                 BTEqualStrategyNumber, F_OIDEQ,
     415             :                 ObjectIdGetDatum(objectId));
     416             : 
     417           8 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     418             :                               NULL, 2, key);
     419             : 
     420          28 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     421             :     {
     422          20 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     423             : 
     424          20 :         if (depform->refclassid == refclassId &&
     425           8 :             depform->refobjid == refobjectId &&
     426           8 :             depform->deptype == deptype)
     427             :         {
     428           8 :             CatalogTupleDelete(depRel, &tup->t_self);
     429           8 :             count++;
     430             :         }
     431             :     }
     432             : 
     433           8 :     systable_endscan(scan);
     434             : 
     435           8 :     table_close(depRel, RowExclusiveLock);
     436             : 
     437           8 :     return count;
     438             : }
     439             : 
     440             : /*
     441             :  * Adjust dependency record(s) to point to a different object of the same type
     442             :  *
     443             :  * classId/objectId specify the referencing object.
     444             :  * refClassId/oldRefObjectId specify the old referenced object.
     445             :  * newRefObjectId is the new referenced object (must be of class refClassId).
     446             :  *
     447             :  * Note the lack of objsubid parameters.  If there are subobject references
     448             :  * they will all be readjusted.  Also, there is an expectation that we are
     449             :  * dealing with NORMAL dependencies: if we have to replace an (implicit)
     450             :  * dependency on a pinned object with an explicit dependency on an unpinned
     451             :  * one, the new one will be NORMAL.
     452             :  *
     453             :  * Returns the number of records updated -- zero indicates a problem.
     454             :  */
     455             : long
     456         252 : changeDependencyFor(Oid classId, Oid objectId,
     457             :                     Oid refClassId, Oid oldRefObjectId,
     458             :                     Oid newRefObjectId)
     459             : {
     460         252 :     long        count = 0;
     461             :     Relation    depRel;
     462             :     ScanKeyData key[2];
     463             :     SysScanDesc scan;
     464             :     HeapTuple   tup;
     465             :     ObjectAddress objAddr;
     466             :     ObjectAddress depAddr;
     467             :     bool        oldIsPinned;
     468             :     bool        newIsPinned;
     469             : 
     470             :     /*
     471             :      * Check to see if either oldRefObjectId or newRefObjectId is pinned.
     472             :      * Pinned objects should not have any dependency entries pointing to them,
     473             :      * so in these cases we should add or remove a pg_depend entry, or do
     474             :      * nothing at all, rather than update an entry as in the normal case.
     475             :      */
     476         252 :     objAddr.classId = refClassId;
     477         252 :     objAddr.objectId = oldRefObjectId;
     478         252 :     objAddr.objectSubId = 0;
     479             : 
     480         252 :     oldIsPinned = isObjectPinned(&objAddr);
     481             : 
     482         252 :     objAddr.objectId = newRefObjectId;
     483             : 
     484         252 :     newIsPinned = isObjectPinned(&objAddr);
     485             : 
     486         252 :     if (oldIsPinned)
     487             :     {
     488             :         /*
     489             :          * If both are pinned, we need do nothing.  However, return 1 not 0,
     490             :          * else callers will think this is an error case.
     491             :          */
     492          14 :         if (newIsPinned)
     493           0 :             return 1;
     494             : 
     495             :         /*
     496             :          * There is no old dependency record, but we should insert a new one.
     497             :          * Assume a normal dependency is wanted.
     498             :          */
     499          14 :         depAddr.classId = classId;
     500          14 :         depAddr.objectId = objectId;
     501          14 :         depAddr.objectSubId = 0;
     502          14 :         recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
     503             : 
     504          14 :         return 1;
     505             :     }
     506             : 
     507         238 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     508             : 
     509             :     /* There should be existing dependency record(s), so search. */
     510         238 :     ScanKeyInit(&key[0],
     511             :                 Anum_pg_depend_classid,
     512             :                 BTEqualStrategyNumber, F_OIDEQ,
     513             :                 ObjectIdGetDatum(classId));
     514         238 :     ScanKeyInit(&key[1],
     515             :                 Anum_pg_depend_objid,
     516             :                 BTEqualStrategyNumber, F_OIDEQ,
     517             :                 ObjectIdGetDatum(objectId));
     518             : 
     519         238 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     520             :                               NULL, 2, key);
     521             : 
     522         590 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     523             :     {
     524         352 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     525             : 
     526         352 :         if (depform->refclassid == refClassId &&
     527         238 :             depform->refobjid == oldRefObjectId)
     528             :         {
     529         238 :             if (newIsPinned)
     530          24 :                 CatalogTupleDelete(depRel, &tup->t_self);
     531             :             else
     532             :             {
     533             :                 /* make a modifiable copy */
     534         214 :                 tup = heap_copytuple(tup);
     535         214 :                 depform = (Form_pg_depend) GETSTRUCT(tup);
     536             : 
     537         214 :                 depform->refobjid = newRefObjectId;
     538             : 
     539         214 :                 CatalogTupleUpdate(depRel, &tup->t_self, tup);
     540             : 
     541         214 :                 heap_freetuple(tup);
     542             :             }
     543             : 
     544         238 :             count++;
     545             :         }
     546             :     }
     547             : 
     548         238 :     systable_endscan(scan);
     549             : 
     550         238 :     table_close(depRel, RowExclusiveLock);
     551             : 
     552         238 :     return count;
     553             : }
     554             : 
     555             : /*
     556             :  * Adjust all dependency records to come from a different object of the same type
     557             :  *
     558             :  * classId/oldObjectId specify the old referencing object.
     559             :  * newObjectId is the new referencing object (must be of class classId).
     560             :  *
     561             :  * Returns the number of records updated.
     562             :  */
     563             : long
     564         864 : changeDependenciesOf(Oid classId, Oid oldObjectId,
     565             :                      Oid newObjectId)
     566             : {
     567         864 :     long        count = 0;
     568             :     Relation    depRel;
     569             :     ScanKeyData key[2];
     570             :     SysScanDesc scan;
     571             :     HeapTuple   tup;
     572             : 
     573         864 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     574             : 
     575         864 :     ScanKeyInit(&key[0],
     576             :                 Anum_pg_depend_classid,
     577             :                 BTEqualStrategyNumber, F_OIDEQ,
     578             :                 ObjectIdGetDatum(classId));
     579         864 :     ScanKeyInit(&key[1],
     580             :                 Anum_pg_depend_objid,
     581             :                 BTEqualStrategyNumber, F_OIDEQ,
     582             :                 ObjectIdGetDatum(oldObjectId));
     583             : 
     584         864 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     585             :                               NULL, 2, key);
     586             : 
     587        2432 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     588             :     {
     589             :         Form_pg_depend depform;
     590             : 
     591             :         /* make a modifiable copy */
     592        1568 :         tup = heap_copytuple(tup);
     593        1568 :         depform = (Form_pg_depend) GETSTRUCT(tup);
     594             : 
     595        1568 :         depform->objid = newObjectId;
     596             : 
     597        1568 :         CatalogTupleUpdate(depRel, &tup->t_self, tup);
     598             : 
     599        1568 :         heap_freetuple(tup);
     600             : 
     601        1568 :         count++;
     602             :     }
     603             : 
     604         864 :     systable_endscan(scan);
     605             : 
     606         864 :     table_close(depRel, RowExclusiveLock);
     607             : 
     608         864 :     return count;
     609             : }
     610             : 
     611             : /*
     612             :  * Adjust all dependency records to point to a different object of the same type
     613             :  *
     614             :  * refClassId/oldRefObjectId specify the old referenced object.
     615             :  * newRefObjectId is the new referenced object (must be of class refClassId).
     616             :  *
     617             :  * Returns the number of records updated.
     618             :  */
     619             : long
     620         864 : changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
     621             :                      Oid newRefObjectId)
     622             : {
     623         864 :     long        count = 0;
     624             :     Relation    depRel;
     625             :     ScanKeyData key[2];
     626             :     SysScanDesc scan;
     627             :     HeapTuple   tup;
     628             :     ObjectAddress objAddr;
     629             :     bool        newIsPinned;
     630             : 
     631         864 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     632             : 
     633             :     /*
     634             :      * If oldRefObjectId is pinned, there won't be any dependency entries on
     635             :      * it --- we can't cope in that case.  (This isn't really worth expending
     636             :      * code to fix, in current usage; it just means you can't rename stuff out
     637             :      * of pg_catalog, which would likely be a bad move anyway.)
     638             :      */
     639         864 :     objAddr.classId = refClassId;
     640         864 :     objAddr.objectId = oldRefObjectId;
     641         864 :     objAddr.objectSubId = 0;
     642             : 
     643         864 :     if (isObjectPinned(&objAddr))
     644           0 :         ereport(ERROR,
     645             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     646             :                  errmsg("cannot remove dependency on %s because it is a system object",
     647             :                         getObjectDescription(&objAddr, false))));
     648             : 
     649             :     /*
     650             :      * We can handle adding a dependency on something pinned, though, since
     651             :      * that just means deleting the dependency entry.
     652             :      */
     653         864 :     objAddr.objectId = newRefObjectId;
     654             : 
     655         864 :     newIsPinned = isObjectPinned(&objAddr);
     656             : 
     657             :     /* Now search for dependency records */
     658         864 :     ScanKeyInit(&key[0],
     659             :                 Anum_pg_depend_refclassid,
     660             :                 BTEqualStrategyNumber, F_OIDEQ,
     661             :                 ObjectIdGetDatum(refClassId));
     662         864 :     ScanKeyInit(&key[1],
     663             :                 Anum_pg_depend_refobjid,
     664             :                 BTEqualStrategyNumber, F_OIDEQ,
     665             :                 ObjectIdGetDatum(oldRefObjectId));
     666             : 
     667         864 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     668             :                               NULL, 2, key);
     669             : 
     670         876 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     671             :     {
     672          12 :         if (newIsPinned)
     673           0 :             CatalogTupleDelete(depRel, &tup->t_self);
     674             :         else
     675             :         {
     676             :             Form_pg_depend depform;
     677             : 
     678             :             /* make a modifiable copy */
     679          12 :             tup = heap_copytuple(tup);
     680          12 :             depform = (Form_pg_depend) GETSTRUCT(tup);
     681             : 
     682          12 :             depform->refobjid = newRefObjectId;
     683             : 
     684          12 :             CatalogTupleUpdate(depRel, &tup->t_self, tup);
     685             : 
     686          12 :             heap_freetuple(tup);
     687             :         }
     688             : 
     689          12 :         count++;
     690             :     }
     691             : 
     692         864 :     systable_endscan(scan);
     693             : 
     694         864 :     table_close(depRel, RowExclusiveLock);
     695             : 
     696         864 :     return count;
     697             : }
     698             : 
     699             : /*
     700             :  * isObjectPinned()
     701             :  *
     702             :  * Test if an object is required for basic database functionality.
     703             :  *
     704             :  * The passed subId, if any, is ignored; we assume that only whole objects
     705             :  * are pinned (and that this implies pinning their components).
     706             :  */
     707             : static bool
     708     6531222 : isObjectPinned(const ObjectAddress *object)
     709             : {
     710     6531222 :     return IsPinnedObject(object->classId, object->objectId);
     711             : }
     712             : 
     713             : 
     714             : /*
     715             :  * Various special-purpose lookups and manipulations of pg_depend.
     716             :  */
     717             : 
     718             : 
     719             : /*
     720             :  * Find the extension containing the specified object, if any
     721             :  *
     722             :  * Returns the OID of the extension, or InvalidOid if the object does not
     723             :  * belong to any extension.
     724             :  *
     725             :  * Extension membership is marked by an EXTENSION dependency from the object
     726             :  * to the extension.  Note that the result will be indeterminate if pg_depend
     727             :  * contains links from this object to more than one extension ... but that
     728             :  * should never happen.
     729             :  */
     730             : Oid
     731         888 : getExtensionOfObject(Oid classId, Oid objectId)
     732             : {
     733         888 :     Oid         result = InvalidOid;
     734             :     Relation    depRel;
     735             :     ScanKeyData key[2];
     736             :     SysScanDesc scan;
     737             :     HeapTuple   tup;
     738             : 
     739         888 :     depRel = table_open(DependRelationId, AccessShareLock);
     740             : 
     741         888 :     ScanKeyInit(&key[0],
     742             :                 Anum_pg_depend_classid,
     743             :                 BTEqualStrategyNumber, F_OIDEQ,
     744             :                 ObjectIdGetDatum(classId));
     745         888 :     ScanKeyInit(&key[1],
     746             :                 Anum_pg_depend_objid,
     747             :                 BTEqualStrategyNumber, F_OIDEQ,
     748             :                 ObjectIdGetDatum(objectId));
     749             : 
     750         888 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     751             :                               NULL, 2, key);
     752             : 
     753        2496 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     754             :     {
     755        2394 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     756             : 
     757        2394 :         if (depform->refclassid == ExtensionRelationId &&
     758         786 :             depform->deptype == DEPENDENCY_EXTENSION)
     759             :         {
     760         786 :             result = depform->refobjid;
     761         786 :             break;              /* no need to keep scanning */
     762             :         }
     763             :     }
     764             : 
     765         888 :     systable_endscan(scan);
     766             : 
     767         888 :     table_close(depRel, AccessShareLock);
     768             : 
     769         888 :     return result;
     770             : }
     771             : 
     772             : /*
     773             :  * Return (possibly NIL) list of extensions that the given object depends on
     774             :  * in DEPENDENCY_AUTO_EXTENSION mode.
     775             :  */
     776             : List *
     777          38 : getAutoExtensionsOfObject(Oid classId, Oid objectId)
     778             : {
     779          38 :     List       *result = NIL;
     780             :     Relation    depRel;
     781             :     ScanKeyData key[2];
     782             :     SysScanDesc scan;
     783             :     HeapTuple   tup;
     784             : 
     785          38 :     depRel = table_open(DependRelationId, AccessShareLock);
     786             : 
     787          38 :     ScanKeyInit(&key[0],
     788             :                 Anum_pg_depend_classid,
     789             :                 BTEqualStrategyNumber, F_OIDEQ,
     790             :                 ObjectIdGetDatum(classId));
     791          38 :     ScanKeyInit(&key[1],
     792             :                 Anum_pg_depend_objid,
     793             :                 BTEqualStrategyNumber, F_OIDEQ,
     794             :                 ObjectIdGetDatum(objectId));
     795             : 
     796          38 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     797             :                               NULL, 2, key);
     798             : 
     799          96 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     800             :     {
     801          58 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     802             : 
     803          58 :         if (depform->refclassid == ExtensionRelationId &&
     804           2 :             depform->deptype == DEPENDENCY_AUTO_EXTENSION)
     805           2 :             result = lappend_oid(result, depform->refobjid);
     806             :     }
     807             : 
     808          38 :     systable_endscan(scan);
     809             : 
     810          38 :     table_close(depRel, AccessShareLock);
     811             : 
     812          38 :     return result;
     813             : }
     814             : 
     815             : /*
     816             :  * Detect whether a sequence is marked as "owned" by a column
     817             :  *
     818             :  * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
     819             :  * column.  If we find one, store the identity of the owning column
     820             :  * into *tableId and *colId and return true; else return false.
     821             :  *
     822             :  * Note: if there's more than one such pg_depend entry then you get
     823             :  * a random one of them returned into the out parameters.  This should
     824             :  * not happen, though.
     825             :  */
     826             : bool
     827         746 : sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
     828             : {
     829         746 :     bool        ret = false;
     830             :     Relation    depRel;
     831             :     ScanKeyData key[2];
     832             :     SysScanDesc scan;
     833             :     HeapTuple   tup;
     834             : 
     835         746 :     depRel = table_open(DependRelationId, AccessShareLock);
     836             : 
     837         746 :     ScanKeyInit(&key[0],
     838             :                 Anum_pg_depend_classid,
     839             :                 BTEqualStrategyNumber, F_OIDEQ,
     840             :                 ObjectIdGetDatum(RelationRelationId));
     841         746 :     ScanKeyInit(&key[1],
     842             :                 Anum_pg_depend_objid,
     843             :                 BTEqualStrategyNumber, F_OIDEQ,
     844             :                 ObjectIdGetDatum(seqId));
     845             : 
     846         746 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     847             :                               NULL, 2, key);
     848             : 
     849        1500 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     850             :     {
     851         760 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     852             : 
     853         760 :         if (depform->refclassid == RelationRelationId &&
     854           6 :             depform->deptype == deptype)
     855             :         {
     856           6 :             *tableId = depform->refobjid;
     857           6 :             *colId = depform->refobjsubid;
     858           6 :             ret = true;
     859           6 :             break;              /* no need to keep scanning */
     860             :         }
     861             :     }
     862             : 
     863         746 :     systable_endscan(scan);
     864             : 
     865         746 :     table_close(depRel, AccessShareLock);
     866             : 
     867         746 :     return ret;
     868             : }
     869             : 
     870             : /*
     871             :  * Collect a list of OIDs of all sequences owned by the specified relation,
     872             :  * and column if specified.  If deptype is not zero, then only find sequences
     873             :  * with the specified dependency type.
     874             :  */
     875             : static List *
     876         546 : getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
     877             : {
     878         546 :     List       *result = NIL;
     879             :     Relation    depRel;
     880             :     ScanKeyData key[3];
     881             :     SysScanDesc scan;
     882             :     HeapTuple   tup;
     883             : 
     884         546 :     depRel = table_open(DependRelationId, AccessShareLock);
     885             : 
     886         546 :     ScanKeyInit(&key[0],
     887             :                 Anum_pg_depend_refclassid,
     888             :                 BTEqualStrategyNumber, F_OIDEQ,
     889             :                 ObjectIdGetDatum(RelationRelationId));
     890         546 :     ScanKeyInit(&key[1],
     891             :                 Anum_pg_depend_refobjid,
     892             :                 BTEqualStrategyNumber, F_OIDEQ,
     893             :                 ObjectIdGetDatum(relid));
     894         546 :     if (attnum)
     895         474 :         ScanKeyInit(&key[2],
     896             :                     Anum_pg_depend_refobjsubid,
     897             :                     BTEqualStrategyNumber, F_INT4EQ,
     898             :                     Int32GetDatum(attnum));
     899             : 
     900         546 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     901             :                               NULL, attnum ? 3 : 2, key);
     902             : 
     903        1328 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     904             :     {
     905         782 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     906             : 
     907             :         /*
     908             :          * We assume any auto or internal dependency of a sequence on a column
     909             :          * must be what we are looking for.  (We need the relkind test because
     910             :          * indexes can also have auto dependencies on columns.)
     911             :          */
     912         782 :         if (deprec->classid == RelationRelationId &&
     913         546 :             deprec->objsubid == 0 &&
     914         546 :             deprec->refobjsubid != 0 &&
     915        1068 :             (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
     916         534 :             get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
     917             :         {
     918         534 :             if (!deptype || deprec->deptype == deptype)
     919         528 :                 result = lappend_oid(result, deprec->objid);
     920             :         }
     921             :     }
     922             : 
     923         546 :     systable_endscan(scan);
     924             : 
     925         546 :     table_close(depRel, AccessShareLock);
     926             : 
     927         546 :     return result;
     928             : }
     929             : 
     930             : /*
     931             :  * Collect a list of OIDs of all sequences owned (identity or serial) by the
     932             :  * specified relation.
     933             :  */
     934             : List *
     935          72 : getOwnedSequences(Oid relid)
     936             : {
     937          72 :     return getOwnedSequences_internal(relid, 0, 0);
     938             : }
     939             : 
     940             : /*
     941             :  * Get owned identity sequence, error if not exactly one.
     942             :  */
     943             : Oid
     944         474 : getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
     945             : {
     946         474 :     List       *seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
     947             : 
     948         474 :     if (list_length(seqlist) > 1)
     949           0 :         elog(ERROR, "more than one owned sequence found");
     950         474 :     else if (seqlist == NIL)
     951             :     {
     952          12 :         if (missing_ok)
     953          12 :             return InvalidOid;
     954             :         else
     955           0 :             elog(ERROR, "no owned sequence found");
     956             :     }
     957             : 
     958         462 :     return linitial_oid(seqlist);
     959             : }
     960             : 
     961             : /*
     962             :  * get_index_constraint
     963             :  *      Given the OID of an index, return the OID of the owning unique,
     964             :  *      primary-key, or exclusion constraint, or InvalidOid if there
     965             :  *      is no owning constraint.
     966             :  */
     967             : Oid
     968       68626 : get_index_constraint(Oid indexId)
     969             : {
     970       68626 :     Oid         constraintId = InvalidOid;
     971             :     Relation    depRel;
     972             :     ScanKeyData key[3];
     973             :     SysScanDesc scan;
     974             :     HeapTuple   tup;
     975             : 
     976             :     /* Search the dependency table for the index */
     977       68626 :     depRel = table_open(DependRelationId, AccessShareLock);
     978             : 
     979       68626 :     ScanKeyInit(&key[0],
     980             :                 Anum_pg_depend_classid,
     981             :                 BTEqualStrategyNumber, F_OIDEQ,
     982             :                 ObjectIdGetDatum(RelationRelationId));
     983       68626 :     ScanKeyInit(&key[1],
     984             :                 Anum_pg_depend_objid,
     985             :                 BTEqualStrategyNumber, F_OIDEQ,
     986             :                 ObjectIdGetDatum(indexId));
     987       68626 :     ScanKeyInit(&key[2],
     988             :                 Anum_pg_depend_objsubid,
     989             :                 BTEqualStrategyNumber, F_INT4EQ,
     990             :                 Int32GetDatum(0));
     991             : 
     992       68626 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     993             :                               NULL, 3, key);
     994             : 
     995       70868 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     996             :     {
     997        3446 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
     998             : 
     999             :         /*
    1000             :          * We assume any internal dependency on a constraint must be what we
    1001             :          * are looking for.
    1002             :          */
    1003        3446 :         if (deprec->refclassid == ConstraintRelationId &&
    1004        1204 :             deprec->refobjsubid == 0 &&
    1005        1204 :             deprec->deptype == DEPENDENCY_INTERNAL)
    1006             :         {
    1007        1204 :             constraintId = deprec->refobjid;
    1008        1204 :             break;
    1009             :         }
    1010             :     }
    1011             : 
    1012       68626 :     systable_endscan(scan);
    1013       68626 :     table_close(depRel, AccessShareLock);
    1014             : 
    1015       68626 :     return constraintId;
    1016             : }
    1017             : 
    1018             : /*
    1019             :  * get_index_ref_constraints
    1020             :  *      Given the OID of an index, return the OID of all foreign key
    1021             :  *      constraints which reference the index.
    1022             :  */
    1023             : List *
    1024         432 : get_index_ref_constraints(Oid indexId)
    1025             : {
    1026         432 :     List       *result = NIL;
    1027             :     Relation    depRel;
    1028             :     ScanKeyData key[3];
    1029             :     SysScanDesc scan;
    1030             :     HeapTuple   tup;
    1031             : 
    1032             :     /* Search the dependency table for the index */
    1033         432 :     depRel = table_open(DependRelationId, AccessShareLock);
    1034             : 
    1035         432 :     ScanKeyInit(&key[0],
    1036             :                 Anum_pg_depend_refclassid,
    1037             :                 BTEqualStrategyNumber, F_OIDEQ,
    1038             :                 ObjectIdGetDatum(RelationRelationId));
    1039         432 :     ScanKeyInit(&key[1],
    1040             :                 Anum_pg_depend_refobjid,
    1041             :                 BTEqualStrategyNumber, F_OIDEQ,
    1042             :                 ObjectIdGetDatum(indexId));
    1043         432 :     ScanKeyInit(&key[2],
    1044             :                 Anum_pg_depend_refobjsubid,
    1045             :                 BTEqualStrategyNumber, F_INT4EQ,
    1046             :                 Int32GetDatum(0));
    1047             : 
    1048         432 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
    1049             :                               NULL, 3, key);
    1050             : 
    1051         444 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
    1052             :     {
    1053          12 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
    1054             : 
    1055             :         /*
    1056             :          * We assume any normal dependency from a constraint must be what we
    1057             :          * are looking for.
    1058             :          */
    1059          12 :         if (deprec->classid == ConstraintRelationId &&
    1060          12 :             deprec->objsubid == 0 &&
    1061          12 :             deprec->deptype == DEPENDENCY_NORMAL)
    1062             :         {
    1063          12 :             result = lappend_oid(result, deprec->objid);
    1064             :         }
    1065             :     }
    1066             : 
    1067         432 :     systable_endscan(scan);
    1068         432 :     table_close(depRel, AccessShareLock);
    1069             : 
    1070         432 :     return result;
    1071             : }

Generated by: LCOV version 1.14