LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_depend.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 97.2 % 359 349
Test Date: 2026-05-31 03:16:17 Functions: 100.0 % 21 21
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-2026, 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 "catalog/pg_type.h"
      27              : #include "catalog/partition.h"
      28              : #include "commands/extension.h"
      29              : #include "miscadmin.h"
      30              : #include "storage/lmgr.h"
      31              : #include "storage/lock.h"
      32              : #include "utils/fmgroids.h"
      33              : #include "utils/lsyscache.h"
      34              : #include "utils/rel.h"
      35              : #include "utils/snapmgr.h"
      36              : #include "utils/syscache.h"
      37              : 
      38              : 
      39              : static bool isObjectPinned(const ObjectAddress *object);
      40              : static void dependencyLockAndCheckObject(Oid classId, Oid objectId);
      41              : 
      42              : 
      43              : /*
      44              :  * Record a dependency between 2 objects via their respective ObjectAddress.
      45              :  * The first argument is the dependent object, the second the one it
      46              :  * references.
      47              :  *
      48              :  * This simply creates an entry in pg_depend, without any other processing.
      49              :  */
      50              : void
      51       538778 : recordDependencyOn(const ObjectAddress *depender,
      52              :                    const ObjectAddress *referenced,
      53              :                    DependencyType behavior)
      54              : {
      55       538778 :     recordMultipleDependencies(depender, referenced, 1, behavior);
      56       538776 : }
      57              : 
      58              : /*
      59              :  * Record multiple dependencies (of the same kind) for a single dependent
      60              :  * object.  This has a little less overhead than recording each separately.
      61              :  */
      62              : void
      63       828013 : recordMultipleDependencies(const ObjectAddress *depender,
      64              :                            const ObjectAddress *referenced,
      65              :                            int nreferenced,
      66              :                            DependencyType behavior)
      67              : {
      68              :     Relation    dependDesc;
      69              :     CatalogIndexState indstate;
      70              :     TupleTableSlot **slot;
      71              :     int         i,
      72              :                 max_slots,
      73              :                 slot_init_count,
      74              :                 slot_stored_count;
      75              : 
      76       828013 :     if (nreferenced <= 0)
      77        33446 :         return;                 /* nothing to do */
      78              : 
      79              :     /*
      80              :      * During bootstrap, do nothing since pg_depend may not exist yet.
      81              :      *
      82              :      * Objects created during bootstrap are most likely pinned, and the few
      83              :      * that are not do not have dependencies on each other, so that there
      84              :      * would be no need to make a pg_depend entry anyway.
      85              :      */
      86       794567 :     if (IsBootstrapProcessingMode())
      87        41154 :         return;
      88              : 
      89       753413 :     dependDesc = table_open(DependRelationId, RowExclusiveLock);
      90              : 
      91              :     /*
      92              :      * Allocate the slots to use, but delay costly initialization until we
      93              :      * know that they will be used.
      94              :      */
      95       753413 :     max_slots = Min(nreferenced,
      96              :                     MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_depend));
      97       753413 :     slot = palloc_array(TupleTableSlot *, max_slots);
      98              : 
      99              :     /* Don't open indexes unless we need to make an update */
     100       753413 :     indstate = NULL;
     101              : 
     102              :     /* number of slots currently storing tuples */
     103       753413 :     slot_stored_count = 0;
     104              :     /* number of slots currently initialized */
     105       753413 :     slot_init_count = 0;
     106      2186023 :     for (i = 0; i < nreferenced; i++, referenced++)
     107              :     {
     108              :         /*
     109              :          * If the referenced object is pinned by the system, there's no real
     110              :          * need to record dependencies on it.  This saves lots of space in
     111              :          * pg_depend, so it's worth the time taken to check.
     112              :          */
     113      1432617 :         if (isObjectPinned(referenced))
     114      1033488 :             continue;
     115              : 
     116              :         /*
     117              :          * Make sure the new referenced object doesn't go away while we record
     118              :          * the dependency.  DROP routines should lock the object exclusively
     119              :          * before they check dependencies.
     120              :          */
     121       399129 :         dependencyLockAndCheckObject(referenced->classId, referenced->objectId);
     122              : 
     123       399122 :         if (slot_init_count < max_slots)
     124              :         {
     125       399122 :             slot[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc),
     126              :                                                                &TTSOpsHeapTuple);
     127       399122 :             slot_init_count++;
     128              :         }
     129              : 
     130       399122 :         ExecClearTuple(slot[slot_stored_count]);
     131              : 
     132              :         /*
     133              :          * Record the dependency.  Note we don't bother to check for duplicate
     134              :          * dependencies; there's no harm in them.
     135              :          */
     136       399122 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
     137       399122 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
     138       399122 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
     139       399122 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
     140       399122 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
     141       399122 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
     142       399122 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
     143              : 
     144       399122 :         memset(slot[slot_stored_count]->tts_isnull, false,
     145       399122 :                slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
     146              : 
     147       399122 :         ExecStoreVirtualTuple(slot[slot_stored_count]);
     148       399122 :         slot_stored_count++;
     149              : 
     150              :         /* If slots are full, insert a batch of tuples */
     151       399122 :         if (slot_stored_count == max_slots)
     152              :         {
     153              :             /* fetch index info only when we know we need it */
     154       281223 :             if (indstate == NULL)
     155       281223 :                 indstate = CatalogOpenIndexes(dependDesc);
     156              : 
     157       281223 :             CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
     158              :                                              indstate);
     159       281223 :             slot_stored_count = 0;
     160              :         }
     161              :     }
     162              : 
     163              :     /* Insert any tuples left in the buffer */
     164       753406 :     if (slot_stored_count > 0)
     165              :     {
     166              :         /* fetch index info only when we know we need it */
     167        61366 :         if (indstate == NULL)
     168        61366 :             indstate = CatalogOpenIndexes(dependDesc);
     169              : 
     170        61366 :         CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
     171              :                                          indstate);
     172              :     }
     173              : 
     174       753406 :     if (indstate != NULL)
     175       342589 :         CatalogCloseIndexes(indstate);
     176              : 
     177       753406 :     table_close(dependDesc, RowExclusiveLock);
     178              : 
     179              :     /* Drop only the number of slots used */
     180      1152528 :     for (i = 0; i < slot_init_count; i++)
     181       399122 :         ExecDropSingleTupleTableSlot(slot[i]);
     182       753406 :     pfree(slot);
     183              : }
     184              : 
     185              : /*
     186              :  * If we are executing a CREATE EXTENSION operation, mark the given object
     187              :  * as being a member of the extension, or check that it already is one.
     188              :  * Otherwise, do nothing.
     189              :  *
     190              :  * This must be called during creation of any user-definable object type
     191              :  * that could be a member of an extension.
     192              :  *
     193              :  * isReplace must be true if the object already existed, and false if it is
     194              :  * newly created.  In the former case we insist that it already be a member
     195              :  * of the current extension.  In the latter case we can skip checking whether
     196              :  * it is already a member of any extension.
     197              :  *
     198              :  * Note: isReplace = true is typically used when updating an object in
     199              :  * CREATE OR REPLACE and similar commands.  We used to allow the target
     200              :  * object to not already be an extension member, instead silently absorbing
     201              :  * it into the current extension.  However, this was both error-prone
     202              :  * (extensions might accidentally overwrite free-standing objects) and
     203              :  * a security hazard (since the object would retain its previous ownership).
     204              :  */
     205              : void
     206       203136 : recordDependencyOnCurrentExtension(const ObjectAddress *object,
     207              :                                    bool isReplace)
     208              : {
     209              :     /* Only whole objects can be extension members */
     210              :     Assert(object->objectSubId == 0);
     211              : 
     212       203136 :     if (creating_extension)
     213              :     {
     214              :         ObjectAddress extension;
     215              : 
     216              :         /* Only need to check for existing membership if isReplace */
     217         5916 :         if (isReplace)
     218              :         {
     219              :             Oid         oldext;
     220              : 
     221              :             /*
     222              :              * Side note: these catalog lookups are safe only because the
     223              :              * object is a pre-existing one.  In the not-isReplace case, the
     224              :              * caller has most likely not yet done a CommandCounterIncrement
     225              :              * that would make the new object visible.
     226              :              */
     227          401 :             oldext = getExtensionOfObject(object->classId, object->objectId);
     228          401 :             if (OidIsValid(oldext))
     229              :             {
     230              :                 /* If already a member of this extension, nothing to do */
     231          397 :                 if (oldext == CurrentExtensionObject)
     232          397 :                     return;
     233              :                 /* Already a member of some other extension, so reject */
     234            0 :                 ereport(ERROR,
     235              :                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     236              :                          errmsg("%s is already a member of extension \"%s\"",
     237              :                                 getObjectDescription(object, false),
     238              :                                 get_extension_name(oldext))));
     239              :             }
     240              :             /* It's a free-standing object, so reject */
     241            4 :             ereport(ERROR,
     242              :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     243              :                      errmsg("%s is not a member of extension \"%s\"",
     244              :                             getObjectDescription(object, false),
     245              :                             get_extension_name(CurrentExtensionObject)),
     246              :                      errdetail("An extension is not allowed to replace an object that it does not own.")));
     247              :         }
     248              : 
     249              :         /* OK, record it as a member of CurrentExtensionObject */
     250         5515 :         extension.classId = ExtensionRelationId;
     251         5515 :         extension.objectId = CurrentExtensionObject;
     252         5515 :         extension.objectSubId = 0;
     253              : 
     254         5515 :         recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
     255              :     }
     256              : }
     257              : 
     258              : /*
     259              :  * If we are executing a CREATE EXTENSION operation, check that the given
     260              :  * object is a member of the extension, and throw an error if it isn't.
     261              :  * Otherwise, do nothing.
     262              :  *
     263              :  * This must be called whenever a CREATE IF NOT EXISTS operation (for an
     264              :  * object type that can be an extension member) has found that an object of
     265              :  * the desired name already exists.  It is insecure for an extension to use
     266              :  * IF NOT EXISTS except when the conflicting object is already an extension
     267              :  * member; otherwise a hostile user could substitute an object with arbitrary
     268              :  * properties.
     269              :  */
     270              : void
     271           85 : checkMembershipInCurrentExtension(const ObjectAddress *object)
     272              : {
     273              :     /*
     274              :      * This is actually the same condition tested in
     275              :      * recordDependencyOnCurrentExtension; but we want to issue a
     276              :      * differently-worded error, and anyway it would be pretty confusing to
     277              :      * call recordDependencyOnCurrentExtension in these circumstances.
     278              :      */
     279              : 
     280              :     /* Only whole objects can be extension members */
     281              :     Assert(object->objectSubId == 0);
     282              : 
     283           85 :     if (creating_extension)
     284              :     {
     285              :         Oid         oldext;
     286              : 
     287           14 :         oldext = getExtensionOfObject(object->classId, object->objectId);
     288              :         /* If already a member of this extension, OK */
     289           14 :         if (oldext == CurrentExtensionObject)
     290            7 :             return;
     291              :         /* Else complain */
     292            7 :         ereport(ERROR,
     293              :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     294              :                  errmsg("%s is not a member of extension \"%s\"",
     295              :                         getObjectDescription(object, false),
     296              :                         get_extension_name(CurrentExtensionObject)),
     297              :                  errdetail("An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.")));
     298              :     }
     299              : }
     300              : 
     301              : /*
     302              :  * deleteDependencyRecordsFor -- delete all records with given depender
     303              :  * classId/objectId.  Returns the number of records deleted.
     304              :  *
     305              :  * This is used when redefining an existing object.  Links leading to the
     306              :  * object do not change, and links leading from it will be recreated
     307              :  * (possibly with some differences from before).
     308              :  *
     309              :  * If skipExtensionDeps is true, we do not delete any dependencies that
     310              :  * show that the given object is a member of an extension.  This avoids
     311              :  * needing a lot of extra logic to fetch and recreate that dependency.
     312              :  */
     313              : long
     314        10786 : deleteDependencyRecordsFor(Oid classId, Oid objectId,
     315              :                            bool skipExtensionDeps)
     316              : {
     317        10786 :     long        count = 0;
     318              :     Relation    depRel;
     319              :     ScanKeyData key[2];
     320              :     SysScanDesc scan;
     321              :     HeapTuple   tup;
     322              : 
     323        10786 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     324              : 
     325        10786 :     ScanKeyInit(&key[0],
     326              :                 Anum_pg_depend_classid,
     327              :                 BTEqualStrategyNumber, F_OIDEQ,
     328              :                 ObjectIdGetDatum(classId));
     329        10786 :     ScanKeyInit(&key[1],
     330              :                 Anum_pg_depend_objid,
     331              :                 BTEqualStrategyNumber, F_OIDEQ,
     332              :                 ObjectIdGetDatum(objectId));
     333              : 
     334        10786 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     335              :                               NULL, 2, key);
     336              : 
     337        18848 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     338              :     {
     339         8062 :         if (skipExtensionDeps &&
     340         5909 :             ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
     341          635 :             continue;
     342              : 
     343         7427 :         CatalogTupleDelete(depRel, &tup->t_self);
     344         7427 :         count++;
     345              :     }
     346              : 
     347        10786 :     systable_endscan(scan);
     348              : 
     349        10786 :     table_close(depRel, RowExclusiveLock);
     350              : 
     351        10786 :     return count;
     352              : }
     353              : 
     354              : /*
     355              :  * deleteDependencyRecordsForClass -- delete all records with given depender
     356              :  * classId/objectId, dependee classId, and deptype.
     357              :  * Returns the number of records deleted.
     358              :  *
     359              :  * This is a variant of deleteDependencyRecordsFor, useful when revoking
     360              :  * an object property that is expressed by a dependency record (such as
     361              :  * extension membership).
     362              :  */
     363              : long
     364         9510 : deleteDependencyRecordsForClass(Oid classId, Oid objectId,
     365              :                                 Oid refclassId, char deptype)
     366              : {
     367         9510 :     long        count = 0;
     368              :     Relation    depRel;
     369              :     ScanKeyData key[2];
     370              :     SysScanDesc scan;
     371              :     HeapTuple   tup;
     372              : 
     373         9510 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     374              : 
     375         9510 :     ScanKeyInit(&key[0],
     376              :                 Anum_pg_depend_classid,
     377              :                 BTEqualStrategyNumber, F_OIDEQ,
     378              :                 ObjectIdGetDatum(classId));
     379         9510 :     ScanKeyInit(&key[1],
     380              :                 Anum_pg_depend_objid,
     381              :                 BTEqualStrategyNumber, F_OIDEQ,
     382              :                 ObjectIdGetDatum(objectId));
     383              : 
     384         9510 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     385              :                               NULL, 2, key);
     386              : 
     387        15961 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     388              :     {
     389         6451 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     390              : 
     391         6451 :         if (depform->refclassid == refclassId && depform->deptype == deptype)
     392              :         {
     393         1477 :             CatalogTupleDelete(depRel, &tup->t_self);
     394         1477 :             count++;
     395              :         }
     396              :     }
     397              : 
     398         9510 :     systable_endscan(scan);
     399              : 
     400         9510 :     table_close(depRel, RowExclusiveLock);
     401              : 
     402         9510 :     return count;
     403              : }
     404              : 
     405              : /*
     406              :  * deleteDependencyRecordsForSpecific -- delete all records with given depender
     407              :  * classId/objectId, dependee classId/objectId, of the given deptype.
     408              :  * Returns the number of records deleted.
     409              :  */
     410              : long
     411           59 : deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
     412              :                                    Oid refclassId, Oid refobjectId)
     413              : {
     414           59 :     long        count = 0;
     415              :     Relation    depRel;
     416              :     ScanKeyData key[2];
     417              :     SysScanDesc scan;
     418              :     HeapTuple   tup;
     419              : 
     420           59 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     421              : 
     422           59 :     ScanKeyInit(&key[0],
     423              :                 Anum_pg_depend_classid,
     424              :                 BTEqualStrategyNumber, F_OIDEQ,
     425              :                 ObjectIdGetDatum(classId));
     426           59 :     ScanKeyInit(&key[1],
     427              :                 Anum_pg_depend_objid,
     428              :                 BTEqualStrategyNumber, F_OIDEQ,
     429              :                 ObjectIdGetDatum(objectId));
     430              : 
     431           59 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     432              :                               NULL, 2, key);
     433              : 
     434          319 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     435              :     {
     436          260 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     437              : 
     438          260 :         if (depform->refclassid == refclassId &&
     439           60 :             depform->refobjid == refobjectId &&
     440           59 :             depform->deptype == deptype)
     441              :         {
     442           59 :             CatalogTupleDelete(depRel, &tup->t_self);
     443           59 :             count++;
     444              :         }
     445              :     }
     446              : 
     447           59 :     systable_endscan(scan);
     448              : 
     449           59 :     table_close(depRel, RowExclusiveLock);
     450              : 
     451           59 :     return count;
     452              : }
     453              : 
     454              : /*
     455              :  * Adjust dependency record(s) to point to a different object of the same type
     456              :  *
     457              :  * classId/objectId specify the referencing object.
     458              :  * refClassId/oldRefObjectId specify the old referenced object.
     459              :  * newRefObjectId is the new referenced object (must be of class refClassId).
     460              :  *
     461              :  * Note the lack of objsubid parameters.  If there are subobject references
     462              :  * they will all be readjusted.  Also, there is an expectation that we are
     463              :  * dealing with NORMAL dependencies: if we have to replace an (implicit)
     464              :  * dependency on a pinned object with an explicit dependency on an unpinned
     465              :  * one, the new one will be NORMAL.
     466              :  *
     467              :  * Returns the number of records updated -- zero indicates a problem.
     468              :  */
     469              : long
     470          251 : changeDependencyFor(Oid classId, Oid objectId,
     471              :                     Oid refClassId, Oid oldRefObjectId,
     472              :                     Oid newRefObjectId)
     473              : {
     474          251 :     long        count = 0;
     475              :     Relation    depRel;
     476              :     ScanKeyData key[2];
     477              :     SysScanDesc scan;
     478              :     HeapTuple   tup;
     479              :     ObjectAddress objAddr;
     480              :     ObjectAddress depAddr;
     481              :     bool        oldIsPinned;
     482              :     bool        newIsPinned;
     483              : 
     484              :     /*
     485              :      * Check to see if either oldRefObjectId or newRefObjectId is pinned.
     486              :      * Pinned objects should not have any dependency entries pointing to them,
     487              :      * so in these cases we should add or remove a pg_depend entry, or do
     488              :      * nothing at all, rather than update an entry as in the normal case.
     489              :      */
     490          251 :     objAddr.classId = refClassId;
     491          251 :     objAddr.objectId = oldRefObjectId;
     492          251 :     objAddr.objectSubId = 0;
     493              : 
     494          251 :     oldIsPinned = isObjectPinned(&objAddr);
     495              : 
     496          251 :     objAddr.objectId = newRefObjectId;
     497              : 
     498          251 :     newIsPinned = isObjectPinned(&objAddr);
     499              : 
     500          251 :     if (oldIsPinned)
     501              :     {
     502              :         /*
     503              :          * If both are pinned, we need do nothing.  However, return 1 not 0,
     504              :          * else callers will think this is an error case.
     505              :          */
     506           37 :         if (newIsPinned)
     507            0 :             return 1;
     508              : 
     509              :         /*
     510              :          * There is no old dependency record, but we should insert a new one.
     511              :          * Assume a normal dependency is wanted.
     512              :          */
     513           37 :         depAddr.classId = classId;
     514           37 :         depAddr.objectId = objectId;
     515           37 :         depAddr.objectSubId = 0;
     516           37 :         recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
     517              : 
     518           37 :         return 1;
     519              :     }
     520              : 
     521              :     /*
     522              :      * Make sure the new referenced object doesn't go away while we record the
     523              :      * dependency.
     524              :      */
     525          214 :     if (!newIsPinned)
     526          170 :         dependencyLockAndCheckObject(refClassId, newRefObjectId);
     527              : 
     528          213 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     529              : 
     530              :     /* There should be existing dependency record(s), so search. */
     531          213 :     ScanKeyInit(&key[0],
     532              :                 Anum_pg_depend_classid,
     533              :                 BTEqualStrategyNumber, F_OIDEQ,
     534              :                 ObjectIdGetDatum(classId));
     535          213 :     ScanKeyInit(&key[1],
     536              :                 Anum_pg_depend_objid,
     537              :                 BTEqualStrategyNumber, F_OIDEQ,
     538              :                 ObjectIdGetDatum(objectId));
     539              : 
     540          213 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     541              :                               NULL, 2, key);
     542              : 
     543          557 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     544              :     {
     545          344 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     546              : 
     547          344 :         if (depform->refclassid == refClassId &&
     548          213 :             depform->refobjid == oldRefObjectId)
     549              :         {
     550          213 :             if (newIsPinned)
     551           44 :                 CatalogTupleDelete(depRel, &tup->t_self);
     552              :             else
     553              :             {
     554              :                 /* make a modifiable copy */
     555          169 :                 tup = heap_copytuple(tup);
     556          169 :                 depform = (Form_pg_depend) GETSTRUCT(tup);
     557              : 
     558          169 :                 depform->refobjid = newRefObjectId;
     559              : 
     560          169 :                 CatalogTupleUpdate(depRel, &tup->t_self, tup);
     561              : 
     562          169 :                 heap_freetuple(tup);
     563              :             }
     564              : 
     565          213 :             count++;
     566              :         }
     567              :     }
     568              : 
     569          213 :     systable_endscan(scan);
     570              : 
     571          213 :     table_close(depRel, RowExclusiveLock);
     572              : 
     573          213 :     return count;
     574              : }
     575              : 
     576              : /*
     577              :  * Adjust all dependency records to come from a different object of the same type
     578              :  *
     579              :  * classId/oldObjectId specify the old referencing object.
     580              :  * newObjectId is the new referencing object (must be of class classId).
     581              :  *
     582              :  * Returns the number of records updated.
     583              :  */
     584              : long
     585          640 : changeDependenciesOf(Oid classId, Oid oldObjectId,
     586              :                      Oid newObjectId)
     587              : {
     588          640 :     long        count = 0;
     589              :     Relation    depRel;
     590              :     ScanKeyData key[2];
     591              :     SysScanDesc scan;
     592              :     HeapTuple   tup;
     593              : 
     594          640 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     595              : 
     596          640 :     ScanKeyInit(&key[0],
     597              :                 Anum_pg_depend_classid,
     598              :                 BTEqualStrategyNumber, F_OIDEQ,
     599              :                 ObjectIdGetDatum(classId));
     600          640 :     ScanKeyInit(&key[1],
     601              :                 Anum_pg_depend_objid,
     602              :                 BTEqualStrategyNumber, F_OIDEQ,
     603              :                 ObjectIdGetDatum(oldObjectId));
     604              : 
     605          640 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     606              :                               NULL, 2, key);
     607              : 
     608         1808 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     609              :     {
     610              :         Form_pg_depend depform;
     611              : 
     612              :         /* make a modifiable copy */
     613         1168 :         tup = heap_copytuple(tup);
     614         1168 :         depform = (Form_pg_depend) GETSTRUCT(tup);
     615              : 
     616         1168 :         depform->objid = newObjectId;
     617              : 
     618         1168 :         CatalogTupleUpdate(depRel, &tup->t_self, tup);
     619              : 
     620         1168 :         heap_freetuple(tup);
     621              : 
     622         1168 :         count++;
     623              :     }
     624              : 
     625          640 :     systable_endscan(scan);
     626              : 
     627          640 :     table_close(depRel, RowExclusiveLock);
     628              : 
     629          640 :     return count;
     630              : }
     631              : 
     632              : /*
     633              :  * Adjust all dependency records to point to a different object of the same type
     634              :  *
     635              :  * refClassId/oldRefObjectId specify the old referenced object.
     636              :  * newRefObjectId is the new referenced object (must be of class refClassId).
     637              :  *
     638              :  * Returns the number of records updated.
     639              :  */
     640              : long
     641          640 : changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
     642              :                      Oid newRefObjectId)
     643              : {
     644          640 :     long        count = 0;
     645              :     Relation    depRel;
     646              :     ScanKeyData key[2];
     647              :     SysScanDesc scan;
     648              :     HeapTuple   tup;
     649              :     ObjectAddress objAddr;
     650              :     bool        newIsPinned;
     651              : 
     652          640 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     653              : 
     654              :     /*
     655              :      * If oldRefObjectId is pinned, there won't be any dependency entries on
     656              :      * it --- we can't cope in that case.  (This isn't really worth expending
     657              :      * code to fix, in current usage; it just means you can't rename stuff out
     658              :      * of pg_catalog, which would likely be a bad move anyway.)
     659              :      */
     660          640 :     objAddr.classId = refClassId;
     661          640 :     objAddr.objectId = oldRefObjectId;
     662          640 :     objAddr.objectSubId = 0;
     663              : 
     664          640 :     if (isObjectPinned(&objAddr))
     665            0 :         ereport(ERROR,
     666              :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     667              :                  errmsg("cannot remove dependency on %s because it is a system object",
     668              :                         getObjectDescription(&objAddr, false))));
     669              : 
     670              :     /*
     671              :      * We can handle adding a dependency on something pinned, though, since
     672              :      * that just means deleting the dependency entry.
     673              :      */
     674          640 :     objAddr.objectId = newRefObjectId;
     675              : 
     676          640 :     newIsPinned = isObjectPinned(&objAddr);
     677              : 
     678              :     /* Now search for dependency records */
     679          640 :     ScanKeyInit(&key[0],
     680              :                 Anum_pg_depend_refclassid,
     681              :                 BTEqualStrategyNumber, F_OIDEQ,
     682              :                 ObjectIdGetDatum(refClassId));
     683          640 :     ScanKeyInit(&key[1],
     684              :                 Anum_pg_depend_refobjid,
     685              :                 BTEqualStrategyNumber, F_OIDEQ,
     686              :                 ObjectIdGetDatum(oldRefObjectId));
     687              : 
     688          640 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     689              :                               NULL, 2, key);
     690              : 
     691          651 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     692              :     {
     693           11 :         if (newIsPinned)
     694            0 :             CatalogTupleDelete(depRel, &tup->t_self);
     695              :         else
     696              :         {
     697              :             Form_pg_depend depform;
     698              : 
     699              :             /* make a modifiable copy */
     700           11 :             tup = heap_copytuple(tup);
     701           11 :             depform = (Form_pg_depend) GETSTRUCT(tup);
     702              : 
     703           11 :             depform->refobjid = newRefObjectId;
     704              : 
     705           11 :             CatalogTupleUpdate(depRel, &tup->t_self, tup);
     706              : 
     707           11 :             heap_freetuple(tup);
     708              :         }
     709              : 
     710           11 :         count++;
     711              :     }
     712              : 
     713          640 :     systable_endscan(scan);
     714              : 
     715          640 :     table_close(depRel, RowExclusiveLock);
     716              : 
     717          640 :     return count;
     718              : }
     719              : 
     720              : /*
     721              :  * isObjectPinned()
     722              :  *
     723              :  * Test if an object is required for basic database functionality.
     724              :  *
     725              :  * The passed subId, if any, is ignored; we assume that only whole objects
     726              :  * are pinned (and that this implies pinning their components).
     727              :  */
     728              : static bool
     729      1434399 : isObjectPinned(const ObjectAddress *object)
     730              : {
     731      1434399 :     return IsPinnedObject(object->classId, object->objectId);
     732              : }
     733              : 
     734              : 
     735              : /*
     736              :  * dependencyLockAndCheckObject
     737              :  *
     738              :  * Lock the object that we are about to record a dependency on.  After it's
     739              :  * locked, verify that it hasn't been dropped while we weren't looking.  If it
     740              :  * has been dropped, throw an an error.
     741              :  *
     742              :  * If the caller already holds a lock that conflicts with DROP
     743              :  * (AccessShareLock or stronger), this does nothing.  Callers should acquire
     744              :  * locks already when they look up the referenced objects, but many callers
     745              :  * currently do not.  This is a backstop to make sure that we don't record a
     746              :  * bogus reference permanently in the catalogs in that case.  In the future,
     747              :  * after we have tightened up all the callers to acquire locks earlier, this
     748              :  * could just verify that the object is already locked and throw an error if
     749              :  * not.
     750              :  */
     751              : static void
     752       399299 : dependencyLockAndCheckObject(Oid classId, Oid objectId)
     753              : {
     754              :     /*
     755              :      * Pinned objects cannot be dropped concurrently, and callers checked this
     756              :      * already.
     757              :      */
     758              :     Assert(!IsPinnedObject(classId, objectId));
     759              : 
     760       399299 :     if (classId != RelationRelationId)
     761              :     {
     762              :         LOCKTAG     tag;
     763              :         SysCacheIdentifier cache;
     764              :         Relation    rel;
     765              :         SysScanDesc scan;
     766              :         ScanKeyData skey;
     767              :         HeapTuple   tuple;
     768              : 
     769       213065 :         SET_LOCKTAG_OBJECT(tag,
     770              :                            MyDatabaseId,
     771              :                            classId,
     772              :                            objectId,
     773              :                            0);
     774              : 
     775       213065 :         if (LockHeldByMe(&tag, AccessShareLock, true))
     776       158783 :             return;
     777              : 
     778              :         /* Assume we should lock the whole object not a sub-object */
     779        97738 :         LockDatabaseObject(classId, objectId, 0, AccessShareLock);
     780              : 
     781              :         /*
     782              :          * Check that the object still exists.  If the catalog has a suitable
     783              :          * syscache, check that first.
     784              :          */
     785        97738 :         cache = get_object_catcache_oid(classId);
     786        97738 :         if (cache != SYSCACHEID_INVALID)
     787              :         {
     788        95236 :             if (SearchSysCacheExists1(cache, ObjectIdGetDatum(objectId)))
     789        43456 :                 return;
     790              :         }
     791              : 
     792              :         /*
     793              :          * If it's not found in the syscache, or there's no suitable syscache
     794              :          * we can use, scan the catalog table using SnapshotSelf.  This
     795              :          * handles the case that it's an object we just created (for example,
     796              :          * if it's a composite type created as part of creating a table).
     797              :          */
     798        54282 :         rel = table_open(classId, AccessShareLock);
     799              : 
     800       108564 :         ScanKeyInit(&skey,
     801        54282 :                     get_object_attnum_oid(classId),
     802              :                     BTEqualStrategyNumber, F_OIDEQ,
     803              :                     ObjectIdGetDatum(objectId));
     804              : 
     805        54282 :         scan = systable_beginscan(rel, get_object_oid_index(classId),
     806              :                                   true, SnapshotSelf, 1, &skey);
     807              : 
     808        54282 :         tuple = systable_getnext(scan);
     809        54282 :         if (!HeapTupleIsValid(tuple))
     810            8 :             ereport(ERROR,
     811              :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     812              :                      errmsg("referenced %s was concurrently dropped",
     813              :                             get_object_class_descr(classId))));
     814              : 
     815        54274 :         systable_endscan(scan);
     816        54274 :         table_close(rel, AccessShareLock);
     817              :     }
     818              :     else
     819              :     {
     820              :         /*
     821              :          * Same logic for pg_class entries, but locking relations is handled
     822              :          * by different functions.
     823              :          *
     824              :          * Callers are more careful with locking relations than other objects,
     825              :          * so we should already have a lock on the relation, or on another
     826              :          * object that indirectly prevents the relation from being dropped.
     827              :          * For example, we might have a strong lock on a table while adding
     828              :          * dependency to its index.  However, we cannot detect the indirectly
     829              :          * protected case here easily.  To err on the safe side, acquire a
     830              :          * lock directly on the relation if we're not holding one already.
     831              :          */
     832              : 
     833              :         /* all shared relations are pinned */
     834              :         Assert(!IsSharedRelation(objectId));
     835              : 
     836       186234 :         if (CheckRelationOidLockedByMe(objectId, AccessShareLock, true))
     837       184174 :             return;
     838         2060 :         LockRelationOid(objectId, AccessShareLock);
     839              : 
     840         2060 :         if (SearchSysCacheExists1(RELOID, ObjectIdGetDatum(objectId)))
     841         2060 :             return;
     842            0 :         ereport(ERROR,
     843              :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     844              :                  errmsg("referenced relation was concurrently dropped")));
     845              :     }
     846              : }
     847              : 
     848              : /*
     849              :  * Various special-purpose lookups and manipulations of pg_depend.
     850              :  */
     851              : 
     852              : 
     853              : /*
     854              :  * Find the extension containing the specified object, if any
     855              :  *
     856              :  * Returns the OID of the extension, or InvalidOid if the object does not
     857              :  * belong to any extension.
     858              :  *
     859              :  * Extension membership is marked by an EXTENSION dependency from the object
     860              :  * to the extension.  Note that the result will be indeterminate if pg_depend
     861              :  * contains links from this object to more than one extension ... but that
     862              :  * should never happen.
     863              :  */
     864              : Oid
     865          656 : getExtensionOfObject(Oid classId, Oid objectId)
     866              : {
     867          656 :     Oid         result = InvalidOid;
     868              :     Relation    depRel;
     869              :     ScanKeyData key[2];
     870              :     SysScanDesc scan;
     871              :     HeapTuple   tup;
     872              : 
     873          656 :     depRel = table_open(DependRelationId, AccessShareLock);
     874              : 
     875          656 :     ScanKeyInit(&key[0],
     876              :                 Anum_pg_depend_classid,
     877              :                 BTEqualStrategyNumber, F_OIDEQ,
     878              :                 ObjectIdGetDatum(classId));
     879          656 :     ScanKeyInit(&key[1],
     880              :                 Anum_pg_depend_objid,
     881              :                 BTEqualStrategyNumber, F_OIDEQ,
     882              :                 ObjectIdGetDatum(objectId));
     883              : 
     884          656 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     885              :                               NULL, 2, key);
     886              : 
     887         1562 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     888              :     {
     889         1483 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     890              : 
     891         1483 :         if (depform->refclassid == ExtensionRelationId &&
     892          577 :             depform->deptype == DEPENDENCY_EXTENSION)
     893              :         {
     894          577 :             result = depform->refobjid;
     895          577 :             break;              /* no need to keep scanning */
     896              :         }
     897              :     }
     898              : 
     899          656 :     systable_endscan(scan);
     900              : 
     901          656 :     table_close(depRel, AccessShareLock);
     902              : 
     903          656 :     return result;
     904              : }
     905              : 
     906              : /*
     907              :  * Return (possibly NIL) list of extensions that the given object depends on
     908              :  * in DEPENDENCY_AUTO_EXTENSION mode.
     909              :  */
     910              : List *
     911          227 : getAutoExtensionsOfObject(Oid classId, Oid objectId)
     912              : {
     913          227 :     List       *result = NIL;
     914              :     Relation    depRel;
     915              :     ScanKeyData key[2];
     916              :     SysScanDesc scan;
     917              :     HeapTuple   tup;
     918              : 
     919          227 :     depRel = table_open(DependRelationId, AccessShareLock);
     920              : 
     921          227 :     ScanKeyInit(&key[0],
     922              :                 Anum_pg_depend_classid,
     923              :                 BTEqualStrategyNumber, F_OIDEQ,
     924              :                 ObjectIdGetDatum(classId));
     925          227 :     ScanKeyInit(&key[1],
     926              :                 Anum_pg_depend_objid,
     927              :                 BTEqualStrategyNumber, F_OIDEQ,
     928              :                 ObjectIdGetDatum(objectId));
     929              : 
     930          227 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     931              :                               NULL, 2, key);
     932              : 
     933          911 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     934              :     {
     935          684 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     936              : 
     937          684 :         if (depform->refclassid == ExtensionRelationId &&
     938           26 :             depform->deptype == DEPENDENCY_AUTO_EXTENSION)
     939           26 :             result = lappend_oid(result, depform->refobjid);
     940              :     }
     941              : 
     942          227 :     systable_endscan(scan);
     943              : 
     944          227 :     table_close(depRel, AccessShareLock);
     945              : 
     946          227 :     return result;
     947              : }
     948              : 
     949              : /*
     950              :  * Look up a type belonging to an extension.
     951              :  *
     952              :  * Returns the type's OID, or InvalidOid if not found.
     953              :  *
     954              :  * Notice that the type is specified by name only, without a schema.
     955              :  * That's because this will typically be used by relocatable extensions
     956              :  * which can't make a-priori assumptions about which schema their objects
     957              :  * are in.  As long as the extension only defines one type of this name,
     958              :  * the answer is unique anyway.
     959              :  *
     960              :  * We might later add the ability to look up functions, operators, etc.
     961              :  */
     962              : Oid
     963            1 : getExtensionType(Oid extensionOid, const char *typname)
     964              : {
     965            1 :     Oid         result = InvalidOid;
     966              :     Relation    depRel;
     967              :     ScanKeyData key[3];
     968              :     SysScanDesc scan;
     969              :     HeapTuple   tup;
     970              : 
     971            1 :     depRel = table_open(DependRelationId, AccessShareLock);
     972              : 
     973            1 :     ScanKeyInit(&key[0],
     974              :                 Anum_pg_depend_refclassid,
     975              :                 BTEqualStrategyNumber, F_OIDEQ,
     976              :                 ObjectIdGetDatum(ExtensionRelationId));
     977            1 :     ScanKeyInit(&key[1],
     978              :                 Anum_pg_depend_refobjid,
     979              :                 BTEqualStrategyNumber, F_OIDEQ,
     980              :                 ObjectIdGetDatum(extensionOid));
     981            1 :     ScanKeyInit(&key[2],
     982              :                 Anum_pg_depend_refobjsubid,
     983              :                 BTEqualStrategyNumber, F_INT4EQ,
     984              :                 Int32GetDatum(0));
     985              : 
     986            1 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     987              :                               NULL, 3, key);
     988              : 
     989            1 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     990              :     {
     991            1 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     992              : 
     993            1 :         if (depform->classid == TypeRelationId &&
     994            1 :             depform->deptype == DEPENDENCY_EXTENSION)
     995              :         {
     996            1 :             Oid         typoid = depform->objid;
     997              :             HeapTuple   typtup;
     998              : 
     999            1 :             typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
    1000            1 :             if (!HeapTupleIsValid(typtup))
    1001            0 :                 continue;       /* should we throw an error? */
    1002            1 :             if (strcmp(NameStr(((Form_pg_type) GETSTRUCT(typtup))->typname),
    1003              :                        typname) == 0)
    1004              :             {
    1005            1 :                 result = typoid;
    1006            1 :                 ReleaseSysCache(typtup);
    1007            1 :                 break;          /* no need to keep searching */
    1008              :             }
    1009            0 :             ReleaseSysCache(typtup);
    1010              :         }
    1011              :     }
    1012              : 
    1013            1 :     systable_endscan(scan);
    1014              : 
    1015            1 :     table_close(depRel, AccessShareLock);
    1016              : 
    1017            1 :     return result;
    1018              : }
    1019              : 
    1020              : /*
    1021              :  * Detect whether a sequence is marked as "owned" by a column
    1022              :  *
    1023              :  * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the
    1024              :  * column.  If we find one, store the identity of the owning column
    1025              :  * into *tableId and *colId and return true; else return false.
    1026              :  *
    1027              :  * Note: if there's more than one such pg_depend entry then you get
    1028              :  * a random one of them returned into the out parameters.  This should
    1029              :  * not happen, though.
    1030              :  */
    1031              : bool
    1032          557 : sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
    1033              : {
    1034          557 :     bool        ret = false;
    1035              :     Relation    depRel;
    1036              :     ScanKeyData key[2];
    1037              :     SysScanDesc scan;
    1038              :     HeapTuple   tup;
    1039              : 
    1040          557 :     depRel = table_open(DependRelationId, AccessShareLock);
    1041              : 
    1042          557 :     ScanKeyInit(&key[0],
    1043              :                 Anum_pg_depend_classid,
    1044              :                 BTEqualStrategyNumber, F_OIDEQ,
    1045              :                 ObjectIdGetDatum(RelationRelationId));
    1046          557 :     ScanKeyInit(&key[1],
    1047              :                 Anum_pg_depend_objid,
    1048              :                 BTEqualStrategyNumber, F_OIDEQ,
    1049              :                 ObjectIdGetDatum(seqId));
    1050              : 
    1051          557 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
    1052              :                               NULL, 2, key);
    1053              : 
    1054         1115 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
    1055              :     {
    1056          566 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
    1057              : 
    1058          566 :         if (depform->refclassid == RelationRelationId &&
    1059            8 :             depform->deptype == deptype)
    1060              :         {
    1061            8 :             *tableId = depform->refobjid;
    1062            8 :             *colId = depform->refobjsubid;
    1063            8 :             ret = true;
    1064            8 :             break;              /* no need to keep scanning */
    1065              :         }
    1066              :     }
    1067              : 
    1068          557 :     systable_endscan(scan);
    1069              : 
    1070          557 :     table_close(depRel, AccessShareLock);
    1071              : 
    1072          557 :     return ret;
    1073              : }
    1074              : 
    1075              : /*
    1076              :  * Collect a list of OIDs of all sequences owned by the specified relation,
    1077              :  * and column if specified.  If deptype is not zero, then only find sequences
    1078              :  * with the specified dependency type.
    1079              :  */
    1080              : static List *
    1081          495 : getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
    1082              : {
    1083          495 :     List       *result = NIL;
    1084              :     Relation    depRel;
    1085              :     ScanKeyData key[3];
    1086              :     SysScanDesc scan;
    1087              :     HeapTuple   tup;
    1088              : 
    1089          495 :     depRel = table_open(DependRelationId, AccessShareLock);
    1090              : 
    1091          495 :     ScanKeyInit(&key[0],
    1092              :                 Anum_pg_depend_refclassid,
    1093              :                 BTEqualStrategyNumber, F_OIDEQ,
    1094              :                 ObjectIdGetDatum(RelationRelationId));
    1095          495 :     ScanKeyInit(&key[1],
    1096              :                 Anum_pg_depend_refobjid,
    1097              :                 BTEqualStrategyNumber, F_OIDEQ,
    1098              :                 ObjectIdGetDatum(relid));
    1099          495 :     if (attnum)
    1100          429 :         ScanKeyInit(&key[2],
    1101              :                     Anum_pg_depend_refobjsubid,
    1102              :                     BTEqualStrategyNumber, F_INT4EQ,
    1103              :                     Int32GetDatum(attnum));
    1104              : 
    1105          495 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
    1106              :                               NULL, attnum ? 3 : 2, key);
    1107              : 
    1108         1656 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
    1109              :     {
    1110         1161 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
    1111              : 
    1112              :         /*
    1113              :          * We assume any auto or internal dependency of a sequence on a column
    1114              :          * must be what we are looking for.  (We need the relkind test because
    1115              :          * indexes can also have auto dependencies on columns.)
    1116              :          */
    1117         1161 :         if (deprec->classid == RelationRelationId &&
    1118          502 :             deprec->objsubid == 0 &&
    1119          502 :             deprec->refobjsubid != 0 &&
    1120          964 :             (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
    1121          482 :             get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
    1122              :         {
    1123          479 :             if (!deptype || deprec->deptype == deptype)
    1124          475 :                 result = lappend_oid(result, deprec->objid);
    1125              :         }
    1126              :     }
    1127              : 
    1128          495 :     systable_endscan(scan);
    1129              : 
    1130          495 :     table_close(depRel, AccessShareLock);
    1131              : 
    1132          495 :     return result;
    1133              : }
    1134              : 
    1135              : /*
    1136              :  * Collect a list of OIDs of all sequences owned (identity or serial) by the
    1137              :  * specified relation.
    1138              :  */
    1139              : List *
    1140           66 : getOwnedSequences(Oid relid)
    1141              : {
    1142           66 :     return getOwnedSequences_internal(relid, 0, 0);
    1143              : }
    1144              : 
    1145              : /*
    1146              :  * Get owned identity sequence, error if not exactly one.
    1147              :  */
    1148              : Oid
    1149          429 : getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
    1150              : {
    1151          429 :     Oid         relid = RelationGetRelid(rel);
    1152              :     List       *seqlist;
    1153              : 
    1154              :     /*
    1155              :      * The identity sequence is associated with the topmost partitioned table,
    1156              :      * which might have column order different than the given partition.
    1157              :      */
    1158          429 :     if (RelationGetForm(rel)->relispartition)
    1159              :     {
    1160           36 :         List       *ancestors = get_partition_ancestors(relid);
    1161           36 :         const char *attname = get_attname(relid, attnum, false);
    1162              : 
    1163           36 :         relid = llast_oid(ancestors);
    1164           36 :         attnum = get_attnum(relid, attname);
    1165           36 :         if (attnum == InvalidAttrNumber)
    1166            0 :             elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
    1167              :                  attname, relid);
    1168           36 :         list_free(ancestors);
    1169              :     }
    1170              : 
    1171          429 :     seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
    1172          429 :     if (list_length(seqlist) > 1)
    1173            0 :         elog(ERROR, "more than one owned sequence found");
    1174          429 :     else if (seqlist == NIL)
    1175              :     {
    1176            8 :         if (missing_ok)
    1177            8 :             return InvalidOid;
    1178              :         else
    1179            0 :             elog(ERROR, "no owned sequence found");
    1180              :     }
    1181              : 
    1182          421 :     return linitial_oid(seqlist);
    1183              : }
    1184              : 
    1185              : /*
    1186              :  * get_index_constraint
    1187              :  *      Given the OID of an index, return the OID of the owning unique,
    1188              :  *      primary-key, or exclusion constraint, or InvalidOid if there
    1189              :  *      is no owning constraint.
    1190              :  */
    1191              : Oid
    1192         8813 : get_index_constraint(Oid indexId)
    1193              : {
    1194         8813 :     Oid         constraintId = InvalidOid;
    1195              :     Relation    depRel;
    1196              :     ScanKeyData key[3];
    1197              :     SysScanDesc scan;
    1198              :     HeapTuple   tup;
    1199              : 
    1200              :     /* Search the dependency table for the index */
    1201         8813 :     depRel = table_open(DependRelationId, AccessShareLock);
    1202              : 
    1203         8813 :     ScanKeyInit(&key[0],
    1204              :                 Anum_pg_depend_classid,
    1205              :                 BTEqualStrategyNumber, F_OIDEQ,
    1206              :                 ObjectIdGetDatum(RelationRelationId));
    1207         8813 :     ScanKeyInit(&key[1],
    1208              :                 Anum_pg_depend_objid,
    1209              :                 BTEqualStrategyNumber, F_OIDEQ,
    1210              :                 ObjectIdGetDatum(indexId));
    1211         8813 :     ScanKeyInit(&key[2],
    1212              :                 Anum_pg_depend_objsubid,
    1213              :                 BTEqualStrategyNumber, F_INT4EQ,
    1214              :                 Int32GetDatum(0));
    1215              : 
    1216         8813 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
    1217              :                               NULL, 3, key);
    1218              : 
    1219        10743 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
    1220              :     {
    1221         3129 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
    1222              : 
    1223              :         /*
    1224              :          * We assume any internal dependency on a constraint must be what we
    1225              :          * are looking for.
    1226              :          */
    1227         3129 :         if (deprec->refclassid == ConstraintRelationId &&
    1228         1199 :             deprec->refobjsubid == 0 &&
    1229         1199 :             deprec->deptype == DEPENDENCY_INTERNAL)
    1230              :         {
    1231         1199 :             constraintId = deprec->refobjid;
    1232         1199 :             break;
    1233              :         }
    1234              :     }
    1235              : 
    1236         8813 :     systable_endscan(scan);
    1237         8813 :     table_close(depRel, AccessShareLock);
    1238              : 
    1239         8813 :     return constraintId;
    1240              : }
    1241              : 
    1242              : /*
    1243              :  * get_index_ref_constraints
    1244              :  *      Given the OID of an index, return the OID of all foreign key
    1245              :  *      constraints which reference the index.
    1246              :  */
    1247              : List *
    1248          320 : get_index_ref_constraints(Oid indexId)
    1249              : {
    1250          320 :     List       *result = NIL;
    1251              :     Relation    depRel;
    1252              :     ScanKeyData key[3];
    1253              :     SysScanDesc scan;
    1254              :     HeapTuple   tup;
    1255              : 
    1256              :     /* Search the dependency table for the index */
    1257          320 :     depRel = table_open(DependRelationId, AccessShareLock);
    1258              : 
    1259          320 :     ScanKeyInit(&key[0],
    1260              :                 Anum_pg_depend_refclassid,
    1261              :                 BTEqualStrategyNumber, F_OIDEQ,
    1262              :                 ObjectIdGetDatum(RelationRelationId));
    1263          320 :     ScanKeyInit(&key[1],
    1264              :                 Anum_pg_depend_refobjid,
    1265              :                 BTEqualStrategyNumber, F_OIDEQ,
    1266              :                 ObjectIdGetDatum(indexId));
    1267          320 :     ScanKeyInit(&key[2],
    1268              :                 Anum_pg_depend_refobjsubid,
    1269              :                 BTEqualStrategyNumber, F_INT4EQ,
    1270              :                 Int32GetDatum(0));
    1271              : 
    1272          320 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
    1273              :                               NULL, 3, key);
    1274              : 
    1275          331 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
    1276              :     {
    1277           11 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
    1278              : 
    1279              :         /*
    1280              :          * We assume any normal dependency from a constraint must be what we
    1281              :          * are looking for.
    1282              :          */
    1283           11 :         if (deprec->classid == ConstraintRelationId &&
    1284           11 :             deprec->objsubid == 0 &&
    1285           11 :             deprec->deptype == DEPENDENCY_NORMAL)
    1286              :         {
    1287           11 :             result = lappend_oid(result, deprec->objid);
    1288              :         }
    1289              :     }
    1290              : 
    1291          320 :     systable_endscan(scan);
    1292          320 :     table_close(depRel, AccessShareLock);
    1293              : 
    1294          320 :     return result;
    1295              : }
        

Generated by: LCOV version 2.0-1