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

Generated by: LCOV version 2.0-1