LCOV - code coverage report
Current view: top level - src/backend/utils/cache - syscache.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 170 184 92.4 %
Date: 2024-12-12 16:15:21 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-2024, 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       28952 : InitCatalogCache(void)
     111             : {
     112             :     int         cacheId;
     113             : 
     114             :     Assert(!CacheInitialized);
     115             : 
     116       28952 :     SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0;
     117             : 
     118     2489872 :     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     4921840 :         SysCache[cacheId] = InitCatCache(cacheId,
     129             :                                          cacheinfo[cacheId].reloid,
     130             :                                          cacheinfo[cacheId].indoid,
     131             :                                          cacheinfo[cacheId].nkeys,
     132     2460920 :                                          cacheinfo[cacheId].key,
     133             :                                          cacheinfo[cacheId].nbuckets);
     134     2460920 :         if (!PointerIsValid(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     2460920 :         SysCacheRelationOid[SysCacheRelationOidSize++] =
     139     2460920 :             cacheinfo[cacheId].reloid;
     140     2460920 :         SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
     141     2460920 :             cacheinfo[cacheId].reloid;
     142     2460920 :         SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
     143     2460920 :             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       28952 :     qsort(SysCacheRelationOid, SysCacheRelationOidSize,
     153             :           sizeof(Oid), oid_compare);
     154       28952 :     SysCacheRelationOidSize =
     155       28952 :         qunique(SysCacheRelationOid, SysCacheRelationOidSize, sizeof(Oid),
     156             :                 oid_compare);
     157             : 
     158       28952 :     qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
     159             :           sizeof(Oid), oid_compare);
     160       28952 :     SysCacheSupportingRelOidSize =
     161       28952 :         qunique(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
     162             :                 sizeof(Oid), oid_compare);
     163             : 
     164       28952 :     CacheInitialized = true;
     165       28952 : }
     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        2814 : InitCatalogCachePhase2(void)
     181             : {
     182             :     int         cacheId;
     183             : 
     184             :     Assert(CacheInitialized);
     185             : 
     186      241928 :     for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
     187      239118 :         InitCatCachePhase2(SysCache[cacheId], true);
     188        2810 : }
     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     5044964 : SearchSysCache(int cacheId,
     209             :                Datum key1,
     210             :                Datum key2,
     211             :                Datum key3,
     212             :                Datum key4)
     213             : {
     214             :     Assert(cacheId >= 0 && cacheId < SysCacheSize &&
     215             :            PointerIsValid(SysCache[cacheId]));
     216             : 
     217     5044964 :     return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
     218             : }
     219             : 
     220             : HeapTuple
     221    62278932 : SearchSysCache1(int cacheId,
     222             :                 Datum key1)
     223             : {
     224             :     Assert(cacheId >= 0 && cacheId < SysCacheSize &&
     225             :            PointerIsValid(SysCache[cacheId]));
     226             :     Assert(SysCache[cacheId]->cc_nkeys == 1);
     227             : 
     228    62278932 :     return SearchCatCache1(SysCache[cacheId], key1);
     229             : }
     230             : 
     231             : HeapTuple
     232     5021062 : SearchSysCache2(int cacheId,
     233             :                 Datum key1, Datum key2)
     234             : {
     235             :     Assert(cacheId >= 0 && cacheId < SysCacheSize &&
     236             :            PointerIsValid(SysCache[cacheId]));
     237             :     Assert(SysCache[cacheId]->cc_nkeys == 2);
     238             : 
     239     5021062 :     return SearchCatCache2(SysCache[cacheId], key1, key2);
     240             : }
     241             : 
     242             : HeapTuple
     243     4731466 : SearchSysCache3(int cacheId,
     244             :                 Datum key1, Datum key2, Datum key3)
     245             : {
     246             :     Assert(cacheId >= 0 && cacheId < SysCacheSize &&
     247             :            PointerIsValid(SysCache[cacheId]));
     248             :     Assert(SysCache[cacheId]->cc_nkeys == 3);
     249             : 
     250     4731466 :     return SearchCatCache3(SysCache[cacheId], key1, key2, key3);
     251             : }
     252             : 
     253             : HeapTuple
     254     3905676 : SearchSysCache4(int cacheId,
     255             :                 Datum key1, Datum key2, Datum key3, Datum key4)
     256             : {
     257             :     Assert(cacheId >= 0 && cacheId < SysCacheSize &&
     258             :            PointerIsValid(SysCache[cacheId]));
     259             :     Assert(SysCache[cacheId]->cc_nkeys == 4);
     260             : 
     261     3905676 :     return SearchCatCache4(SysCache[cacheId], key1, key2, key3, key4);
     262             : }
     263             : 
     264             : /*
     265             :  * ReleaseSysCache
     266             :  *      Release previously grabbed reference count on a tuple
     267             :  */
     268             : void
     269    75676540 : ReleaseSysCache(HeapTuple tuple)
     270             : {
     271    75676540 :     ReleaseCatCache(tuple);
     272    75676540 : }
     273             : 
     274             : /*
     275             :  * SearchSysCacheLocked1
     276             :  *
     277             :  * Combine SearchSysCache1() with acquiring a LOCKTAG_TUPLE at mode
     278             :  * InplaceUpdateTupleLock.  This is a tool for complying with the
     279             :  * README.tuplock section "Locking to write inplace-updated tables".  After
     280             :  * the caller's heap_update(), it should UnlockTuple(InplaceUpdateTupleLock)
     281             :  * and ReleaseSysCache().
     282             :  *
     283             :  * The returned tuple may be the subject of an uncommitted update, so this
     284             :  * doesn't prevent the "tuple concurrently updated" error.
     285             :  */
     286             : HeapTuple
     287       43302 : SearchSysCacheLocked1(int cacheId,
     288             :                       Datum key1)
     289             : {
     290       43302 :     CatCache   *cache = SysCache[cacheId];
     291             :     ItemPointerData tid;
     292             :     LOCKTAG     tag;
     293             : 
     294             :     /*----------
     295             :      * Since inplace updates may happen just before our LockTuple(), we must
     296             :      * return content acquired after LockTuple() of the TID we return.  If we
     297             :      * just fetched twice instead of looping, the following sequence would
     298             :      * defeat our locking:
     299             :      *
     300             :      * GRANT:   SearchSysCache1() = TID (1,5)
     301             :      * GRANT:   LockTuple(pg_class, (1,5))
     302             :      * [no more inplace update of (1,5) until we release the lock]
     303             :      * CLUSTER: SearchSysCache1() = TID (1,5)
     304             :      * CLUSTER: heap_update() = TID (1,8)
     305             :      * CLUSTER: COMMIT
     306             :      * GRANT:   SearchSysCache1() = TID (1,8)
     307             :      * GRANT:   return (1,8) from SearchSysCacheLocked1()
     308             :      * VACUUM:  SearchSysCache1() = TID (1,8)
     309             :      * VACUUM:  LockTuple(pg_class, (1,8))  # two TIDs now locked for one rel
     310             :      * VACUUM:  inplace update
     311             :      * GRANT:   heap_update() = (1,9)  # lose inplace update
     312             :      *
     313             :      * In the happy case, this takes two fetches, one to determine the TID to
     314             :      * lock and another to get the content and confirm the TID didn't change.
     315             :      *
     316             :      * This is valid even if the row gets updated to a new TID, the old TID
     317             :      * becomes LP_UNUSED, and the row gets updated back to its old TID.  We'd
     318             :      * still hold the right LOCKTAG_TUPLE and a copy of the row captured after
     319             :      * the LOCKTAG_TUPLE.
     320             :      */
     321       43302 :     ItemPointerSetInvalid(&tid);
     322             :     for (;;)
     323       43304 :     {
     324             :         HeapTuple   tuple;
     325       86606 :         LOCKMODE    lockmode = InplaceUpdateTupleLock;
     326             : 
     327       86606 :         tuple = SearchSysCache1(cacheId, key1);
     328       86606 :         if (ItemPointerIsValid(&tid))
     329             :         {
     330       43304 :             if (!HeapTupleIsValid(tuple))
     331             :             {
     332           0 :                 LockRelease(&tag, lockmode, false);
     333           0 :                 return tuple;
     334             :             }
     335       43304 :             if (ItemPointerEquals(&tid, &tuple->t_self))
     336       43302 :                 return tuple;
     337           2 :             LockRelease(&tag, lockmode, false);
     338             :         }
     339       43302 :         else if (!HeapTupleIsValid(tuple))
     340           0 :             return tuple;
     341             : 
     342       43304 :         tid = tuple->t_self;
     343       43304 :         ReleaseSysCache(tuple);
     344             : 
     345             :         /*
     346             :          * Do like LockTuple(rel, &tid, lockmode).  While cc_relisshared won't
     347             :          * change from one iteration to another, it may have been a temporary
     348             :          * "false" until our first SearchSysCache1().
     349             :          */
     350       43304 :         SET_LOCKTAG_TUPLE(tag,
     351             :                           cache->cc_relisshared ? InvalidOid : MyDatabaseId,
     352             :                           cache->cc_reloid,
     353             :                           ItemPointerGetBlockNumber(&tid),
     354             :                           ItemPointerGetOffsetNumber(&tid));
     355       43304 :         (void) LockAcquire(&tag, lockmode, false, false);
     356             : 
     357             :         /*
     358             :          * If an inplace update just finished, ensure we process the syscache
     359             :          * inval.
     360             :          *
     361             :          * If a heap_update() call just released its LOCKTAG_TUPLE, we'll
     362             :          * probably find the old tuple and reach "tuple concurrently updated".
     363             :          * If that heap_update() aborts, our LOCKTAG_TUPLE blocks inplace
     364             :          * updates while our caller works.
     365             :          */
     366       43304 :         AcceptInvalidationMessages();
     367             :     }
     368             : }
     369             : 
     370             : /*
     371             :  * SearchSysCacheCopy
     372             :  *
     373             :  * A convenience routine that does SearchSysCache and (if successful)
     374             :  * returns a modifiable copy of the syscache entry.  The original
     375             :  * syscache entry is released before returning.  The caller should
     376             :  * heap_freetuple() the result when done with it.
     377             :  */
     378             : HeapTuple
     379      448072 : SearchSysCacheCopy(int cacheId,
     380             :                    Datum key1,
     381             :                    Datum key2,
     382             :                    Datum key3,
     383             :                    Datum key4)
     384             : {
     385             :     HeapTuple   tuple,
     386             :                 newtuple;
     387             : 
     388      448072 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     389      448072 :     if (!HeapTupleIsValid(tuple))
     390      129904 :         return tuple;
     391      318168 :     newtuple = heap_copytuple(tuple);
     392      318168 :     ReleaseSysCache(tuple);
     393      318168 :     return newtuple;
     394             : }
     395             : 
     396             : /*
     397             :  * SearchSysCacheLockedCopy1
     398             :  *
     399             :  * Meld SearchSysCacheLockedCopy1 with SearchSysCacheCopy().  After the
     400             :  * caller's heap_update(), it should UnlockTuple(InplaceUpdateTupleLock) and
     401             :  * heap_freetuple().
     402             :  */
     403             : HeapTuple
     404       15842 : SearchSysCacheLockedCopy1(int cacheId,
     405             :                           Datum key1)
     406             : {
     407             :     HeapTuple   tuple,
     408             :                 newtuple;
     409             : 
     410       15842 :     tuple = SearchSysCacheLocked1(cacheId, key1);
     411       15842 :     if (!HeapTupleIsValid(tuple))
     412           0 :         return tuple;
     413       15842 :     newtuple = heap_copytuple(tuple);
     414       15842 :     ReleaseSysCache(tuple);
     415       15842 :     return newtuple;
     416             : }
     417             : 
     418             : /*
     419             :  * SearchSysCacheExists
     420             :  *
     421             :  * A convenience routine that just probes to see if a tuple can be found.
     422             :  * No lock is retained on the syscache entry.
     423             :  */
     424             : bool
     425     1227320 : SearchSysCacheExists(int cacheId,
     426             :                      Datum key1,
     427             :                      Datum key2,
     428             :                      Datum key3,
     429             :                      Datum key4)
     430             : {
     431             :     HeapTuple   tuple;
     432             : 
     433     1227320 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     434     1227320 :     if (!HeapTupleIsValid(tuple))
     435      207914 :         return false;
     436     1019406 :     ReleaseSysCache(tuple);
     437     1019406 :     return true;
     438             : }
     439             : 
     440             : /*
     441             :  * GetSysCacheOid
     442             :  *
     443             :  * A convenience routine that does SearchSysCache and returns the OID in the
     444             :  * oidcol column of the found tuple, or InvalidOid if no tuple could be found.
     445             :  * No lock is retained on the syscache entry.
     446             :  */
     447             : Oid
     448     3369572 : GetSysCacheOid(int cacheId,
     449             :                AttrNumber oidcol,
     450             :                Datum key1,
     451             :                Datum key2,
     452             :                Datum key3,
     453             :                Datum key4)
     454             : {
     455             :     HeapTuple   tuple;
     456             :     bool        isNull;
     457             :     Oid         result;
     458             : 
     459     3369572 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     460     3369572 :     if (!HeapTupleIsValid(tuple))
     461     1351642 :         return InvalidOid;
     462     4035860 :     result = heap_getattr(tuple, oidcol,
     463     2017930 :                           SysCache[cacheId]->cc_tupdesc,
     464             :                           &isNull);
     465             :     Assert(!isNull);            /* columns used as oids should never be NULL */
     466     2017930 :     ReleaseSysCache(tuple);
     467     2017930 :     return result;
     468             : }
     469             : 
     470             : 
     471             : /*
     472             :  * SearchSysCacheAttName
     473             :  *
     474             :  * This routine is equivalent to SearchSysCache on the ATTNAME cache,
     475             :  * except that it will return NULL if the found attribute is marked
     476             :  * attisdropped.  This is convenient for callers that want to act as
     477             :  * though dropped attributes don't exist.
     478             :  */
     479             : HeapTuple
     480      101446 : SearchSysCacheAttName(Oid relid, const char *attname)
     481             : {
     482             :     HeapTuple   tuple;
     483             : 
     484      101446 :     tuple = SearchSysCache2(ATTNAME,
     485             :                             ObjectIdGetDatum(relid),
     486             :                             CStringGetDatum(attname));
     487      101446 :     if (!HeapTupleIsValid(tuple))
     488         924 :         return NULL;
     489      100522 :     if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
     490             :     {
     491          78 :         ReleaseSysCache(tuple);
     492          78 :         return NULL;
     493             :     }
     494      100444 :     return tuple;
     495             : }
     496             : 
     497             : /*
     498             :  * SearchSysCacheCopyAttName
     499             :  *
     500             :  * As above, an attisdropped-aware version of SearchSysCacheCopy.
     501             :  */
     502             : HeapTuple
     503        8536 : SearchSysCacheCopyAttName(Oid relid, const char *attname)
     504             : {
     505             :     HeapTuple   tuple,
     506             :                 newtuple;
     507             : 
     508        8536 :     tuple = SearchSysCacheAttName(relid, attname);
     509        8536 :     if (!HeapTupleIsValid(tuple))
     510         654 :         return tuple;
     511        7882 :     newtuple = heap_copytuple(tuple);
     512        7882 :     ReleaseSysCache(tuple);
     513        7882 :     return newtuple;
     514             : }
     515             : 
     516             : /*
     517             :  * SearchSysCacheExistsAttName
     518             :  *
     519             :  * As above, an attisdropped-aware version of SearchSysCacheExists.
     520             :  */
     521             : bool
     522        1014 : SearchSysCacheExistsAttName(Oid relid, const char *attname)
     523             : {
     524             :     HeapTuple   tuple;
     525             : 
     526        1014 :     tuple = SearchSysCacheAttName(relid, attname);
     527        1014 :     if (!HeapTupleIsValid(tuple))
     528          54 :         return false;
     529         960 :     ReleaseSysCache(tuple);
     530         960 :     return true;
     531             : }
     532             : 
     533             : 
     534             : /*
     535             :  * SearchSysCacheAttNum
     536             :  *
     537             :  * This routine is equivalent to SearchSysCache on the ATTNUM cache,
     538             :  * except that it will return NULL if the found attribute is marked
     539             :  * attisdropped.  This is convenient for callers that want to act as
     540             :  * though dropped attributes don't exist.
     541             :  */
     542             : HeapTuple
     543        1580 : SearchSysCacheAttNum(Oid relid, int16 attnum)
     544             : {
     545             :     HeapTuple   tuple;
     546             : 
     547        1580 :     tuple = SearchSysCache2(ATTNUM,
     548             :                             ObjectIdGetDatum(relid),
     549             :                             Int16GetDatum(attnum));
     550        1580 :     if (!HeapTupleIsValid(tuple))
     551          12 :         return NULL;
     552        1568 :     if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
     553             :     {
     554           0 :         ReleaseSysCache(tuple);
     555           0 :         return NULL;
     556             :     }
     557        1568 :     return tuple;
     558             : }
     559             : 
     560             : /*
     561             :  * SearchSysCacheCopyAttNum
     562             :  *
     563             :  * As above, an attisdropped-aware version of SearchSysCacheCopy.
     564             :  */
     565             : HeapTuple
     566        1516 : SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
     567             : {
     568             :     HeapTuple   tuple,
     569             :                 newtuple;
     570             : 
     571        1516 :     tuple = SearchSysCacheAttNum(relid, attnum);
     572        1516 :     if (!HeapTupleIsValid(tuple))
     573           0 :         return NULL;
     574        1516 :     newtuple = heap_copytuple(tuple);
     575        1516 :     ReleaseSysCache(tuple);
     576        1516 :     return newtuple;
     577             : }
     578             : 
     579             : 
     580             : /*
     581             :  * SysCacheGetAttr
     582             :  *
     583             :  *      Given a tuple previously fetched by SearchSysCache(),
     584             :  *      extract a specific attribute.
     585             :  *
     586             :  * This is equivalent to using heap_getattr() on a tuple fetched
     587             :  * from a non-cached relation.  Usually, this is only used for attributes
     588             :  * that could be NULL or variable length; the fixed-size attributes in
     589             :  * a system table are accessed just by mapping the tuple onto the C struct
     590             :  * declarations from include/catalog/.
     591             :  *
     592             :  * As with heap_getattr(), if the attribute is of a pass-by-reference type
     593             :  * then a pointer into the tuple data area is returned --- the caller must
     594             :  * not modify or pfree the datum!
     595             :  *
     596             :  * Note: it is legal to use SysCacheGetAttr() with a cacheId referencing
     597             :  * a different cache for the same catalog the tuple was fetched from.
     598             :  */
     599             : Datum
     600     5033052 : SysCacheGetAttr(int cacheId, HeapTuple tup,
     601             :                 AttrNumber attributeNumber,
     602             :                 bool *isNull)
     603             : {
     604             :     /*
     605             :      * We just need to get the TupleDesc out of the cache entry, and then we
     606             :      * can apply heap_getattr().  Normally the cache control data is already
     607             :      * valid (because the caller recently fetched the tuple via this same
     608             :      * cache), but there are cases where we have to initialize the cache here.
     609             :      */
     610     5033052 :     if (cacheId < 0 || cacheId >= SysCacheSize ||
     611     5033052 :         !PointerIsValid(SysCache[cacheId]))
     612           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     613     5033052 :     if (!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
     614             :     {
     615       27488 :         InitCatCachePhase2(SysCache[cacheId], false);
     616             :         Assert(PointerIsValid(SysCache[cacheId]->cc_tupdesc));
     617             :     }
     618             : 
     619    10066104 :     return heap_getattr(tup, attributeNumber,
     620     5033052 :                         SysCache[cacheId]->cc_tupdesc,
     621             :                         isNull);
     622             : }
     623             : 
     624             : /*
     625             :  * SysCacheGetAttrNotNull
     626             :  *
     627             :  * As above, a version of SysCacheGetAttr which knows that the attr cannot
     628             :  * be NULL.
     629             :  */
     630             : Datum
     631     2844014 : SysCacheGetAttrNotNull(int cacheId, HeapTuple tup,
     632             :                        AttrNumber attributeNumber)
     633             : {
     634             :     bool        isnull;
     635             :     Datum       attr;
     636             : 
     637     2844014 :     attr = SysCacheGetAttr(cacheId, tup, attributeNumber, &isnull);
     638             : 
     639     2844014 :     if (isnull)
     640             :     {
     641           0 :         elog(ERROR,
     642             :              "unexpected null value in cached tuple for catalog %s column %s",
     643             :              get_rel_name(cacheinfo[cacheId].reloid),
     644             :              NameStr(TupleDescAttr(SysCache[cacheId]->cc_tupdesc, attributeNumber - 1)->attname));
     645             :     }
     646             : 
     647     2844014 :     return attr;
     648             : }
     649             : 
     650             : /*
     651             :  * GetSysCacheHashValue
     652             :  *
     653             :  * Get the hash value that would be used for a tuple in the specified cache
     654             :  * with the given search keys.
     655             :  *
     656             :  * The reason for exposing this as part of the API is that the hash value is
     657             :  * exposed in cache invalidation operations, so there are places outside the
     658             :  * catcache code that need to be able to compute the hash values.
     659             :  */
     660             : uint32
     661      994326 : GetSysCacheHashValue(int cacheId,
     662             :                      Datum key1,
     663             :                      Datum key2,
     664             :                      Datum key3,
     665             :                      Datum key4)
     666             : {
     667      994326 :     if (cacheId < 0 || cacheId >= SysCacheSize ||
     668      994326 :         !PointerIsValid(SysCache[cacheId]))
     669           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     670             : 
     671      994326 :     return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4);
     672             : }
     673             : 
     674             : /*
     675             :  * List-search interface
     676             :  */
     677             : struct catclist *
     678     3309392 : SearchSysCacheList(int cacheId, int nkeys,
     679             :                    Datum key1, Datum key2, Datum key3)
     680             : {
     681     3309392 :     if (cacheId < 0 || cacheId >= SysCacheSize ||
     682     3309392 :         !PointerIsValid(SysCache[cacheId]))
     683           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     684             : 
     685     3309392 :     return SearchCatCacheList(SysCache[cacheId], nkeys,
     686             :                               key1, key2, key3);
     687             : }
     688             : 
     689             : /*
     690             :  * SysCacheInvalidate
     691             :  *
     692             :  *  Invalidate entries in the specified cache, given a hash value.
     693             :  *  See CatCacheInvalidate() for more info.
     694             :  *
     695             :  *  This routine is only quasi-public: it should only be used by inval.c.
     696             :  */
     697             : void
     698    19184256 : SysCacheInvalidate(int cacheId, uint32 hashValue)
     699             : {
     700    19184256 :     if (cacheId < 0 || cacheId >= SysCacheSize)
     701           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     702             : 
     703             :     /* if this cache isn't initialized yet, no need to do anything */
     704    19184256 :     if (!PointerIsValid(SysCache[cacheId]))
     705           0 :         return;
     706             : 
     707    19184256 :     CatCacheInvalidate(SysCache[cacheId], hashValue);
     708             : }
     709             : 
     710             : /*
     711             :  * Certain relations that do not have system caches send snapshot invalidation
     712             :  * messages in lieu of catcache messages.  This is for the benefit of
     713             :  * GetCatalogSnapshot(), which can then reuse its existing MVCC snapshot
     714             :  * for scanning one of those catalogs, rather than taking a new one, if no
     715             :  * invalidation has been received.
     716             :  *
     717             :  * Relations that have syscaches need not (and must not) be listed here.  The
     718             :  * catcache invalidation messages will also flush the snapshot.  If you add a
     719             :  * syscache for one of these relations, remove it from this list.
     720             :  */
     721             : bool
     722    14188954 : RelationInvalidatesSnapshotsOnly(Oid relid)
     723             : {
     724    14188954 :     switch (relid)
     725             :     {
     726     2408712 :         case DbRoleSettingRelationId:
     727             :         case DependRelationId:
     728             :         case SharedDependRelationId:
     729             :         case DescriptionRelationId:
     730             :         case SharedDescriptionRelationId:
     731             :         case SecLabelRelationId:
     732             :         case SharedSecLabelRelationId:
     733     2408712 :             return true;
     734    11780242 :         default:
     735    11780242 :             break;
     736             :     }
     737             : 
     738    11780242 :     return false;
     739             : }
     740             : 
     741             : /*
     742             :  * Test whether a relation has a system cache.
     743             :  */
     744             : bool
     745     8866184 : RelationHasSysCache(Oid relid)
     746             : {
     747     8866184 :     int         low = 0,
     748     8866184 :                 high = SysCacheRelationOidSize - 1;
     749             : 
     750    39184446 :     while (low <= high)
     751             :     {
     752    38741488 :         int         middle = low + (high - low) / 2;
     753             : 
     754    38741488 :         if (SysCacheRelationOid[middle] == relid)
     755     8423226 :             return true;
     756    30318262 :         if (SysCacheRelationOid[middle] < relid)
     757    10539020 :             low = middle + 1;
     758             :         else
     759    19779242 :             high = middle - 1;
     760             :     }
     761             : 
     762      442958 :     return false;
     763             : }
     764             : 
     765             : /*
     766             :  * Test whether a relation supports a system cache, ie it is either a
     767             :  * cached table or the index used for a cache.
     768             :  */
     769             : bool
     770     2249358 : RelationSupportsSysCache(Oid relid)
     771             : {
     772     2249358 :     int         low = 0,
     773     2249358 :                 high = SysCacheSupportingRelOidSize - 1;
     774             : 
     775    18833024 :     while (low <= high)
     776             :     {
     777    17041134 :         int         middle = low + (high - low) / 2;
     778             : 
     779    17041134 :         if (SysCacheSupportingRelOid[middle] == relid)
     780      457468 :             return true;
     781    16583666 :         if (SysCacheSupportingRelOid[middle] < relid)
     782    15084476 :             low = middle + 1;
     783             :         else
     784     1499190 :             high = middle - 1;
     785             :     }
     786             : 
     787     1791890 :     return false;
     788             : }
     789             : 
     790             : 
     791             : /*
     792             :  * OID comparator for qsort
     793             :  */
     794             : static int
     795    57238104 : oid_compare(const void *a, const void *b)
     796             : {
     797    57238104 :     Oid         oa = *((const Oid *) a);
     798    57238104 :     Oid         ob = *((const Oid *) b);
     799             : 
     800    57238104 :     return pg_cmp_u32(oa, ob);
     801             : }

Generated by: LCOV version 1.14