LCOV - differential code coverage report
Current view: top level - src/backend/catalog - pg_depend.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 98.0 % 301 295 6 1 294 1
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 19 19 1 18
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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 CBC     1644876 : recordDependencyOn(const ObjectAddress *depender,
      45                 :                    const ObjectAddress *referenced,
      46                 :                    DependencyType behavior)
      47                 : {
      48         1644876 :     recordMultipleDependencies(depender, referenced, 1, behavior);
      49         1644876 : }
      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         2115320 : 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         2115320 :     if (nreferenced <= 0)
      70           43444 :         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         2071876 :     if (IsBootstrapProcessingMode())
      80          203435 :         return;
      81                 : 
      82         1868441 :     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         1868441 :     max_slots = Min(nreferenced,
      89                 :                     MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_depend));
      90         1868441 :     slot = palloc(sizeof(TupleTableSlot *) * max_slots);
      91                 : 
      92                 :     /* Don't open indexes unless we need to make an update */
      93         1868441 :     indstate = NULL;
      94                 : 
      95                 :     /* number of slots currently storing tuples */
      96         1868441 :     slot_stored_count = 0;
      97                 :     /* number of slots currently initialized */
      98         1868441 :     slot_init_count = 0;
      99         5365101 :     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         3496660 :         if (isObjectPinned(referenced))
     107         2807470 :             continue;
     108                 : 
     109          689190 :         if (slot_init_count < max_slots)
     110                 :         {
     111          689190 :             slot[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc),
     112                 :                                                                &TTSOpsHeapTuple);
     113          689190 :             slot_init_count++;
     114                 :         }
     115                 : 
     116          689190 :         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          689190 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
     123          689190 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
     124          689190 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
     125          689190 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
     126          689190 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
     127          689190 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
     128          689190 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
     129                 : 
     130          689190 :         memset(slot[slot_stored_count]->tts_isnull, false,
     131          689190 :                slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
     132                 : 
     133          689190 :         ExecStoreVirtualTuple(slot[slot_stored_count]);
     134          689190 :         slot_stored_count++;
     135                 : 
     136                 :         /* If slots are full, insert a batch of tuples */
     137          689190 :         if (slot_stored_count == max_slots)
     138                 :         {
     139                 :             /* fetch index info only when we know we need it */
     140          480987 :             if (indstate == NULL)
     141          480987 :                 indstate = CatalogOpenIndexes(dependDesc);
     142                 : 
     143          480987 :             CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
     144                 :                                              indstate);
     145          480987 :             slot_stored_count = 0;
     146                 :         }
     147                 :     }
     148                 : 
     149                 :     /* Insert any tuples left in the buffer */
     150         1868441 :     if (slot_stored_count > 0)
     151                 :     {
     152                 :         /* fetch index info only when we know we need it */
     153           82143 :         if (indstate == NULL)
     154           82143 :             indstate = CatalogOpenIndexes(dependDesc);
     155                 : 
     156           82143 :         CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
     157                 :                                          indstate);
     158                 :     }
     159                 : 
     160         1868441 :     if (indstate != NULL)
     161          563130 :         CatalogCloseIndexes(indstate);
     162                 : 
     163         1868441 :     table_close(dependDesc, RowExclusiveLock);
     164                 : 
     165                 :     /* Drop only the number of slots used */
     166         2557631 :     for (i = 0; i < slot_init_count; i++)
     167          689190 :         ExecDropSingleTupleTableSlot(slot[i]);
     168         1868441 :     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          588619 : recordDependencyOnCurrentExtension(const ObjectAddress *object,
     193                 :                                    bool isReplace)
     194                 : {
     195                 :     /* Only whole objects can be extension members */
     196          588619 :     Assert(object->objectSubId == 0);
     197                 : 
     198          588619 :     if (creating_extension)
     199                 :     {
     200                 :         ObjectAddress extension;
     201                 : 
     202                 :         /* Only need to check for existing membership if isReplace */
     203            4759 :         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             310 :             oldext = getExtensionOfObject(object->classId, object->objectId);
     214             310 :             if (OidIsValid(oldext))
     215                 :             {
     216                 :                 /* If already a member of this extension, nothing to do */
     217             306 :                 if (oldext == CurrentExtensionObject)
     218             306 :                     return;
     219                 :                 /* Already a member of some other extension, so reject */
     220 UBC           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 CBC           4 :             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            4449 :         extension.classId = ExtensionRelationId;
     237            4449 :         extension.objectId = CurrentExtensionObject;
     238            4449 :         extension.objectSubId = 0;
     239                 : 
     240            4449 :         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              75 : 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              75 :     Assert(object->objectSubId == 0);
     268                 : 
     269              75 :     if (creating_extension)
     270                 :     {
     271                 :         Oid         oldext;
     272                 : 
     273              14 :         oldext = getExtensionOfObject(object->classId, object->objectId);
     274                 :         /* If already a member of this extension, OK */
     275              14 :         if (oldext == CurrentExtensionObject)
     276               7 :             return;
     277                 :         /* Else complain */
     278               7 :         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           51441 : deleteDependencyRecordsFor(Oid classId, Oid objectId,
     301                 :                            bool skipExtensionDeps)
     302                 : {
     303           51441 :     long        count = 0;
     304                 :     Relation    depRel;
     305                 :     ScanKeyData key[2];
     306                 :     SysScanDesc scan;
     307                 :     HeapTuple   tup;
     308                 : 
     309           51441 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     310                 : 
     311           51441 :     ScanKeyInit(&key[0],
     312                 :                 Anum_pg_depend_classid,
     313                 :                 BTEqualStrategyNumber, F_OIDEQ,
     314                 :                 ObjectIdGetDatum(classId));
     315           51441 :     ScanKeyInit(&key[1],
     316                 :                 Anum_pg_depend_objid,
     317                 :                 BTEqualStrategyNumber, F_OIDEQ,
     318                 :                 ObjectIdGetDatum(objectId));
     319                 : 
     320           51441 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     321                 :                               NULL, 2, key);
     322                 : 
     323           64168 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     324                 :     {
     325           12727 :         if (skipExtensionDeps &&
     326           11846 :             ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
     327             538 :             continue;
     328                 : 
     329           12189 :         CatalogTupleDelete(depRel, &tup->t_self);
     330           12189 :         count++;
     331                 :     }
     332                 : 
     333           51441 :     systable_endscan(scan);
     334                 : 
     335           51441 :     table_close(depRel, RowExclusiveLock);
     336                 : 
     337           51441 :     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           34539 : deleteDependencyRecordsForClass(Oid classId, Oid objectId,
     351                 :                                 Oid refclassId, char deptype)
     352                 : {
     353           34539 :     long        count = 0;
     354                 :     Relation    depRel;
     355                 :     ScanKeyData key[2];
     356                 :     SysScanDesc scan;
     357                 :     HeapTuple   tup;
     358                 : 
     359           34539 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     360                 : 
     361           34539 :     ScanKeyInit(&key[0],
     362                 :                 Anum_pg_depend_classid,
     363                 :                 BTEqualStrategyNumber, F_OIDEQ,
     364                 :                 ObjectIdGetDatum(classId));
     365           34539 :     ScanKeyInit(&key[1],
     366                 :                 Anum_pg_depend_objid,
     367                 :                 BTEqualStrategyNumber, F_OIDEQ,
     368                 :                 ObjectIdGetDatum(objectId));
     369                 : 
     370           34539 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     371                 :                               NULL, 2, key);
     372                 : 
     373           36806 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     374                 :     {
     375            2267 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     376                 : 
     377            2267 :         if (depform->refclassid == refclassId && depform->deptype == deptype)
     378                 :         {
     379             434 :             CatalogTupleDelete(depRel, &tup->t_self);
     380             434 :             count++;
     381                 :         }
     382                 :     }
     383                 : 
     384           34539 :     systable_endscan(scan);
     385                 : 
     386           34539 :     table_close(depRel, RowExclusiveLock);
     387                 : 
     388           34539 :     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               4 : deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
     398                 :                                    Oid refclassId, Oid refobjectId)
     399                 : {
     400               4 :     long        count = 0;
     401                 :     Relation    depRel;
     402                 :     ScanKeyData key[2];
     403                 :     SysScanDesc scan;
     404                 :     HeapTuple   tup;
     405                 : 
     406               4 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     407                 : 
     408               4 :     ScanKeyInit(&key[0],
     409                 :                 Anum_pg_depend_classid,
     410                 :                 BTEqualStrategyNumber, F_OIDEQ,
     411                 :                 ObjectIdGetDatum(classId));
     412               4 :     ScanKeyInit(&key[1],
     413                 :                 Anum_pg_depend_objid,
     414                 :                 BTEqualStrategyNumber, F_OIDEQ,
     415                 :                 ObjectIdGetDatum(objectId));
     416                 : 
     417               4 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     418                 :                               NULL, 2, key);
     419                 : 
     420              14 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     421                 :     {
     422              10 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     423                 : 
     424              10 :         if (depform->refclassid == refclassId &&
     425               4 :             depform->refobjid == refobjectId &&
     426               4 :             depform->deptype == deptype)
     427                 :         {
     428               4 :             CatalogTupleDelete(depRel, &tup->t_self);
     429               4 :             count++;
     430                 :         }
     431                 :     }
     432                 : 
     433               4 :     systable_endscan(scan);
     434                 : 
     435               4 :     table_close(depRel, RowExclusiveLock);
     436                 : 
     437               4 :     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             129 : changeDependencyFor(Oid classId, Oid objectId,
     457                 :                     Oid refClassId, Oid oldRefObjectId,
     458                 :                     Oid newRefObjectId)
     459                 : {
     460             129 :     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             129 :     objAddr.classId = refClassId;
     477             129 :     objAddr.objectId = oldRefObjectId;
     478             129 :     objAddr.objectSubId = 0;
     479                 : 
     480             129 :     oldIsPinned = isObjectPinned(&objAddr);
     481                 : 
     482             129 :     objAddr.objectId = newRefObjectId;
     483                 : 
     484             129 :     newIsPinned = isObjectPinned(&objAddr);
     485                 : 
     486             129 :     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               7 :         if (newIsPinned)
     493 UBC           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 CBC           7 :         depAddr.classId = classId;
     500               7 :         depAddr.objectId = objectId;
     501               7 :         depAddr.objectSubId = 0;
     502               7 :         recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
     503                 : 
     504               7 :         return 1;
     505                 :     }
     506                 : 
     507             122 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     508                 : 
     509                 :     /* There should be existing dependency record(s), so search. */
     510             122 :     ScanKeyInit(&key[0],
     511                 :                 Anum_pg_depend_classid,
     512                 :                 BTEqualStrategyNumber, F_OIDEQ,
     513                 :                 ObjectIdGetDatum(classId));
     514             122 :     ScanKeyInit(&key[1],
     515                 :                 Anum_pg_depend_objid,
     516                 :                 BTEqualStrategyNumber, F_OIDEQ,
     517                 :                 ObjectIdGetDatum(objectId));
     518                 : 
     519             122 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     520                 :                               NULL, 2, key);
     521                 : 
     522             301 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     523                 :     {
     524             179 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     525                 : 
     526             179 :         if (depform->refclassid == refClassId &&
     527             122 :             depform->refobjid == oldRefObjectId)
     528                 :         {
     529             122 :             if (newIsPinned)
     530              12 :                 CatalogTupleDelete(depRel, &tup->t_self);
     531                 :             else
     532                 :             {
     533                 :                 /* make a modifiable copy */
     534             110 :                 tup = heap_copytuple(tup);
     535             110 :                 depform = (Form_pg_depend) GETSTRUCT(tup);
     536                 : 
     537             110 :                 depform->refobjid = newRefObjectId;
     538                 : 
     539             110 :                 CatalogTupleUpdate(depRel, &tup->t_self, tup);
     540                 : 
     541             110 :                 heap_freetuple(tup);
     542                 :             }
     543                 : 
     544             122 :             count++;
     545                 :         }
     546                 :     }
     547                 : 
     548             122 :     systable_endscan(scan);
     549                 : 
     550             122 :     table_close(depRel, RowExclusiveLock);
     551                 : 
     552             122 :     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             428 : changeDependenciesOf(Oid classId, Oid oldObjectId,
     565                 :                      Oid newObjectId)
     566                 : {
     567             428 :     long        count = 0;
     568                 :     Relation    depRel;
     569                 :     ScanKeyData key[2];
     570                 :     SysScanDesc scan;
     571                 :     HeapTuple   tup;
     572                 : 
     573             428 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     574                 : 
     575             428 :     ScanKeyInit(&key[0],
     576                 :                 Anum_pg_depend_classid,
     577                 :                 BTEqualStrategyNumber, F_OIDEQ,
     578                 :                 ObjectIdGetDatum(classId));
     579             428 :     ScanKeyInit(&key[1],
     580                 :                 Anum_pg_depend_objid,
     581                 :                 BTEqualStrategyNumber, F_OIDEQ,
     582                 :                 ObjectIdGetDatum(oldObjectId));
     583                 : 
     584             428 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     585                 :                               NULL, 2, key);
     586                 : 
     587            1208 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     588                 :     {
     589                 :         Form_pg_depend depform;
     590                 : 
     591                 :         /* make a modifiable copy */
     592             780 :         tup = heap_copytuple(tup);
     593             780 :         depform = (Form_pg_depend) GETSTRUCT(tup);
     594                 : 
     595             780 :         depform->objid = newObjectId;
     596                 : 
     597             780 :         CatalogTupleUpdate(depRel, &tup->t_self, tup);
     598                 : 
     599             780 :         heap_freetuple(tup);
     600                 : 
     601             780 :         count++;
     602                 :     }
     603                 : 
     604             428 :     systable_endscan(scan);
     605                 : 
     606             428 :     table_close(depRel, RowExclusiveLock);
     607                 : 
     608             428 :     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             428 : changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
     621                 :                      Oid newRefObjectId)
     622                 : {
     623             428 :     long        count = 0;
     624                 :     Relation    depRel;
     625                 :     ScanKeyData key[2];
     626                 :     SysScanDesc scan;
     627                 :     HeapTuple   tup;
     628                 :     ObjectAddress objAddr;
     629                 :     bool        newIsPinned;
     630                 : 
     631             428 :     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             428 :     objAddr.classId = refClassId;
     640             428 :     objAddr.objectId = oldRefObjectId;
     641             428 :     objAddr.objectSubId = 0;
     642                 : 
     643             428 :     if (isObjectPinned(&objAddr))
     644 UBC           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 CBC         428 :     objAddr.objectId = newRefObjectId;
     654                 : 
     655             428 :     newIsPinned = isObjectPinned(&objAddr);
     656                 : 
     657                 :     /* Now search for dependency records */
     658             428 :     ScanKeyInit(&key[0],
     659                 :                 Anum_pg_depend_refclassid,
     660                 :                 BTEqualStrategyNumber, F_OIDEQ,
     661                 :                 ObjectIdGetDatum(refClassId));
     662             428 :     ScanKeyInit(&key[1],
     663                 :                 Anum_pg_depend_refobjid,
     664                 :                 BTEqualStrategyNumber, F_OIDEQ,
     665                 :                 ObjectIdGetDatum(oldRefObjectId));
     666                 : 
     667             428 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     668                 :                               NULL, 2, key);
     669                 : 
     670             434 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     671                 :     {
     672               6 :         if (newIsPinned)
     673 UBC           0 :             CatalogTupleDelete(depRel, &tup->t_self);
     674                 :         else
     675                 :         {
     676                 :             Form_pg_depend depform;
     677                 : 
     678                 :             /* make a modifiable copy */
     679 CBC           6 :             tup = heap_copytuple(tup);
     680               6 :             depform = (Form_pg_depend) GETSTRUCT(tup);
     681                 : 
     682               6 :             depform->refobjid = newRefObjectId;
     683                 : 
     684               6 :             CatalogTupleUpdate(depRel, &tup->t_self, tup);
     685                 : 
     686               6 :             heap_freetuple(tup);
     687                 :         }
     688                 : 
     689               6 :         count++;
     690                 :     }
     691                 : 
     692             428 :     systable_endscan(scan);
     693                 : 
     694             428 :     table_close(depRel, RowExclusiveLock);
     695                 : 
     696             428 :     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         3497774 : isObjectPinned(const ObjectAddress *object)
     709                 : {
     710         3497774 :     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             435 : getExtensionOfObject(Oid classId, Oid objectId)
     732                 : {
     733             435 :     Oid         result = InvalidOid;
     734                 :     Relation    depRel;
     735                 :     ScanKeyData key[2];
     736                 :     SysScanDesc scan;
     737                 :     HeapTuple   tup;
     738                 : 
     739             435 :     depRel = table_open(DependRelationId, AccessShareLock);
     740                 : 
     741             435 :     ScanKeyInit(&key[0],
     742                 :                 Anum_pg_depend_classid,
     743                 :                 BTEqualStrategyNumber, F_OIDEQ,
     744                 :                 ObjectIdGetDatum(classId));
     745             435 :     ScanKeyInit(&key[1],
     746                 :                 Anum_pg_depend_objid,
     747                 :                 BTEqualStrategyNumber, F_OIDEQ,
     748                 :                 ObjectIdGetDatum(objectId));
     749                 : 
     750             435 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     751                 :                               NULL, 2, key);
     752                 : 
     753            1224 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     754                 :     {
     755            1173 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     756                 : 
     757            1173 :         if (depform->refclassid == ExtensionRelationId &&
     758             384 :             depform->deptype == DEPENDENCY_EXTENSION)
     759                 :         {
     760             384 :             result = depform->refobjid;
     761             384 :             break;              /* no need to keep scanning */
     762                 :         }
     763                 :     }
     764                 : 
     765             435 :     systable_endscan(scan);
     766                 : 
     767             435 :     table_close(depRel, AccessShareLock);
     768                 : 
     769             435 :     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              19 : getAutoExtensionsOfObject(Oid classId, Oid objectId)
     778                 : {
     779              19 :     List       *result = NIL;
     780                 :     Relation    depRel;
     781                 :     ScanKeyData key[2];
     782                 :     SysScanDesc scan;
     783                 :     HeapTuple   tup;
     784                 : 
     785              19 :     depRel = table_open(DependRelationId, AccessShareLock);
     786                 : 
     787              19 :     ScanKeyInit(&key[0],
     788                 :                 Anum_pg_depend_classid,
     789                 :                 BTEqualStrategyNumber, F_OIDEQ,
     790                 :                 ObjectIdGetDatum(classId));
     791              19 :     ScanKeyInit(&key[1],
     792                 :                 Anum_pg_depend_objid,
     793                 :                 BTEqualStrategyNumber, F_OIDEQ,
     794                 :                 ObjectIdGetDatum(objectId));
     795                 : 
     796              19 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     797                 :                               NULL, 2, key);
     798                 : 
     799              48 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     800                 :     {
     801              29 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     802                 : 
     803              29 :         if (depform->refclassid == ExtensionRelationId &&
     804               1 :             depform->deptype == DEPENDENCY_AUTO_EXTENSION)
     805               1 :             result = lappend_oid(result, depform->refobjid);
     806                 :     }
     807                 : 
     808              19 :     systable_endscan(scan);
     809                 : 
     810              19 :     table_close(depRel, AccessShareLock);
     811                 : 
     812              19 :     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             367 : sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
     828                 : {
     829             367 :     bool        ret = false;
     830                 :     Relation    depRel;
     831                 :     ScanKeyData key[2];
     832                 :     SysScanDesc scan;
     833                 :     HeapTuple   tup;
     834                 : 
     835             367 :     depRel = table_open(DependRelationId, AccessShareLock);
     836                 : 
     837             367 :     ScanKeyInit(&key[0],
     838                 :                 Anum_pg_depend_classid,
     839                 :                 BTEqualStrategyNumber, F_OIDEQ,
     840                 :                 ObjectIdGetDatum(RelationRelationId));
     841             367 :     ScanKeyInit(&key[1],
     842                 :                 Anum_pg_depend_objid,
     843                 :                 BTEqualStrategyNumber, F_OIDEQ,
     844                 :                 ObjectIdGetDatum(seqId));
     845                 : 
     846             367 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     847                 :                               NULL, 2, key);
     848                 : 
     849             738 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     850                 :     {
     851             374 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     852                 : 
     853             374 :         if (depform->refclassid == RelationRelationId &&
     854               3 :             depform->deptype == deptype)
     855                 :         {
     856               3 :             *tableId = depform->refobjid;
     857               3 :             *colId = depform->refobjsubid;
     858               3 :             ret = true;
     859               3 :             break;              /* no need to keep scanning */
     860                 :         }
     861                 :     }
     862                 : 
     863             367 :     systable_endscan(scan);
     864                 : 
     865             367 :     table_close(depRel, AccessShareLock);
     866                 : 
     867             367 :     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             272 : getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
     877                 : {
     878             272 :     List       *result = NIL;
     879                 :     Relation    depRel;
     880                 :     ScanKeyData key[3];
     881                 :     SysScanDesc scan;
     882                 :     HeapTuple   tup;
     883                 : 
     884             272 :     depRel = table_open(DependRelationId, AccessShareLock);
     885                 : 
     886             272 :     ScanKeyInit(&key[0],
     887                 :                 Anum_pg_depend_refclassid,
     888                 :                 BTEqualStrategyNumber, F_OIDEQ,
     889                 :                 ObjectIdGetDatum(RelationRelationId));
     890             272 :     ScanKeyInit(&key[1],
     891                 :                 Anum_pg_depend_refobjid,
     892                 :                 BTEqualStrategyNumber, F_OIDEQ,
     893                 :                 ObjectIdGetDatum(relid));
     894             272 :     if (attnum)
     895             236 :         ScanKeyInit(&key[2],
     896                 :                     Anum_pg_depend_refobjsubid,
     897                 :                     BTEqualStrategyNumber, F_INT4EQ,
     898                 :                     Int32GetDatum(attnum));
     899                 : 
     900             272 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     901                 :                               NULL, attnum ? 3 : 2, key);
     902                 : 
     903             921 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     904                 :     {
     905             649 :         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             649 :         if (deprec->classid == RelationRelationId &&
     913             272 :             deprec->objsubid == 0 &&
     914             272 :             deprec->refobjsubid != 0 &&
     915             532 :             (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
     916             266 :             get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
     917                 :         {
     918             266 :             if (!deptype || deprec->deptype == deptype)
     919             263 :                 result = lappend_oid(result, deprec->objid);
     920                 :         }
     921                 :     }
     922                 : 
     923             272 :     systable_endscan(scan);
     924                 : 
     925             272 :     table_close(depRel, AccessShareLock);
     926                 : 
     927             272 :     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              36 : getOwnedSequences(Oid relid)
     936                 : {
     937              36 :     return getOwnedSequences_internal(relid, 0, 0);
     938                 : }
     939                 : 
     940                 : /*
     941                 :  * Get owned identity sequence, error if not exactly one.
     942                 :  */
     943                 : Oid
     944             236 : getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
     945                 : {
     946             236 :     List       *seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
     947                 : 
     948             236 :     if (list_length(seqlist) > 1)
     949 UBC           0 :         elog(ERROR, "more than one owned sequence found");
     950 GNC         236 :     else if (seqlist == NIL)
     951                 :     {
     952 CBC           6 :         if (missing_ok)
     953               6 :             return InvalidOid;
     954                 :         else
     955 UBC           0 :             elog(ERROR, "no owned sequence found");
     956                 :     }
     957                 : 
     958 CBC         230 :     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           34534 : get_index_constraint(Oid indexId)
     969                 : {
     970           34534 :     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           34534 :     depRel = table_open(DependRelationId, AccessShareLock);
     978                 : 
     979           34534 :     ScanKeyInit(&key[0],
     980                 :                 Anum_pg_depend_classid,
     981                 :                 BTEqualStrategyNumber, F_OIDEQ,
     982                 :                 ObjectIdGetDatum(RelationRelationId));
     983           34534 :     ScanKeyInit(&key[1],
     984                 :                 Anum_pg_depend_objid,
     985                 :                 BTEqualStrategyNumber, F_OIDEQ,
     986                 :                 ObjectIdGetDatum(indexId));
     987           34534 :     ScanKeyInit(&key[2],
     988                 :                 Anum_pg_depend_objsubid,
     989                 :                 BTEqualStrategyNumber, F_INT4EQ,
     990                 :                 Int32GetDatum(0));
     991                 : 
     992           34534 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     993                 :                               NULL, 3, key);
     994                 : 
     995           35653 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     996                 :     {
     997            1724 :         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            1724 :         if (deprec->refclassid == ConstraintRelationId &&
    1004             605 :             deprec->refobjsubid == 0 &&
    1005             605 :             deprec->deptype == DEPENDENCY_INTERNAL)
    1006                 :         {
    1007             605 :             constraintId = deprec->refobjid;
    1008             605 :             break;
    1009                 :         }
    1010                 :     }
    1011                 : 
    1012           34534 :     systable_endscan(scan);
    1013           34534 :     table_close(depRel, AccessShareLock);
    1014                 : 
    1015           34534 :     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             214 : get_index_ref_constraints(Oid indexId)
    1025                 : {
    1026             214 :     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             214 :     depRel = table_open(DependRelationId, AccessShareLock);
    1034                 : 
    1035             214 :     ScanKeyInit(&key[0],
    1036                 :                 Anum_pg_depend_refclassid,
    1037                 :                 BTEqualStrategyNumber, F_OIDEQ,
    1038                 :                 ObjectIdGetDatum(RelationRelationId));
    1039             214 :     ScanKeyInit(&key[1],
    1040                 :                 Anum_pg_depend_refobjid,
    1041                 :                 BTEqualStrategyNumber, F_OIDEQ,
    1042                 :                 ObjectIdGetDatum(indexId));
    1043             214 :     ScanKeyInit(&key[2],
    1044                 :                 Anum_pg_depend_refobjsubid,
    1045                 :                 BTEqualStrategyNumber, F_INT4EQ,
    1046                 :                 Int32GetDatum(0));
    1047                 : 
    1048             214 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
    1049                 :                               NULL, 3, key);
    1050                 : 
    1051             220 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
    1052                 :     {
    1053               6 :         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               6 :         if (deprec->classid == ConstraintRelationId &&
    1060               6 :             deprec->objsubid == 0 &&
    1061               6 :             deprec->deptype == DEPENDENCY_NORMAL)
    1062                 :         {
    1063               6 :             result = lappend_oid(result, deprec->objid);
    1064                 :         }
    1065                 :     }
    1066                 : 
    1067             214 :     systable_endscan(scan);
    1068             214 :     table_close(depRel, AccessShareLock);
    1069                 : 
    1070             214 :     return result;
    1071                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a