LCOV - code coverage report
Current view: top level - src/backend/utils/cache - syscache.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 173 185 93.5 %
Date: 2025-10-10 18:17:38 Functions: 27 27 100.0 %
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-2025, 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       36058 : InitCatalogCache(void)
     111             : {
     112             :     int         cacheId;
     113             : 
     114             :     Assert(!CacheInitialized);
     115             : 
     116       36058 :     SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0;
     117             : 
     118     3100988 :     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     6129860 :         SysCache[cacheId] = InitCatCache(cacheId,
     129     3064930 :                                          cacheinfo[cacheId].reloid,
     130     3064930 :                                          cacheinfo[cacheId].indoid,
     131     3064930 :                                          cacheinfo[cacheId].nkeys,
     132     3064930 :                                          cacheinfo[cacheId].key,
     133     3064930 :                                          cacheinfo[cacheId].nbuckets);
     134     3064930 :         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     3064930 :         SysCacheRelationOid[SysCacheRelationOidSize++] =
     139     3064930 :             cacheinfo[cacheId].reloid;
     140     3064930 :         SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
     141     3064930 :             cacheinfo[cacheId].reloid;
     142     3064930 :         SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
     143     3064930 :             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       36058 :     qsort(SysCacheRelationOid, SysCacheRelationOidSize,
     153             :           sizeof(Oid), oid_compare);
     154       36058 :     SysCacheRelationOidSize =
     155       36058 :         qunique(SysCacheRelationOid, SysCacheRelationOidSize, sizeof(Oid),
     156             :                 oid_compare);
     157             : 
     158       36058 :     qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
     159             :           sizeof(Oid), oid_compare);
     160       36058 :     SysCacheSupportingRelOidSize =
     161       36058 :         qunique(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
     162             :                 sizeof(Oid), oid_compare);
     163             : 
     164       36058 :     CacheInitialized = true;
     165       36058 : }
     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        3706 : InitCatalogCachePhase2(void)
     181             : {
     182             :     int         cacheId;
     183             : 
     184             :     Assert(CacheInitialized);
     185             : 
     186      318716 :     for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
     187      315010 :         InitCatCachePhase2(SysCache[cacheId], true);
     188        3706 : }
     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     5805956 : SearchSysCache(int cacheId,
     209             :                Datum key1,
     210             :                Datum key2,
     211             :                Datum key3,
     212             :                Datum key4)
     213             : {
     214             :     Assert(cacheId >= 0 && cacheId < SysCacheSize && SysCache[cacheId]);
     215             : 
     216     5805956 :     return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
     217             : }
     218             : 
     219             : HeapTuple
     220    73242718 : SearchSysCache1(int cacheId,
     221             :                 Datum key1)
     222             : {
     223             :     Assert(cacheId >= 0 && cacheId < SysCacheSize && SysCache[cacheId]);
     224             :     Assert(SysCache[cacheId]->cc_nkeys == 1);
     225             : 
     226    73242718 :     return SearchCatCache1(SysCache[cacheId], key1);
     227             : }
     228             : 
     229             : HeapTuple
     230     6110412 : SearchSysCache2(int cacheId,
     231             :                 Datum key1, Datum key2)
     232             : {
     233             :     Assert(cacheId >= 0 && cacheId < SysCacheSize && SysCache[cacheId]);
     234             :     Assert(SysCache[cacheId]->cc_nkeys == 2);
     235             : 
     236     6110412 :     return SearchCatCache2(SysCache[cacheId], key1, key2);
     237             : }
     238             : 
     239             : HeapTuple
     240     5887318 : SearchSysCache3(int 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     5887318 :     return SearchCatCache3(SysCache[cacheId], key1, key2, key3);
     247             : }
     248             : 
     249             : HeapTuple
     250     4559710 : SearchSysCache4(int 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     4559710 :     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    89500708 : ReleaseSysCache(HeapTuple tuple)
     265             : {
     266    89500708 :     ReleaseCatCache(tuple);
     267    89500708 : }
     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       45926 : SearchSysCacheLocked1(int cacheId,
     283             :                       Datum key1)
     284             : {
     285       45926 :     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       45926 :     ItemPointerSetInvalid(&tid);
     317             :     for (;;)
     318       45928 :     {
     319             :         HeapTuple   tuple;
     320       91854 :         LOCKMODE    lockmode = InplaceUpdateTupleLock;
     321             : 
     322       91854 :         tuple = SearchSysCache1(cacheId, key1);
     323       91854 :         if (ItemPointerIsValid(&tid))
     324             :         {
     325       45928 :             if (!HeapTupleIsValid(tuple))
     326             :             {
     327           2 :                 LockRelease(&tag, lockmode, false);
     328           2 :                 return tuple;
     329             :             }
     330       45926 :             if (ItemPointerEquals(&tid, &tuple->t_self))
     331       45924 :                 return tuple;
     332           2 :             LockRelease(&tag, lockmode, false);
     333             :         }
     334       45926 :         else if (!HeapTupleIsValid(tuple))
     335           0 :             return tuple;
     336             : 
     337       45928 :         tid = tuple->t_self;
     338       45928 :         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       45928 :         SET_LOCKTAG_TUPLE(tag,
     346             :                           cache->cc_relisshared ? InvalidOid : MyDatabaseId,
     347             :                           cache->cc_reloid,
     348             :                           ItemPointerGetBlockNumber(&tid),
     349             :                           ItemPointerGetOffsetNumber(&tid));
     350       45928 :         (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       45928 :         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      631398 : SearchSysCacheCopy(int cacheId,
     375             :                    Datum key1,
     376             :                    Datum key2,
     377             :                    Datum key3,
     378             :                    Datum key4)
     379             : {
     380             :     HeapTuple   tuple,
     381             :                 newtuple;
     382             : 
     383      631398 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     384      631398 :     if (!HeapTupleIsValid(tuple))
     385      143112 :         return tuple;
     386      488286 :     newtuple = heap_copytuple(tuple);
     387      488286 :     ReleaseSysCache(tuple);
     388      488286 :     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       16850 : SearchSysCacheLockedCopy1(int cacheId,
     400             :                           Datum key1)
     401             : {
     402             :     HeapTuple   tuple,
     403             :                 newtuple;
     404             : 
     405       16850 :     tuple = SearchSysCacheLocked1(cacheId, key1);
     406       16850 :     if (!HeapTupleIsValid(tuple))
     407           0 :         return tuple;
     408       16850 :     newtuple = heap_copytuple(tuple);
     409       16850 :     ReleaseSysCache(tuple);
     410       16850 :     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     1498420 : SearchSysCacheExists(int cacheId,
     421             :                      Datum key1,
     422             :                      Datum key2,
     423             :                      Datum key3,
     424             :                      Datum key4)
     425             : {
     426             :     HeapTuple   tuple;
     427             : 
     428     1498420 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     429     1498420 :     if (!HeapTupleIsValid(tuple))
     430      234024 :         return false;
     431     1264396 :     ReleaseSysCache(tuple);
     432     1264396 :     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     3676138 : GetSysCacheOid(int 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     3676138 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     455     3676138 :     if (!HeapTupleIsValid(tuple))
     456     1394610 :         return InvalidOid;
     457     2281528 :     result = DatumGetObjectId(heap_getattr(tuple, oidcol,
     458     2281528 :                                            SysCache[cacheId]->cc_tupdesc,
     459             :                                            &isNull));
     460             :     Assert(!isNull);            /* columns used as oids should never be NULL */
     461     2281528 :     ReleaseSysCache(tuple);
     462     2281528 :     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      111788 : SearchSysCacheAttName(Oid relid, const char *attname)
     476             : {
     477             :     HeapTuple   tuple;
     478             : 
     479      111788 :     tuple = SearchSysCache2(ATTNAME,
     480             :                             ObjectIdGetDatum(relid),
     481             :                             CStringGetDatum(attname));
     482      111788 :     if (!HeapTupleIsValid(tuple))
     483        1032 :         return NULL;
     484      110756 :     if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
     485             :     {
     486          84 :         ReleaseSysCache(tuple);
     487          84 :         return NULL;
     488             :     }
     489      110672 :     return tuple;
     490             : }
     491             : 
     492             : /*
     493             :  * SearchSysCacheCopyAttName
     494             :  *
     495             :  * As above, an attisdropped-aware version of SearchSysCacheCopy.
     496             :  */
     497             : HeapTuple
     498        9526 : SearchSysCacheCopyAttName(Oid relid, const char *attname)
     499             : {
     500             :     HeapTuple   tuple,
     501             :                 newtuple;
     502             : 
     503        9526 :     tuple = SearchSysCacheAttName(relid, attname);
     504        9526 :     if (!HeapTupleIsValid(tuple))
     505         744 :         return tuple;
     506        8782 :     newtuple = heap_copytuple(tuple);
     507        8782 :     ReleaseSysCache(tuple);
     508        8782 :     return newtuple;
     509             : }
     510             : 
     511             : /*
     512             :  * SearchSysCacheExistsAttName
     513             :  *
     514             :  * As above, an attisdropped-aware version of SearchSysCacheExists.
     515             :  */
     516             : bool
     517        1102 : SearchSysCacheExistsAttName(Oid relid, const char *attname)
     518             : {
     519             :     HeapTuple   tuple;
     520             : 
     521        1102 :     tuple = SearchSysCacheAttName(relid, attname);
     522        1102 :     if (!HeapTupleIsValid(tuple))
     523          54 :         return false;
     524        1048 :     ReleaseSysCache(tuple);
     525        1048 :     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        1882 : SearchSysCacheAttNum(Oid relid, int16 attnum)
     539             : {
     540             :     HeapTuple   tuple;
     541             : 
     542        1882 :     tuple = SearchSysCache2(ATTNUM,
     543             :                             ObjectIdGetDatum(relid),
     544             :                             Int16GetDatum(attnum));
     545        1882 :     if (!HeapTupleIsValid(tuple))
     546          12 :         return NULL;
     547        1870 :     if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
     548             :     {
     549           0 :         ReleaseSysCache(tuple);
     550           0 :         return NULL;
     551             :     }
     552        1870 :     return tuple;
     553             : }
     554             : 
     555             : /*
     556             :  * SearchSysCacheCopyAttNum
     557             :  *
     558             :  * As above, an attisdropped-aware version of SearchSysCacheCopy.
     559             :  */
     560             : HeapTuple
     561        1818 : SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
     562             : {
     563             :     HeapTuple   tuple,
     564             :                 newtuple;
     565             : 
     566        1818 :     tuple = SearchSysCacheAttNum(relid, attnum);
     567        1818 :     if (!HeapTupleIsValid(tuple))
     568           0 :         return NULL;
     569        1818 :     newtuple = heap_copytuple(tuple);
     570        1818 :     ReleaseSysCache(tuple);
     571        1818 :     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     6041892 : SysCacheGetAttr(int 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     6041892 :     if (cacheId < 0 || cacheId >= SysCacheSize || !SysCache[cacheId])
     606           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     607     6041892 :     if (!SysCache[cacheId]->cc_tupdesc)
     608             :     {
     609       34458 :         InitCatCachePhase2(SysCache[cacheId], false);
     610             :         Assert(SysCache[cacheId]->cc_tupdesc);
     611             :     }
     612             : 
     613    12083784 :     return heap_getattr(tup, attributeNumber,
     614     6041892 :                         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     3493022 : SysCacheGetAttrNotNull(int cacheId, HeapTuple tup,
     626             :                        AttrNumber attributeNumber)
     627             : {
     628             :     bool        isnull;
     629             :     Datum       attr;
     630             : 
     631     3493022 :     attr = SysCacheGetAttr(cacheId, tup, attributeNumber, &isnull);
     632             : 
     633     3493022 :     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     3493022 :     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     1109990 : GetSysCacheHashValue(int cacheId,
     656             :                      Datum key1,
     657             :                      Datum key2,
     658             :                      Datum key3,
     659             :                      Datum key4)
     660             : {
     661     1109990 :     if (cacheId < 0 || cacheId >= SysCacheSize || !SysCache[cacheId])
     662           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     663             : 
     664     1109990 :     return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4);
     665             : }
     666             : 
     667             : /*
     668             :  * List-search interface
     669             :  */
     670             : struct catclist *
     671     3945014 : SearchSysCacheList(int cacheId, int nkeys,
     672             :                    Datum key1, Datum key2, Datum key3)
     673             : {
     674     3945014 :     if (cacheId < 0 || cacheId >= SysCacheSize || !SysCache[cacheId])
     675           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     676             : 
     677     3945014 :     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    22438732 : SysCacheInvalidate(int cacheId, uint32 hashValue)
     691             : {
     692    22438732 :     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    22438732 :     if (!SysCache[cacheId])
     697           0 :         return;
     698             : 
     699    22438732 :     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    17238356 : RelationInvalidatesSnapshotsOnly(Oid relid)
     715             : {
     716    17238356 :     switch (relid)
     717             :     {
     718     2657904 :         case DbRoleSettingRelationId:
     719             :         case DependRelationId:
     720             :         case SharedDependRelationId:
     721             :         case DescriptionRelationId:
     722             :         case SharedDescriptionRelationId:
     723             :         case SecLabelRelationId:
     724             :         case SharedSecLabelRelationId:
     725     2657904 :             return true;
     726    14580452 :         default:
     727    14580452 :             break;
     728             :     }
     729             : 
     730    14580452 :     return false;
     731             : }
     732             : 
     733             : /*
     734             :  * Test whether a relation has a system cache.
     735             :  */
     736             : bool
     737    11299130 : RelationHasSysCache(Oid relid)
     738             : {
     739    11299130 :     int         low = 0,
     740    11299130 :                 high = SysCacheRelationOidSize - 1;
     741             : 
     742    49927180 :     while (low <= high)
     743             :     {
     744    49434782 :         int         middle = low + (high - low) / 2;
     745             : 
     746    49434782 :         if (SysCacheRelationOid[middle] == relid)
     747    10806732 :             return true;
     748    38628050 :         if (SysCacheRelationOid[middle] < relid)
     749    13422744 :             low = middle + 1;
     750             :         else
     751    25205306 :             high = middle - 1;
     752             :     }
     753             : 
     754      492398 :     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     2659590 : RelationSupportsSysCache(Oid relid)
     763             : {
     764     2659590 :     int         low = 0,
     765     2659590 :                 high = SysCacheSupportingRelOidSize - 1;
     766             : 
     767    21923794 :     while (low <= high)
     768             :     {
     769    19906190 :         int         middle = low + (high - low) / 2;
     770             : 
     771    19906190 :         if (SysCacheSupportingRelOid[middle] == relid)
     772      641986 :             return true;
     773    19264204 :         if (SysCacheSupportingRelOid[middle] < relid)
     774    17047952 :             low = middle + 1;
     775             :         else
     776     2216252 :             high = middle - 1;
     777             :     }
     778             : 
     779     2017604 :     return false;
     780             : }
     781             : 
     782             : 
     783             : /*
     784             :  * OID comparator for qsort
     785             :  */
     786             : static int
     787    71286666 : oid_compare(const void *a, const void *b)
     788             : {
     789    71286666 :     Oid         oa = *((const Oid *) a);
     790    71286666 :     Oid         ob = *((const Oid *) b);
     791             : 
     792    71286666 :     return pg_cmp_u32(oa, ob);
     793             : }

Generated by: LCOV version 1.16