LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_depend.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 97.2 % 359 349
Test Date: 2026-07-09 00:15:43 Functions: 100.0 % 21 21
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 76.3 % 186 142

             Branch data     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                 :      543077 : recordDependencyOn(const ObjectAddress *depender,
      52                 :             :                    const ObjectAddress *referenced,
      53                 :             :                    DependencyType behavior)
      54                 :             : {
      55                 :      543077 :     recordMultipleDependencies(depender, referenced, 1, behavior);
      56                 :      543075 : }
      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                 :      835079 : 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         [ +  + ]:      835079 :     if (nreferenced <= 0)
      77                 :       33662 :         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         [ +  + ]:      801417 :     if (IsBootstrapProcessingMode())
      87                 :       41325 :         return;
      88                 :             : 
      89                 :      760092 :     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         [ +  - ]:      760092 :     max_slots = Min(nreferenced,
      96                 :             :                     MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_depend));
      97                 :      760092 :     slot = palloc_array(TupleTableSlot *, max_slots);
      98                 :             : 
      99                 :             :     /* Don't open indexes unless we need to make an update */
     100                 :      760092 :     indstate = NULL;
     101                 :             : 
     102                 :             :     /* number of slots currently storing tuples */
     103                 :      760092 :     slot_stored_count = 0;
     104                 :             :     /* number of slots currently initialized */
     105                 :      760092 :     slot_init_count = 0;
     106         [ +  + ]:     2204536 :     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         [ +  + ]:     1444451 :         if (isObjectPinned(referenced))
     114                 :     1041847 :             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                 :      402604 :         dependencyLockAndCheckObject(referenced->classId, referenced->objectId);
     122                 :             : 
     123         [ +  - ]:      402597 :         if (slot_init_count < max_slots)
     124                 :             :         {
     125                 :      402597 :             slot[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc),
     126                 :             :                                                                &TTSOpsHeapTuple);
     127                 :      402597 :             slot_init_count++;
     128                 :             :         }
     129                 :             : 
     130                 :      402597 :         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                 :      402597 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
     137                 :      402597 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
     138                 :      402597 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
     139                 :      402597 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior);
     140                 :      402597 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
     141                 :      402597 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
     142                 :      402597 :         slot[slot_stored_count]->tts_values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
     143                 :             : 
     144                 :      402597 :         memset(slot[slot_stored_count]->tts_isnull, false,
     145                 :      402597 :                slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
     146                 :             : 
     147                 :      402597 :         ExecStoreVirtualTuple(slot[slot_stored_count]);
     148                 :      402597 :         slot_stored_count++;
     149                 :             : 
     150                 :             :         /* If slots are full, insert a batch of tuples */
     151         [ +  + ]:      402597 :         if (slot_stored_count == max_slots)
     152                 :             :         {
     153                 :             :             /* fetch index info only when we know we need it */
     154         [ +  - ]:      283699 :             if (indstate == NULL)
     155                 :      283699 :                 indstate = CatalogOpenIndexes(dependDesc);
     156                 :             : 
     157                 :      283699 :             CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
     158                 :             :                                              indstate);
     159                 :      283699 :             slot_stored_count = 0;
     160                 :             :         }
     161                 :             :     }
     162                 :             : 
     163                 :             :     /* Insert any tuples left in the buffer */
     164         [ +  + ]:      760085 :     if (slot_stored_count > 0)
     165                 :             :     {
     166                 :             :         /* fetch index info only when we know we need it */
     167         [ +  - ]:       61916 :         if (indstate == NULL)
     168                 :       61916 :             indstate = CatalogOpenIndexes(dependDesc);
     169                 :             : 
     170                 :       61916 :         CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count,
     171                 :             :                                          indstate);
     172                 :             :     }
     173                 :             : 
     174         [ +  + ]:      760085 :     if (indstate != NULL)
     175                 :      345615 :         CatalogCloseIndexes(indstate);
     176                 :             : 
     177                 :      760085 :     table_close(dependDesc, RowExclusiveLock);
     178                 :             : 
     179                 :             :     /* Drop only the number of slots used */
     180         [ +  + ]:     1162682 :     for (i = 0; i < slot_init_count; i++)
     181                 :      402597 :         ExecDropSingleTupleTableSlot(slot[i]);
     182                 :      760085 :     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                 :      204545 : recordDependencyOnCurrentExtension(const ObjectAddress *object,
     207                 :             :                                    bool isReplace)
     208                 :             : {
     209                 :             :     /* Only whole objects can be extension members */
     210                 :             :     Assert(object->objectSubId == 0);
     211                 :             : 
     212         [ +  + ]:      204545 :     if (creating_extension)
     213                 :             :     {
     214                 :             :         ObjectAddress extension;
     215                 :             : 
     216                 :             :         /* Only need to check for existing membership if isReplace */
     217         [ +  + ]:        5969 :         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                 :        5568 :         extension.classId = ExtensionRelationId;
     251                 :        5568 :         extension.objectId = CurrentExtensionObject;
     252                 :        5568 :         extension.objectSubId = 0;
     253                 :             : 
     254                 :        5568 :         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                 :       10860 : deleteDependencyRecordsFor(Oid classId, Oid objectId,
     315                 :             :                            bool skipExtensionDeps)
     316                 :             : {
     317                 :       10860 :     long        count = 0;
     318                 :             :     Relation    depRel;
     319                 :             :     ScanKeyData key[2];
     320                 :             :     SysScanDesc scan;
     321                 :             :     HeapTuple   tup;
     322                 :             : 
     323                 :       10860 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     324                 :             : 
     325                 :       10860 :     ScanKeyInit(&key[0],
     326                 :             :                 Anum_pg_depend_classid,
     327                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     328                 :             :                 ObjectIdGetDatum(classId));
     329                 :       10860 :     ScanKeyInit(&key[1],
     330                 :             :                 Anum_pg_depend_objid,
     331                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     332                 :             :                 ObjectIdGetDatum(objectId));
     333                 :             : 
     334                 :       10860 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     335                 :             :                               NULL, 2, key);
     336                 :             : 
     337         [ +  + ]:       19008 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     338                 :             :     {
     339         [ +  + ]:        8148 :         if (skipExtensionDeps &&
     340         [ +  + ]:        5915 :             ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
     341                 :         635 :             continue;
     342                 :             : 
     343                 :        7513 :         CatalogTupleDelete(depRel, &tup->t_self);
     344                 :        7513 :         count++;
     345                 :             :     }
     346                 :             : 
     347                 :       10860 :     systable_endscan(scan);
     348                 :             : 
     349                 :       10860 :     table_close(depRel, RowExclusiveLock);
     350                 :             : 
     351                 :       10860 :     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                 :        9543 : deleteDependencyRecordsForClass(Oid classId, Oid objectId,
     365                 :             :                                 Oid refclassId, char deptype)
     366                 :             : {
     367                 :        9543 :     long        count = 0;
     368                 :             :     Relation    depRel;
     369                 :             :     ScanKeyData key[2];
     370                 :             :     SysScanDesc scan;
     371                 :             :     HeapTuple   tup;
     372                 :             : 
     373                 :        9543 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     374                 :             : 
     375                 :        9543 :     ScanKeyInit(&key[0],
     376                 :             :                 Anum_pg_depend_classid,
     377                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     378                 :             :                 ObjectIdGetDatum(classId));
     379                 :        9543 :     ScanKeyInit(&key[1],
     380                 :             :                 Anum_pg_depend_objid,
     381                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     382                 :             :                 ObjectIdGetDatum(objectId));
     383                 :             : 
     384                 :        9543 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     385                 :             :                               NULL, 2, key);
     386                 :             : 
     387         [ +  + ]:       16051 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     388                 :             :     {
     389                 :        6508 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     390                 :             : 
     391   [ +  +  +  + ]:        6508 :         if (depform->refclassid == refclassId && depform->deptype == deptype)
     392                 :             :         {
     393                 :        1501 :             CatalogTupleDelete(depRel, &tup->t_self);
     394                 :        1501 :             count++;
     395                 :             :         }
     396                 :             :     }
     397                 :             : 
     398                 :        9543 :     systable_endscan(scan);
     399                 :             : 
     400                 :        9543 :     table_close(depRel, RowExclusiveLock);
     401                 :             : 
     402                 :        9543 :     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                 :          67 : deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype,
     412                 :             :                                    Oid refclassId, Oid refobjectId)
     413                 :             : {
     414                 :          67 :     long        count = 0;
     415                 :             :     Relation    depRel;
     416                 :             :     ScanKeyData key[2];
     417                 :             :     SysScanDesc scan;
     418                 :             :     HeapTuple   tup;
     419                 :             : 
     420                 :          67 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     421                 :             : 
     422                 :          67 :     ScanKeyInit(&key[0],
     423                 :             :                 Anum_pg_depend_classid,
     424                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     425                 :             :                 ObjectIdGetDatum(classId));
     426                 :          67 :     ScanKeyInit(&key[1],
     427                 :             :                 Anum_pg_depend_objid,
     428                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     429                 :             :                 ObjectIdGetDatum(objectId));
     430                 :             : 
     431                 :          67 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     432                 :             :                               NULL, 2, key);
     433                 :             : 
     434         [ +  + ]:         335 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     435                 :             :     {
     436                 :         268 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     437                 :             : 
     438         [ +  + ]:         268 :         if (depform->refclassid == refclassId &&
     439         [ +  + ]:          68 :             depform->refobjid == refobjectId &&
     440         [ +  - ]:          67 :             depform->deptype == deptype)
     441                 :             :         {
     442                 :          67 :             CatalogTupleDelete(depRel, &tup->t_self);
     443                 :          67 :             count++;
     444                 :             :         }
     445                 :             :     }
     446                 :             : 
     447                 :          67 :     systable_endscan(scan);
     448                 :             : 
     449                 :          67 :     table_close(depRel, RowExclusiveLock);
     450                 :             : 
     451                 :          67 :     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                 :         666 : changeDependenciesOf(Oid classId, Oid oldObjectId,
     586                 :             :                      Oid newObjectId)
     587                 :             : {
     588                 :         666 :     long        count = 0;
     589                 :             :     Relation    depRel;
     590                 :             :     ScanKeyData key[2];
     591                 :             :     SysScanDesc scan;
     592                 :             :     HeapTuple   tup;
     593                 :             : 
     594                 :         666 :     depRel = table_open(DependRelationId, RowExclusiveLock);
     595                 :             : 
     596                 :         666 :     ScanKeyInit(&key[0],
     597                 :             :                 Anum_pg_depend_classid,
     598                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     599                 :             :                 ObjectIdGetDatum(classId));
     600                 :         666 :     ScanKeyInit(&key[1],
     601                 :             :                 Anum_pg_depend_objid,
     602                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     603                 :             :                 ObjectIdGetDatum(oldObjectId));
     604                 :             : 
     605                 :         666 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     606                 :             :                               NULL, 2, key);
     607                 :             : 
     608         [ +  + ]:        1860 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     609                 :             :     {
     610                 :             :         Form_pg_depend depform;
     611                 :             : 
     612                 :             :         /* make a modifiable copy */
     613                 :        1194 :         tup = heap_copytuple(tup);
     614                 :        1194 :         depform = (Form_pg_depend) GETSTRUCT(tup);
     615                 :             : 
     616                 :        1194 :         depform->objid = newObjectId;
     617                 :             : 
     618                 :        1194 :         CatalogTupleUpdate(depRel, &tup->t_self, tup);
     619                 :             : 
     620                 :        1194 :         heap_freetuple(tup);
     621                 :             : 
     622                 :        1194 :         count++;
     623                 :             :     }
     624                 :             : 
     625                 :         666 :     systable_endscan(scan);
     626                 :             : 
     627                 :         666 :     table_close(depRel, RowExclusiveLock);
     628                 :             : 
     629                 :         666 :     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                 :         666 : changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
     642                 :             :                      Oid newRefObjectId)
     643                 :             : {
     644                 :         666 :     long        count = 0;
     645                 :             :     Relation    depRel;
     646                 :             :     ScanKeyData key[2];
     647                 :             :     SysScanDesc scan;
     648                 :             :     HeapTuple   tup;
     649                 :             :     ObjectAddress objAddr;
     650                 :             :     bool        newIsPinned;
     651                 :             : 
     652                 :         666 :     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                 :         666 :     objAddr.classId = refClassId;
     661                 :         666 :     objAddr.objectId = oldRefObjectId;
     662                 :         666 :     objAddr.objectSubId = 0;
     663                 :             : 
     664         [ -  + ]:         666 :     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                 :         666 :     objAddr.objectId = newRefObjectId;
     675                 :             : 
     676                 :         666 :     newIsPinned = isObjectPinned(&objAddr);
     677                 :             : 
     678                 :             :     /* Now search for dependency records */
     679                 :         666 :     ScanKeyInit(&key[0],
     680                 :             :                 Anum_pg_depend_refclassid,
     681                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     682                 :             :                 ObjectIdGetDatum(refClassId));
     683                 :         666 :     ScanKeyInit(&key[1],
     684                 :             :                 Anum_pg_depend_refobjid,
     685                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     686                 :             :                 ObjectIdGetDatum(oldRefObjectId));
     687                 :             : 
     688                 :         666 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
     689                 :             :                               NULL, 2, key);
     690                 :             : 
     691         [ +  + ]:         677 :     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                 :         666 :     systable_endscan(scan);
     714                 :             : 
     715                 :         666 :     table_close(depRel, RowExclusiveLock);
     716                 :             : 
     717                 :         666 :     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                 :     1446285 : isObjectPinned(const ObjectAddress *object)
     730                 :             : {
     731                 :     1446285 :     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                 :      402774 : 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         [ +  + ]:      402774 :     if (classId != RelationRelationId)
     761                 :             :     {
     762                 :             :         LOCKTAG     tag;
     763                 :             :         SysCacheIdentifier cache;
     764                 :             :         Relation    rel;
     765                 :             :         SysScanDesc scan;
     766                 :             :         ScanKeyData skey;
     767                 :             :         HeapTuple   tuple;
     768                 :             : 
     769                 :      214419 :         SET_LOCKTAG_OBJECT(tag,
     770                 :             :                            MyDatabaseId,
     771                 :             :                            classId,
     772                 :             :                            objectId,
     773                 :             :                            0);
     774                 :             : 
     775         [ +  + ]:      214419 :         if (LockHeldByMe(&tag, AccessShareLock, true))
     776                 :      159507 :             return;
     777                 :             : 
     778                 :             :         /* Assume we should lock the whole object not a sub-object */
     779                 :       98556 :         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                 :       98556 :         cache = get_object_catcache_oid(classId);
     786         [ +  + ]:       98556 :         if (cache != SYSCACHEID_INVALID)
     787                 :             :         {
     788         [ +  + ]:       95952 :             if (SearchSysCacheExists1(cache, ObjectIdGetDatum(objectId)))
     789                 :       43644 :                 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                 :       54912 :         rel = table_open(classId, AccessShareLock);
     799                 :             : 
     800                 :      109824 :         ScanKeyInit(&skey,
     801                 :       54912 :                     get_object_attnum_oid(classId),
     802                 :             :                     BTEqualStrategyNumber, F_OIDEQ,
     803                 :             :                     ObjectIdGetDatum(objectId));
     804                 :             : 
     805                 :       54912 :         scan = systable_beginscan(rel, get_object_oid_index(classId),
     806                 :             :                                   true, SnapshotSelf, 1, &skey);
     807                 :             : 
     808                 :       54912 :         tuple = systable_getnext(scan);
     809         [ +  + ]:       54912 :         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                 :       54904 :         systable_endscan(scan);
     816                 :       54904 :         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         [ +  + ]:      188355 :         if (CheckRelationOidLockedByMe(objectId, AccessShareLock, true))
     837                 :      186267 :             return;
     838                 :        2088 :         LockRelationOid(objectId, AccessShareLock);
     839                 :             : 
     840         [ +  - ]:        2088 :         if (SearchSysCacheExists1(RELOID, ObjectIdGetDatum(objectId)))
     841                 :        2088 :             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                 :         678 : getExtensionOfObject(Oid classId, Oid objectId)
     866                 :             : {
     867                 :         678 :     Oid         result = InvalidOid;
     868                 :             :     Relation    depRel;
     869                 :             :     ScanKeyData key[2];
     870                 :             :     SysScanDesc scan;
     871                 :             :     HeapTuple   tup;
     872                 :             : 
     873                 :         678 :     depRel = table_open(DependRelationId, AccessShareLock);
     874                 :             : 
     875                 :         678 :     ScanKeyInit(&key[0],
     876                 :             :                 Anum_pg_depend_classid,
     877                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     878                 :             :                 ObjectIdGetDatum(classId));
     879                 :         678 :     ScanKeyInit(&key[1],
     880                 :             :                 Anum_pg_depend_objid,
     881                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
     882                 :             :                 ObjectIdGetDatum(objectId));
     883                 :             : 
     884                 :         678 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
     885                 :             :                               NULL, 2, key);
     886                 :             : 
     887         [ +  + ]:        1591 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
     888                 :             :     {
     889                 :        1512 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
     890                 :             : 
     891         [ +  + ]:        1512 :         if (depform->refclassid == ExtensionRelationId &&
     892         [ +  - ]:         599 :             depform->deptype == DEPENDENCY_EXTENSION)
     893                 :             :         {
     894                 :         599 :             result = depform->refobjid;
     895                 :         599 :             break;              /* no need to keep scanning */
     896                 :             :         }
     897                 :             :     }
     898                 :             : 
     899                 :         678 :     systable_endscan(scan);
     900                 :             : 
     901                 :         678 :     table_close(depRel, AccessShareLock);
     902                 :             : 
     903                 :         678 :     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                 :         555 : sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
    1033                 :             : {
    1034                 :         555 :     bool        ret = false;
    1035                 :             :     Relation    depRel;
    1036                 :             :     ScanKeyData key[2];
    1037                 :             :     SysScanDesc scan;
    1038                 :             :     HeapTuple   tup;
    1039                 :             : 
    1040                 :         555 :     depRel = table_open(DependRelationId, AccessShareLock);
    1041                 :             : 
    1042                 :         555 :     ScanKeyInit(&key[0],
    1043                 :             :                 Anum_pg_depend_classid,
    1044                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
    1045                 :             :                 ObjectIdGetDatum(RelationRelationId));
    1046                 :         555 :     ScanKeyInit(&key[1],
    1047                 :             :                 Anum_pg_depend_objid,
    1048                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
    1049                 :             :                 ObjectIdGetDatum(seqId));
    1050                 :             : 
    1051                 :         555 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
    1052                 :             :                               NULL, 2, key);
    1053                 :             : 
    1054         [ +  + ]:        1111 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
    1055                 :             :     {
    1056                 :         564 :         Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
    1057                 :             : 
    1058         [ +  + ]:         564 :         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                 :         555 :     systable_endscan(scan);
    1069                 :             : 
    1070                 :         555 :     table_close(depRel, AccessShareLock);
    1071                 :             : 
    1072                 :         555 :     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                 :         428 :         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         [ +  + ]:        1658 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
    1109                 :             :     {
    1110                 :        1163 :         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         [ +  + ]:        1163 :         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                 :          67 : getOwnedSequences(Oid relid)
    1141                 :             : {
    1142                 :          67 :     return getOwnedSequences_internal(relid, 0, 0);
    1143                 :             : }
    1144                 :             : 
    1145                 :             : /*
    1146                 :             :  * Get owned identity sequence, error if not exactly one.
    1147                 :             :  */
    1148                 :             : Oid
    1149                 :         428 : getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
    1150                 :             : {
    1151                 :         428 :     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         [ +  + ]:         428 :     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                 :         428 :     seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
    1172         [ -  + ]:         428 :     if (list_length(seqlist) > 1)
    1173         [ #  # ]:           0 :         elog(ERROR, "more than one owned sequence found");
    1174         [ +  + ]:         428 :     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                 :         420 :     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                 :        8859 : get_index_constraint(Oid indexId)
    1193                 :             : {
    1194                 :        8859 :     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                 :        8859 :     depRel = table_open(DependRelationId, AccessShareLock);
    1202                 :             : 
    1203                 :        8859 :     ScanKeyInit(&key[0],
    1204                 :             :                 Anum_pg_depend_classid,
    1205                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
    1206                 :             :                 ObjectIdGetDatum(RelationRelationId));
    1207                 :        8859 :     ScanKeyInit(&key[1],
    1208                 :             :                 Anum_pg_depend_objid,
    1209                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
    1210                 :             :                 ObjectIdGetDatum(indexId));
    1211                 :        8859 :     ScanKeyInit(&key[2],
    1212                 :             :                 Anum_pg_depend_objsubid,
    1213                 :             :                 BTEqualStrategyNumber, F_INT4EQ,
    1214                 :             :                 Int32GetDatum(0));
    1215                 :             : 
    1216                 :        8859 :     scan = systable_beginscan(depRel, DependDependerIndexId, true,
    1217                 :             :                               NULL, 3, key);
    1218                 :             : 
    1219         [ +  + ]:       10843 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
    1220                 :             :     {
    1221                 :        3183 :         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         [ +  + ]:        3183 :         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                 :        8859 :     systable_endscan(scan);
    1237                 :        8859 :     table_close(depRel, AccessShareLock);
    1238                 :             : 
    1239                 :        8859 :     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                 :         333 : get_index_ref_constraints(Oid indexId)
    1249                 :             : {
    1250                 :         333 :     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                 :         333 :     depRel = table_open(DependRelationId, AccessShareLock);
    1258                 :             : 
    1259                 :         333 :     ScanKeyInit(&key[0],
    1260                 :             :                 Anum_pg_depend_refclassid,
    1261                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
    1262                 :             :                 ObjectIdGetDatum(RelationRelationId));
    1263                 :         333 :     ScanKeyInit(&key[1],
    1264                 :             :                 Anum_pg_depend_refobjid,
    1265                 :             :                 BTEqualStrategyNumber, F_OIDEQ,
    1266                 :             :                 ObjectIdGetDatum(indexId));
    1267                 :         333 :     ScanKeyInit(&key[2],
    1268                 :             :                 Anum_pg_depend_refobjsubid,
    1269                 :             :                 BTEqualStrategyNumber, F_INT4EQ,
    1270                 :             :                 Int32GetDatum(0));
    1271                 :             : 
    1272                 :         333 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
    1273                 :             :                               NULL, 3, key);
    1274                 :             : 
    1275         [ +  + ]:         344 :     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                 :         333 :     systable_endscan(scan);
    1292                 :         333 :     table_close(depRel, AccessShareLock);
    1293                 :             : 
    1294                 :         333 :     return result;
    1295                 :             : }
        

Generated by: LCOV version 2.0-1