LCOV - code coverage report
Current view: top level - src/backend/utils/cache - syscache.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 93.5 % 185 173
Test Date: 2026-04-07 14:16:30 Functions: 100.0 % 27 27
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * syscache.c
       4              :  *    System cache management routines
       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/utils/cache/syscache.c
      12              :  *
      13              :  * NOTES
      14              :  *    These routines allow the parser/planner/executor to perform
      15              :  *    rapid lookups on the contents of the system catalogs.
      16              :  *
      17              :  *    see utils/syscache.h for a list of the cache IDs
      18              :  *
      19              :  *-------------------------------------------------------------------------
      20              :  */
      21              : #include "postgres.h"
      22              : 
      23              : #include "access/htup_details.h"
      24              : #include "catalog/pg_db_role_setting_d.h"
      25              : #include "catalog/pg_depend_d.h"
      26              : #include "catalog/pg_description_d.h"
      27              : #include "catalog/pg_seclabel_d.h"
      28              : #include "catalog/pg_shdepend_d.h"
      29              : #include "catalog/pg_shdescription_d.h"
      30              : #include "catalog/pg_shseclabel_d.h"
      31              : #include "common/int.h"
      32              : #include "lib/qunique.h"
      33              : #include "miscadmin.h"
      34              : #include "storage/lmgr.h"
      35              : #include "storage/lock.h"
      36              : #include "utils/catcache.h"
      37              : #include "utils/inval.h"
      38              : #include "utils/lsyscache.h"
      39              : #include "utils/rel.h"
      40              : #include "utils/syscache.h"
      41              : 
      42              : /*---------------------------------------------------------------------------
      43              : 
      44              :     Adding system caches:
      45              : 
      46              :     There must be a unique index underlying each syscache (ie, an index
      47              :     whose key is the same as that of the cache).  If there is not one
      48              :     already, add the definition for it to include/catalog/pg_*.h using
      49              :     DECLARE_UNIQUE_INDEX.
      50              :     (Adding an index requires a catversion.h update, while simply
      51              :     adding/deleting caches only requires a recompile.)
      52              : 
      53              :     Add a MAKE_SYSCACHE call to the same pg_*.h file specifying the name of
      54              :     your cache, the underlying index, and the initial number of hash buckets.
      55              : 
      56              :     The number of hash buckets must be a power of 2.  It's reasonable to
      57              :     set this to the number of entries that might be in the particular cache
      58              :     in a medium-size database.
      59              : 
      60              :     Finally, any place your relation gets heap_insert() or
      61              :     heap_update() calls, use CatalogTupleInsert() or CatalogTupleUpdate()
      62              :     instead, which also update indexes.  The heap_* calls do not do that.
      63              : 
      64              : *---------------------------------------------------------------------------
      65              : */
      66              : 
      67              : /*
      68              :  *      struct cachedesc: information defining a single syscache
      69              :  */
      70              : struct cachedesc
      71              : {
      72              :     Oid         reloid;         /* OID of the relation being cached */
      73              :     Oid         indoid;         /* OID of index relation for this cache */
      74              :     int         nkeys;          /* # of keys needed for cache lookup */
      75              :     int         key[4];         /* attribute numbers of key attrs */
      76              :     int         nbuckets;       /* number of hash buckets for this cache */
      77              : };
      78              : 
      79              : /* Macro to provide nkeys and key array with convenient syntax. */
      80              : #define KEY(...) VA_ARGS_NARGS(__VA_ARGS__), { __VA_ARGS__ }
      81              : 
      82              : #include "catalog/syscache_info.h"
      83              : 
      84              : StaticAssertDecl(lengthof(cacheinfo) == SysCacheSize,
      85              :                  "SysCacheSize does not match syscache.c's array");
      86              : 
      87              : static CatCache *SysCache[SysCacheSize];
      88              : 
      89              : static bool CacheInitialized = false;
      90              : 
      91              : /* Sorted array of OIDs of tables that have caches on them */
      92              : static Oid  SysCacheRelationOid[SysCacheSize];
      93              : static int  SysCacheRelationOidSize;
      94              : 
      95              : /* Sorted array of OIDs of tables and indexes used by caches */
      96              : static Oid  SysCacheSupportingRelOid[SysCacheSize * 2];
      97              : static int  SysCacheSupportingRelOidSize;
      98              : 
      99              : static int  oid_compare(const void *a, const void *b);
     100              : 
     101              : 
     102              : /*
     103              :  * InitCatalogCache - initialize the caches
     104              :  *
     105              :  * Note that no database access is done here; we only allocate memory
     106              :  * and initialize the cache structure.  Interrogation of the database
     107              :  * to complete initialization of a cache happens upon first use
     108              :  * of that cache.
     109              :  */
     110              : void
     111        19841 : InitCatalogCache(void)
     112              : {
     113              :     SysCacheIdentifier cacheId;
     114              : 
     115              :     Assert(!CacheInitialized);
     116              : 
     117        19841 :     SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0;
     118              : 
     119      1865054 :     for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
     120              :     {
     121              :         /*
     122              :          * Assert that every enumeration value defined in syscache.h has been
     123              :          * populated in the cacheinfo array.
     124              :          */
     125              :         Assert(OidIsValid(cacheinfo[cacheId].reloid));
     126              :         Assert(OidIsValid(cacheinfo[cacheId].indoid));
     127              :         /* .nbuckets and .key[] are checked by InitCatCache() */
     128              : 
     129      3690426 :         SysCache[cacheId] = InitCatCache(cacheId,
     130      1845213 :                                          cacheinfo[cacheId].reloid,
     131      1845213 :                                          cacheinfo[cacheId].indoid,
     132      1845213 :                                          cacheinfo[cacheId].nkeys,
     133      1845213 :                                          cacheinfo[cacheId].key,
     134      1845213 :                                          cacheinfo[cacheId].nbuckets);
     135      1845213 :         if (!SysCache[cacheId])
     136            0 :             elog(ERROR, "could not initialize cache %u (%d)",
     137              :                  cacheinfo[cacheId].reloid, cacheId);
     138              :         /* Accumulate data for OID lists, too */
     139      1845213 :         SysCacheRelationOid[SysCacheRelationOidSize++] =
     140      1845213 :             cacheinfo[cacheId].reloid;
     141      1845213 :         SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
     142      1845213 :             cacheinfo[cacheId].reloid;
     143      1845213 :         SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
     144      1845213 :             cacheinfo[cacheId].indoid;
     145              :         /* see comments for RelationInvalidatesSnapshotsOnly */
     146              :         Assert(!RelationInvalidatesSnapshotsOnly(cacheinfo[cacheId].reloid));
     147              :     }
     148              : 
     149              :     Assert(SysCacheRelationOidSize <= lengthof(SysCacheRelationOid));
     150              :     Assert(SysCacheSupportingRelOidSize <= lengthof(SysCacheSupportingRelOid));
     151              : 
     152              :     /* Sort and de-dup OID arrays, so we can use binary search. */
     153        19841 :     qsort(SysCacheRelationOid, SysCacheRelationOidSize,
     154              :           sizeof(Oid), oid_compare);
     155        19841 :     SysCacheRelationOidSize =
     156        19841 :         qunique(SysCacheRelationOid, SysCacheRelationOidSize, sizeof(Oid),
     157              :                 oid_compare);
     158              : 
     159        19841 :     qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
     160              :           sizeof(Oid), oid_compare);
     161        19841 :     SysCacheSupportingRelOidSize =
     162        19841 :         qunique(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
     163              :                 sizeof(Oid), oid_compare);
     164              : 
     165        19841 :     CacheInitialized = true;
     166        19841 : }
     167              : 
     168              : /*
     169              :  * InitCatalogCachePhase2 - finish initializing the caches
     170              :  *
     171              :  * Finish initializing all the caches, including necessary database
     172              :  * access.
     173              :  *
     174              :  * This is *not* essential; normally we allow syscaches to be initialized
     175              :  * on first use.  However, it is useful as a mechanism to preload the
     176              :  * relcache with entries for the most-commonly-used system catalogs.
     177              :  * Therefore, we invoke this routine when we need to write a new relcache
     178              :  * init file.
     179              :  */
     180              : void
     181         2040 : InitCatalogCachePhase2(void)
     182              : {
     183              :     SysCacheIdentifier cacheId;
     184              : 
     185              :     Assert(CacheInitialized);
     186              : 
     187       191760 :     for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
     188       189720 :         InitCatCachePhase2(SysCache[cacheId], true);
     189         2040 : }
     190              : 
     191              : 
     192              : /*
     193              :  * SearchSysCache
     194              :  *
     195              :  *  A layer on top of SearchCatCache that does the initialization and
     196              :  *  key-setting for you.
     197              :  *
     198              :  *  Returns the cache copy of the tuple if one is found, NULL if not.
     199              :  *  The tuple is the 'cache' copy and must NOT be modified!
     200              :  *
     201              :  *  When the caller is done using the tuple, call ReleaseSysCache()
     202              :  *  to release the reference count grabbed by SearchSysCache().  If this
     203              :  *  is not done, the tuple will remain locked in cache until end of
     204              :  *  transaction, which is tolerable but not desirable.
     205              :  *
     206              :  *  CAUTION: The tuple that is returned must NOT be freed by the caller!
     207              :  */
     208              : HeapTuple
     209      3823391 : SearchSysCache(SysCacheIdentifier cacheId,
     210              :                Datum key1,
     211              :                Datum key2,
     212              :                Datum key3,
     213              :                Datum key4)
     214              : {
     215              :     Assert(cacheId >= 0 && cacheId < SysCacheSize && SysCache[cacheId]);
     216              : 
     217      3823391 :     return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
     218              : }
     219              : 
     220              : HeapTuple
     221     50720048 : SearchSysCache1(SysCacheIdentifier cacheId,
     222              :                 Datum key1)
     223              : {
     224              :     Assert(cacheId >= 0 && cacheId < SysCacheSize && SysCache[cacheId]);
     225              :     Assert(SysCache[cacheId]->cc_nkeys == 1);
     226              : 
     227     50720048 :     return SearchCatCache1(SysCache[cacheId], key1);
     228              : }
     229              : 
     230              : HeapTuple
     231      4306497 : SearchSysCache2(SysCacheIdentifier cacheId,
     232              :                 Datum key1, Datum key2)
     233              : {
     234              :     Assert(cacheId >= 0 && cacheId < SysCacheSize && SysCache[cacheId]);
     235              :     Assert(SysCache[cacheId]->cc_nkeys == 2);
     236              : 
     237      4306497 :     return SearchCatCache2(SysCache[cacheId], key1, key2);
     238              : }
     239              : 
     240              : HeapTuple
     241      4622035 : SearchSysCache3(SysCacheIdentifier cacheId,
     242              :                 Datum key1, Datum key2, Datum key3)
     243              : {
     244              :     Assert(cacheId >= 0 && cacheId < SysCacheSize && SysCache[cacheId]);
     245              :     Assert(SysCache[cacheId]->cc_nkeys == 3);
     246              : 
     247      4622035 :     return SearchCatCache3(SysCache[cacheId], key1, key2, key3);
     248              : }
     249              : 
     250              : HeapTuple
     251      3505618 : SearchSysCache4(SysCacheIdentifier cacheId,
     252              :                 Datum key1, Datum key2, Datum key3, Datum key4)
     253              : {
     254              :     Assert(cacheId >= 0 && cacheId < SysCacheSize && SysCache[cacheId]);
     255              :     Assert(SysCache[cacheId]->cc_nkeys == 4);
     256              : 
     257      3505618 :     return SearchCatCache4(SysCache[cacheId], key1, key2, key3, key4);
     258              : }
     259              : 
     260              : /*
     261              :  * ReleaseSysCache
     262              :  *      Release previously grabbed reference count on a tuple
     263              :  */
     264              : void
     265     62440925 : ReleaseSysCache(HeapTuple tuple)
     266              : {
     267     62440925 :     ReleaseCatCache(tuple);
     268     62440925 : }
     269              : 
     270              : /*
     271              :  * SearchSysCacheLocked1
     272              :  *
     273              :  * Combine SearchSysCache1() with acquiring a LOCKTAG_TUPLE at mode
     274              :  * InplaceUpdateTupleLock.  This is a tool for complying with the
     275              :  * README.tuplock section "Locking to write inplace-updated tables".  After
     276              :  * the caller's heap_update(), it should UnlockTuple(InplaceUpdateTupleLock)
     277              :  * and ReleaseSysCache().
     278              :  *
     279              :  * The returned tuple may be the subject of an uncommitted update, so this
     280              :  * doesn't prevent the "tuple concurrently updated" error.
     281              :  */
     282              : HeapTuple
     283        24677 : SearchSysCacheLocked1(SysCacheIdentifier cacheId,
     284              :                       Datum key1)
     285              : {
     286        24677 :     CatCache   *cache = SysCache[cacheId];
     287              :     ItemPointerData tid;
     288              :     LOCKTAG     tag;
     289              : 
     290              :     /*----------
     291              :      * Since inplace updates may happen just before our LockTuple(), we must
     292              :      * return content acquired after LockTuple() of the TID we return.  If we
     293              :      * just fetched twice instead of looping, the following sequence would
     294              :      * defeat our locking:
     295              :      *
     296              :      * GRANT:   SearchSysCache1() = TID (1,5)
     297              :      * GRANT:   LockTuple(pg_class, (1,5))
     298              :      * [no more inplace update of (1,5) until we release the lock]
     299              :      * CLUSTER: SearchSysCache1() = TID (1,5)
     300              :      * CLUSTER: heap_update() = TID (1,8)
     301              :      * CLUSTER: COMMIT
     302              :      * GRANT:   SearchSysCache1() = TID (1,8)
     303              :      * GRANT:   return (1,8) from SearchSysCacheLocked1()
     304              :      * VACUUM:  SearchSysCache1() = TID (1,8)
     305              :      * VACUUM:  LockTuple(pg_class, (1,8))  # two TIDs now locked for one rel
     306              :      * VACUUM:  inplace update
     307              :      * GRANT:   heap_update() = (1,9)  # lose inplace update
     308              :      *
     309              :      * In the happy case, this takes two fetches, one to determine the TID to
     310              :      * lock and another to get the content and confirm the TID didn't change.
     311              :      *
     312              :      * This is valid even if the row gets updated to a new TID, the old TID
     313              :      * becomes LP_UNUSED, and the row gets updated back to its old TID.  We'd
     314              :      * still hold the right LOCKTAG_TUPLE and a copy of the row captured after
     315              :      * the LOCKTAG_TUPLE.
     316              :      */
     317        24677 :     ItemPointerSetInvalid(&tid);
     318              :     for (;;)
     319        24678 :     {
     320              :         HeapTuple   tuple;
     321        49355 :         LOCKMODE    lockmode = InplaceUpdateTupleLock;
     322              : 
     323        49355 :         tuple = SearchSysCache1(cacheId, key1);
     324        49355 :         if (ItemPointerIsValid(&tid))
     325              :         {
     326        24678 :             if (!HeapTupleIsValid(tuple))
     327              :             {
     328            1 :                 LockRelease(&tag, lockmode, false);
     329            1 :                 return tuple;
     330              :             }
     331        24677 :             if (ItemPointerEquals(&tid, &tuple->t_self))
     332        24676 :                 return tuple;
     333            1 :             LockRelease(&tag, lockmode, false);
     334              :         }
     335        24677 :         else if (!HeapTupleIsValid(tuple))
     336            0 :             return tuple;
     337              : 
     338        24678 :         tid = tuple->t_self;
     339        24678 :         ReleaseSysCache(tuple);
     340              : 
     341              :         /*
     342              :          * Do like LockTuple(rel, &tid, lockmode).  While cc_relisshared won't
     343              :          * change from one iteration to another, it may have been a temporary
     344              :          * "false" until our first SearchSysCache1().
     345              :          */
     346        24678 :         SET_LOCKTAG_TUPLE(tag,
     347              :                           cache->cc_relisshared ? InvalidOid : MyDatabaseId,
     348              :                           cache->cc_reloid,
     349              :                           ItemPointerGetBlockNumber(&tid),
     350              :                           ItemPointerGetOffsetNumber(&tid));
     351        24678 :         (void) LockAcquire(&tag, lockmode, false, false);
     352              : 
     353              :         /*
     354              :          * If an inplace update just finished, ensure we process the syscache
     355              :          * inval.
     356              :          *
     357              :          * If a heap_update() call just released its LOCKTAG_TUPLE, we'll
     358              :          * probably find the old tuple and reach "tuple concurrently updated".
     359              :          * If that heap_update() aborts, our LOCKTAG_TUPLE blocks inplace
     360              :          * updates while our caller works.
     361              :          */
     362        24678 :         AcceptInvalidationMessages();
     363              :     }
     364              : }
     365              : 
     366              : /*
     367              :  * SearchSysCacheCopy
     368              :  *
     369              :  * A convenience routine that does SearchSysCache and (if successful)
     370              :  * returns a modifiable copy of the syscache entry.  The original
     371              :  * syscache entry is released before returning.  The caller should
     372              :  * heap_freetuple() the result when done with it.
     373              :  */
     374              : HeapTuple
     375       372463 : SearchSysCacheCopy(SysCacheIdentifier cacheId,
     376              :                    Datum key1,
     377              :                    Datum key2,
     378              :                    Datum key3,
     379              :                    Datum key4)
     380              : {
     381              :     HeapTuple   tuple,
     382              :                 newtuple;
     383              : 
     384       372463 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     385       372463 :     if (!HeapTupleIsValid(tuple))
     386        94876 :         return tuple;
     387       277587 :     newtuple = heap_copytuple(tuple);
     388       277587 :     ReleaseSysCache(tuple);
     389       277587 :     return newtuple;
     390              : }
     391              : 
     392              : /*
     393              :  * SearchSysCacheLockedCopy1
     394              :  *
     395              :  * Meld SearchSysCacheLocked1 with SearchSysCacheCopy().  After the
     396              :  * caller's heap_update(), it should UnlockTuple(InplaceUpdateTupleLock) and
     397              :  * heap_freetuple().
     398              :  */
     399              : HeapTuple
     400        11211 : SearchSysCacheLockedCopy1(SysCacheIdentifier cacheId,
     401              :                           Datum key1)
     402              : {
     403              :     HeapTuple   tuple,
     404              :                 newtuple;
     405              : 
     406        11211 :     tuple = SearchSysCacheLocked1(cacheId, key1);
     407        11211 :     if (!HeapTupleIsValid(tuple))
     408            0 :         return tuple;
     409        11211 :     newtuple = heap_copytuple(tuple);
     410        11211 :     ReleaseSysCache(tuple);
     411        11211 :     return newtuple;
     412              : }
     413              : 
     414              : /*
     415              :  * SearchSysCacheExists
     416              :  *
     417              :  * A convenience routine that just probes to see if a tuple can be found.
     418              :  * No lock is retained on the syscache entry.
     419              :  */
     420              : bool
     421      1030669 : SearchSysCacheExists(SysCacheIdentifier cacheId,
     422              :                      Datum key1,
     423              :                      Datum key2,
     424              :                      Datum key3,
     425              :                      Datum key4)
     426              : {
     427              :     HeapTuple   tuple;
     428              : 
     429      1030669 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     430      1030669 :     if (!HeapTupleIsValid(tuple))
     431       162510 :         return false;
     432       868159 :     ReleaseSysCache(tuple);
     433       868159 :     return true;
     434              : }
     435              : 
     436              : /*
     437              :  * GetSysCacheOid
     438              :  *
     439              :  * A convenience routine that does SearchSysCache and returns the OID in the
     440              :  * oidcol column of the found tuple, or InvalidOid if no tuple could be found.
     441              :  * No lock is retained on the syscache entry.
     442              :  */
     443              : Oid
     444      2420259 : GetSysCacheOid(SysCacheIdentifier cacheId,
     445              :                AttrNumber oidcol,
     446              :                Datum key1,
     447              :                Datum key2,
     448              :                Datum key3,
     449              :                Datum key4)
     450              : {
     451              :     HeapTuple   tuple;
     452              :     bool        isNull;
     453              :     Oid         result;
     454              : 
     455      2420259 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     456      2420259 :     if (!HeapTupleIsValid(tuple))
     457       951680 :         return InvalidOid;
     458      1468579 :     result = DatumGetObjectId(heap_getattr(tuple, oidcol,
     459      1468579 :                                            SysCache[cacheId]->cc_tupdesc,
     460              :                                            &isNull));
     461              :     Assert(!isNull);            /* columns used as oids should never be NULL */
     462      1468579 :     ReleaseSysCache(tuple);
     463      1468579 :     return result;
     464              : }
     465              : 
     466              : 
     467              : /*
     468              :  * SearchSysCacheAttName
     469              :  *
     470              :  * This routine is equivalent to SearchSysCache on the ATTNAME cache,
     471              :  * except that it will return NULL if the found attribute is marked
     472              :  * attisdropped.  This is convenient for callers that want to act as
     473              :  * though dropped attributes don't exist.
     474              :  */
     475              : HeapTuple
     476        78482 : SearchSysCacheAttName(Oid relid, const char *attname)
     477              : {
     478              :     HeapTuple   tuple;
     479              : 
     480        78482 :     tuple = SearchSysCache2(ATTNAME,
     481              :                             ObjectIdGetDatum(relid),
     482              :                             CStringGetDatum(attname));
     483        78482 :     if (!HeapTupleIsValid(tuple))
     484          713 :         return NULL;
     485        77769 :     if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
     486              :     {
     487           56 :         ReleaseSysCache(tuple);
     488           56 :         return NULL;
     489              :     }
     490        77713 :     return tuple;
     491              : }
     492              : 
     493              : /*
     494              :  * SearchSysCacheCopyAttName
     495              :  *
     496              :  * As above, an attisdropped-aware version of SearchSysCacheCopy.
     497              :  */
     498              : HeapTuple
     499         7622 : SearchSysCacheCopyAttName(Oid relid, const char *attname)
     500              : {
     501              :     HeapTuple   tuple,
     502              :                 newtuple;
     503              : 
     504         7622 :     tuple = SearchSysCacheAttName(relid, attname);
     505         7622 :     if (!HeapTupleIsValid(tuple))
     506          518 :         return tuple;
     507         7104 :     newtuple = heap_copytuple(tuple);
     508         7104 :     ReleaseSysCache(tuple);
     509         7104 :     return newtuple;
     510              : }
     511              : 
     512              : /*
     513              :  * SearchSysCacheExistsAttName
     514              :  *
     515              :  * As above, an attisdropped-aware version of SearchSysCacheExists.
     516              :  */
     517              : bool
     518         1666 : SearchSysCacheExistsAttName(Oid relid, const char *attname)
     519              : {
     520              :     HeapTuple   tuple;
     521              : 
     522         1666 :     tuple = SearchSysCacheAttName(relid, attname);
     523         1666 :     if (!HeapTupleIsValid(tuple))
     524           36 :         return false;
     525         1630 :     ReleaseSysCache(tuple);
     526         1630 :     return true;
     527              : }
     528              : 
     529              : 
     530              : /*
     531              :  * SearchSysCacheAttNum
     532              :  *
     533              :  * This routine is equivalent to SearchSysCache on the ATTNUM cache,
     534              :  * except that it will return NULL if the found attribute is marked
     535              :  * attisdropped.  This is convenient for callers that want to act as
     536              :  * though dropped attributes don't exist.
     537              :  */
     538              : HeapTuple
     539         1263 : SearchSysCacheAttNum(Oid relid, int16 attnum)
     540              : {
     541              :     HeapTuple   tuple;
     542              : 
     543         1263 :     tuple = SearchSysCache2(ATTNUM,
     544              :                             ObjectIdGetDatum(relid),
     545              :                             Int16GetDatum(attnum));
     546         1263 :     if (!HeapTupleIsValid(tuple))
     547            8 :         return NULL;
     548         1255 :     if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
     549              :     {
     550            0 :         ReleaseSysCache(tuple);
     551            0 :         return NULL;
     552              :     }
     553         1255 :     return tuple;
     554              : }
     555              : 
     556              : /*
     557              :  * SearchSysCacheCopyAttNum
     558              :  *
     559              :  * As above, an attisdropped-aware version of SearchSysCacheCopy.
     560              :  */
     561              : HeapTuple
     562         1221 : SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
     563              : {
     564              :     HeapTuple   tuple,
     565              :                 newtuple;
     566              : 
     567         1221 :     tuple = SearchSysCacheAttNum(relid, attnum);
     568         1221 :     if (!HeapTupleIsValid(tuple))
     569            0 :         return NULL;
     570         1221 :     newtuple = heap_copytuple(tuple);
     571         1221 :     ReleaseSysCache(tuple);
     572         1221 :     return newtuple;
     573              : }
     574              : 
     575              : 
     576              : /*
     577              :  * SysCacheGetAttr
     578              :  *
     579              :  *      Given a tuple previously fetched by SearchSysCache(),
     580              :  *      extract a specific attribute.
     581              :  *
     582              :  * This is equivalent to using heap_getattr() on a tuple fetched
     583              :  * from a non-cached relation.  Usually, this is only used for attributes
     584              :  * that could be NULL or variable length; the fixed-size attributes in
     585              :  * a system table are accessed just by mapping the tuple onto the C struct
     586              :  * declarations from include/catalog/.
     587              :  *
     588              :  * As with heap_getattr(), if the attribute is of a pass-by-reference type
     589              :  * then a pointer into the tuple data area is returned --- the caller must
     590              :  * not modify or pfree the datum!
     591              :  *
     592              :  * Note: it is legal to use SysCacheGetAttr() with a cacheId referencing
     593              :  * a different cache for the same catalog the tuple was fetched from.
     594              :  */
     595              : Datum
     596      4816559 : SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup,
     597              :                 AttrNumber attributeNumber,
     598              :                 bool *isNull)
     599              : {
     600              :     /*
     601              :      * We just need to get the TupleDesc out of the cache entry, and then we
     602              :      * can apply heap_getattr().  Normally the cache control data is already
     603              :      * valid (because the caller recently fetched the tuple via this same
     604              :      * cache), but there are cases where we have to initialize the cache here.
     605              :      */
     606      4816559 :     if (cacheId < 0 || cacheId >= SysCacheSize || !SysCache[cacheId])
     607            0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     608      4816559 :     if (!SysCache[cacheId]->cc_tupdesc)
     609              :     {
     610        18819 :         InitCatCachePhase2(SysCache[cacheId], false);
     611              :         Assert(SysCache[cacheId]->cc_tupdesc);
     612              :     }
     613              : 
     614      9633118 :     return heap_getattr(tup, attributeNumber,
     615      4816559 :                         SysCache[cacheId]->cc_tupdesc,
     616              :                         isNull);
     617              : }
     618              : 
     619              : /*
     620              :  * SysCacheGetAttrNotNull
     621              :  *
     622              :  * As above, a version of SysCacheGetAttr which knows that the attr cannot
     623              :  * be NULL.
     624              :  */
     625              : Datum
     626      2868796 : SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup,
     627              :                        AttrNumber attributeNumber)
     628              : {
     629              :     bool        isnull;
     630              :     Datum       attr;
     631              : 
     632      2868796 :     attr = SysCacheGetAttr(cacheId, tup, attributeNumber, &isnull);
     633              : 
     634      2868796 :     if (isnull)
     635              :     {
     636            0 :         elog(ERROR,
     637              :              "unexpected null value in cached tuple for catalog %s column %s",
     638              :              get_rel_name(cacheinfo[cacheId].reloid),
     639              :              NameStr(TupleDescAttr(SysCache[cacheId]->cc_tupdesc, attributeNumber - 1)->attname));
     640              :     }
     641              : 
     642      2868796 :     return attr;
     643              : }
     644              : 
     645              : /*
     646              :  * GetSysCacheHashValue
     647              :  *
     648              :  * Get the hash value that would be used for a tuple in the specified cache
     649              :  * with the given search keys.
     650              :  *
     651              :  * The reason for exposing this as part of the API is that the hash value is
     652              :  * exposed in cache invalidation operations, so there are places outside the
     653              :  * catcache code that need to be able to compute the hash values.
     654              :  */
     655              : uint32
     656       773614 : GetSysCacheHashValue(SysCacheIdentifier cacheId,
     657              :                      Datum key1,
     658              :                      Datum key2,
     659              :                      Datum key3,
     660              :                      Datum key4)
     661              : {
     662       773614 :     if (cacheId < 0 || cacheId >= SysCacheSize || !SysCache[cacheId])
     663            0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     664              : 
     665       773614 :     return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4);
     666              : }
     667              : 
     668              : /*
     669              :  * List-search interface
     670              :  */
     671              : struct catclist *
     672      3013785 : SearchSysCacheList(SysCacheIdentifier cacheId, int nkeys,
     673              :                    Datum key1, Datum key2, Datum key3)
     674              : {
     675      3013785 :     if (cacheId < 0 || cacheId >= SysCacheSize || !SysCache[cacheId])
     676            0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     677              : 
     678      3013785 :     return SearchCatCacheList(SysCache[cacheId], nkeys,
     679              :                               key1, key2, key3);
     680              : }
     681              : 
     682              : /*
     683              :  * SysCacheInvalidate
     684              :  *
     685              :  *  Invalidate entries in the specified cache, given a hash value.
     686              :  *  See CatCacheInvalidate() for more info.
     687              :  *
     688              :  *  This routine is only quasi-public: it should only be used by inval.c.
     689              :  */
     690              : void
     691     15958649 : SysCacheInvalidate(SysCacheIdentifier cacheId, uint32 hashValue)
     692              : {
     693     15958649 :     if (cacheId < 0 || cacheId >= SysCacheSize)
     694            0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     695              : 
     696              :     /* if this cache isn't initialized yet, no need to do anything */
     697     15958649 :     if (!SysCache[cacheId])
     698            0 :         return;
     699              : 
     700     15958649 :     CatCacheInvalidate(SysCache[cacheId], hashValue);
     701              : }
     702              : 
     703              : /*
     704              :  * Certain relations that do not have system caches send snapshot invalidation
     705              :  * messages in lieu of catcache messages.  This is for the benefit of
     706              :  * GetCatalogSnapshot(), which can then reuse its existing MVCC snapshot
     707              :  * for scanning one of those catalogs, rather than taking a new one, if no
     708              :  * invalidation has been received.
     709              :  *
     710              :  * Relations that have syscaches need not (and must not) be listed here.  The
     711              :  * catcache invalidation messages will also flush the snapshot.  If you add a
     712              :  * syscache for one of these relations, remove it from this list.
     713              :  */
     714              : bool
     715     10998827 : RelationInvalidatesSnapshotsOnly(Oid relid)
     716              : {
     717     10998827 :     switch (relid)
     718              :     {
     719      1791908 :         case DbRoleSettingRelationId:
     720              :         case DependRelationId:
     721              :         case SharedDependRelationId:
     722              :         case DescriptionRelationId:
     723              :         case SharedDescriptionRelationId:
     724              :         case SecLabelRelationId:
     725              :         case SharedSecLabelRelationId:
     726      1791908 :             return true;
     727      9206919 :         default:
     728      9206919 :             break;
     729              :     }
     730              : 
     731      9206919 :     return false;
     732              : }
     733              : 
     734              : /*
     735              :  * Test whether a relation has a system cache.
     736              :  */
     737              : bool
     738      7161336 : RelationHasSysCache(Oid relid)
     739              : {
     740      7161336 :     int         low = 0,
     741      7161336 :                 high = SysCacheRelationOidSize - 1;
     742              : 
     743     39515512 :     while (low <= high)
     744              :     {
     745     39168423 :         int         middle = low + (high - low) / 2;
     746              : 
     747     39168423 :         if (SysCacheRelationOid[middle] == relid)
     748      6814247 :             return true;
     749     32354176 :         if (SysCacheRelationOid[middle] < relid)
     750     11634352 :             low = middle + 1;
     751              :         else
     752     20719824 :             high = middle - 1;
     753              :     }
     754              : 
     755       347089 :     return false;
     756              : }
     757              : 
     758              : /*
     759              :  * Test whether a relation supports a system cache, ie it is either a
     760              :  * cached table or the index used for a cache.
     761              :  */
     762              : bool
     763      1713379 : RelationSupportsSysCache(Oid relid)
     764              : {
     765      1713379 :     int         low = 0,
     766      1713379 :                 high = SysCacheSupportingRelOidSize - 1;
     767              : 
     768     14329747 :     while (low <= high)
     769              :     {
     770     12996765 :         int         middle = low + (high - low) / 2;
     771              : 
     772     12996765 :         if (SysCacheSupportingRelOid[middle] == relid)
     773       380397 :             return true;
     774     12616368 :         if (SysCacheSupportingRelOid[middle] < relid)
     775     11342988 :             low = middle + 1;
     776              :         else
     777      1273380 :             high = middle - 1;
     778              :     }
     779              : 
     780      1332982 :     return false;
     781              : }
     782              : 
     783              : 
     784              : /*
     785              :  * OID comparator for qsort
     786              :  */
     787              : static int
     788     43630359 : oid_compare(const void *a, const void *b)
     789              : {
     790     43630359 :     Oid         oa = *((const Oid *) a);
     791     43630359 :     Oid         ob = *((const Oid *) b);
     792              : 
     793     43630359 :     return pg_cmp_u32(oa, ob);
     794              : }
        

Generated by: LCOV version 2.0-1