LCOV - code coverage report
Current view: top level - src/backend/utils/cache - syscache.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 172 186 92.5 %
Date: 2024-11-21 08:14:44 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       31284 : InitCatalogCache(void)
     111             : {
     112             :     int         cacheId;
     113             : 
     114             :     Assert(!CacheInitialized);
     115             : 
     116       31284 :     SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0;
     117             : 
     118     2690424 :     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     5318280 :         SysCache[cacheId] = InitCatCache(cacheId,
     129             :                                          cacheinfo[cacheId].reloid,
     130             :                                          cacheinfo[cacheId].indoid,
     131             :                                          cacheinfo[cacheId].nkeys,
     132     2659140 :                                          cacheinfo[cacheId].key,
     133             :                                          cacheinfo[cacheId].nbuckets);
     134     2659140 :         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     2659140 :         SysCacheRelationOid[SysCacheRelationOidSize++] =
     139     2659140 :             cacheinfo[cacheId].reloid;
     140     2659140 :         SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
     141     2659140 :             cacheinfo[cacheId].reloid;
     142     2659140 :         SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
     143     2659140 :             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       31284 :     qsort(SysCacheRelationOid, SysCacheRelationOidSize,
     153             :           sizeof(Oid), oid_compare);
     154       31284 :     SysCacheRelationOidSize =
     155       31284 :         qunique(SysCacheRelationOid, SysCacheRelationOidSize, sizeof(Oid),
     156             :                 oid_compare);
     157             : 
     158       31284 :     qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
     159             :           sizeof(Oid), oid_compare);
     160       31284 :     SysCacheSupportingRelOidSize =
     161       31284 :         qunique(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
     162             :                 sizeof(Oid), oid_compare);
     163             : 
     164       31284 :     CacheInitialized = true;
     165       31284 : }
     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        2776 : InitCatalogCachePhase2(void)
     181             : {
     182             :     int         cacheId;
     183             : 
     184             :     Assert(CacheInitialized);
     185             : 
     186      238622 :     for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
     187      235852 :         InitCatCachePhase2(SysCache[cacheId], true);
     188        2770 : }
     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     5053162 : 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     5053162 :     return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
     218             : }
     219             : 
     220             : HeapTuple
     221    62360006 : 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    62360006 :     return SearchCatCache1(SysCache[cacheId], key1);
     229             : }
     230             : 
     231             : HeapTuple
     232     4996478 : 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     4996478 :     return SearchCatCache2(SysCache[cacheId], key1, key2);
     240             : }
     241             : 
     242             : HeapTuple
     243     4755000 : 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     4755000 :     return SearchCatCache3(SysCache[cacheId], key1, key2, key3);
     251             : }
     252             : 
     253             : HeapTuple
     254     3906266 : 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     3906266 :     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    75739388 : ReleaseSysCache(HeapTuple tuple)
     270             : {
     271    75739388 :     ReleaseCatCache(tuple);
     272    75739388 : }
     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       43260 : SearchSysCacheLocked1(int cacheId,
     288             :                       Datum key1)
     289             : {
     290             :     ItemPointerData tid;
     291             :     LOCKTAG     tag;
     292       43260 :     Oid         dboid =
     293       43260 :         SysCache[cacheId]->cc_relisshared ? InvalidOid : MyDatabaseId;
     294       43260 :     Oid         reloid = cacheinfo[cacheId].reloid;
     295             : 
     296             :     /*----------
     297             :      * Since inplace updates may happen just before our LockTuple(), we must
     298             :      * return content acquired after LockTuple() of the TID we return.  If we
     299             :      * just fetched twice instead of looping, the following sequence would
     300             :      * defeat our locking:
     301             :      *
     302             :      * GRANT:   SearchSysCache1() = TID (1,5)
     303             :      * GRANT:   LockTuple(pg_class, (1,5))
     304             :      * [no more inplace update of (1,5) until we release the lock]
     305             :      * CLUSTER: SearchSysCache1() = TID (1,5)
     306             :      * CLUSTER: heap_update() = TID (1,8)
     307             :      * CLUSTER: COMMIT
     308             :      * GRANT:   SearchSysCache1() = TID (1,8)
     309             :      * GRANT:   return (1,8) from SearchSysCacheLocked1()
     310             :      * VACUUM:  SearchSysCache1() = TID (1,8)
     311             :      * VACUUM:  LockTuple(pg_class, (1,8))  # two TIDs now locked for one rel
     312             :      * VACUUM:  inplace update
     313             :      * GRANT:   heap_update() = (1,9)  # lose inplace update
     314             :      *
     315             :      * In the happy case, this takes two fetches, one to determine the TID to
     316             :      * lock and another to get the content and confirm the TID didn't change.
     317             :      *
     318             :      * This is valid even if the row gets updated to a new TID, the old TID
     319             :      * becomes LP_UNUSED, and the row gets updated back to its old TID.  We'd
     320             :      * still hold the right LOCKTAG_TUPLE and a copy of the row captured after
     321             :      * the LOCKTAG_TUPLE.
     322             :      */
     323       43260 :     ItemPointerSetInvalid(&tid);
     324             :     for (;;)
     325       43262 :     {
     326             :         HeapTuple   tuple;
     327       86522 :         LOCKMODE    lockmode = InplaceUpdateTupleLock;
     328             : 
     329       86522 :         tuple = SearchSysCache1(cacheId, key1);
     330       86522 :         if (ItemPointerIsValid(&tid))
     331             :         {
     332       43262 :             if (!HeapTupleIsValid(tuple))
     333             :             {
     334           0 :                 LockRelease(&tag, lockmode, false);
     335           0 :                 return tuple;
     336             :             }
     337       43262 :             if (ItemPointerEquals(&tid, &tuple->t_self))
     338       43260 :                 return tuple;
     339           2 :             LockRelease(&tag, lockmode, false);
     340             :         }
     341       43260 :         else if (!HeapTupleIsValid(tuple))
     342           0 :             return tuple;
     343             : 
     344       43262 :         tid = tuple->t_self;
     345       43262 :         ReleaseSysCache(tuple);
     346             :         /* like: LockTuple(rel, &tid, lockmode) */
     347       43262 :         SET_LOCKTAG_TUPLE(tag, dboid, reloid,
     348             :                           ItemPointerGetBlockNumber(&tid),
     349             :                           ItemPointerGetOffsetNumber(&tid));
     350       43262 :         (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       43262 :         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      442864 : SearchSysCacheCopy(int cacheId,
     375             :                    Datum key1,
     376             :                    Datum key2,
     377             :                    Datum key3,
     378             :                    Datum key4)
     379             : {
     380             :     HeapTuple   tuple,
     381             :                 newtuple;
     382             : 
     383      442864 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     384      442864 :     if (!HeapTupleIsValid(tuple))
     385      129626 :         return tuple;
     386      313238 :     newtuple = heap_copytuple(tuple);
     387      313238 :     ReleaseSysCache(tuple);
     388      313238 :     return newtuple;
     389             : }
     390             : 
     391             : /*
     392             :  * SearchSysCacheLockedCopy1
     393             :  *
     394             :  * Meld SearchSysCacheLockedCopy1 with SearchSysCacheCopy().  After the
     395             :  * caller's heap_update(), it should UnlockTuple(InplaceUpdateTupleLock) and
     396             :  * heap_freetuple().
     397             :  */
     398             : HeapTuple
     399       15770 : SearchSysCacheLockedCopy1(int cacheId,
     400             :                           Datum key1)
     401             : {
     402             :     HeapTuple   tuple,
     403             :                 newtuple;
     404             : 
     405       15770 :     tuple = SearchSysCacheLocked1(cacheId, key1);
     406       15770 :     if (!HeapTupleIsValid(tuple))
     407           0 :         return tuple;
     408       15770 :     newtuple = heap_copytuple(tuple);
     409       15770 :     ReleaseSysCache(tuple);
     410       15770 :     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     1234154 : SearchSysCacheExists(int cacheId,
     421             :                      Datum key1,
     422             :                      Datum key2,
     423             :                      Datum key3,
     424             :                      Datum key4)
     425             : {
     426             :     HeapTuple   tuple;
     427             : 
     428     1234154 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     429     1234154 :     if (!HeapTupleIsValid(tuple))
     430      222508 :         return false;
     431     1011646 :     ReleaseSysCache(tuple);
     432     1011646 :     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     3376144 : 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     3376144 :     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     455     3376144 :     if (!HeapTupleIsValid(tuple))
     456     1355550 :         return InvalidOid;
     457     4041188 :     result = heap_getattr(tuple, oidcol,
     458     2020594 :                           SysCache[cacheId]->cc_tupdesc,
     459             :                           &isNull);
     460             :     Assert(!isNull);            /* columns used as oids should never be NULL */
     461     2020594 :     ReleaseSysCache(tuple);
     462     2020594 :     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      101038 : SearchSysCacheAttName(Oid relid, const char *attname)
     476             : {
     477             :     HeapTuple   tuple;
     478             : 
     479      101038 :     tuple = SearchSysCache2(ATTNAME,
     480             :                             ObjectIdGetDatum(relid),
     481             :                             CStringGetDatum(attname));
     482      101038 :     if (!HeapTupleIsValid(tuple))
     483         918 :         return NULL;
     484      100120 :     if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
     485             :     {
     486          78 :         ReleaseSysCache(tuple);
     487          78 :         return NULL;
     488             :     }
     489      100042 :     return tuple;
     490             : }
     491             : 
     492             : /*
     493             :  * SearchSysCacheCopyAttName
     494             :  *
     495             :  * As above, an attisdropped-aware version of SearchSysCacheCopy.
     496             :  */
     497             : HeapTuple
     498        8530 : SearchSysCacheCopyAttName(Oid relid, const char *attname)
     499             : {
     500             :     HeapTuple   tuple,
     501             :                 newtuple;
     502             : 
     503        8530 :     tuple = SearchSysCacheAttName(relid, attname);
     504        8530 :     if (!HeapTupleIsValid(tuple))
     505         654 :         return tuple;
     506        7876 :     newtuple = heap_copytuple(tuple);
     507        7876 :     ReleaseSysCache(tuple);
     508        7876 :     return newtuple;
     509             : }
     510             : 
     511             : /*
     512             :  * SearchSysCacheExistsAttName
     513             :  *
     514             :  * As above, an attisdropped-aware version of SearchSysCacheExists.
     515             :  */
     516             : bool
     517        1014 : SearchSysCacheExistsAttName(Oid relid, const char *attname)
     518             : {
     519             :     HeapTuple   tuple;
     520             : 
     521        1014 :     tuple = SearchSysCacheAttName(relid, attname);
     522        1014 :     if (!HeapTupleIsValid(tuple))
     523          54 :         return false;
     524         960 :     ReleaseSysCache(tuple);
     525         960 :     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        1568 : SearchSysCacheAttNum(Oid relid, int16 attnum)
     539             : {
     540             :     HeapTuple   tuple;
     541             : 
     542        1568 :     tuple = SearchSysCache2(ATTNUM,
     543             :                             ObjectIdGetDatum(relid),
     544             :                             Int16GetDatum(attnum));
     545        1568 :     if (!HeapTupleIsValid(tuple))
     546          12 :         return NULL;
     547        1556 :     if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
     548             :     {
     549           0 :         ReleaseSysCache(tuple);
     550           0 :         return NULL;
     551             :     }
     552        1556 :     return tuple;
     553             : }
     554             : 
     555             : /*
     556             :  * SearchSysCacheCopyAttNum
     557             :  *
     558             :  * As above, an attisdropped-aware version of SearchSysCacheCopy.
     559             :  */
     560             : HeapTuple
     561        1504 : SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
     562             : {
     563             :     HeapTuple   tuple,
     564             :                 newtuple;
     565             : 
     566        1504 :     tuple = SearchSysCacheAttNum(relid, attnum);
     567        1504 :     if (!HeapTupleIsValid(tuple))
     568           0 :         return NULL;
     569        1504 :     newtuple = heap_copytuple(tuple);
     570        1504 :     ReleaseSysCache(tuple);
     571        1504 :     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     5042570 : 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     5042570 :     if (cacheId < 0 || cacheId >= SysCacheSize ||
     606     5042570 :         !PointerIsValid(SysCache[cacheId]))
     607           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     608     5042570 :     if (!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
     609             :     {
     610       29806 :         InitCatCachePhase2(SysCache[cacheId], false);
     611             :         Assert(PointerIsValid(SysCache[cacheId]->cc_tupdesc));
     612             :     }
     613             : 
     614    10085140 :     return heap_getattr(tup, attributeNumber,
     615     5042570 :                         SysCache[cacheId]->cc_tupdesc,
     616             :                         isNull);
     617             : }
     618             : 
     619             : /*
     620             :  * SysCacheGetAttrNotNull
     621             :  *
     622             :  * As above, a version of SysCacheGetAttr which knows that the attr cannot
     623             :  * be NULL.
     624             :  */
     625             : Datum
     626     2848016 : SysCacheGetAttrNotNull(int cacheId, HeapTuple tup,
     627             :                        AttrNumber attributeNumber)
     628             : {
     629             :     bool        isnull;
     630             :     Datum       attr;
     631             : 
     632     2848016 :     attr = SysCacheGetAttr(cacheId, tup, attributeNumber, &isnull);
     633             : 
     634     2848016 :     if (isnull)
     635             :     {
     636           0 :         elog(ERROR,
     637             :              "unexpected null value in cached tuple for catalog %s column %s",
     638             :              get_rel_name(cacheinfo[cacheId].reloid),
     639             :              NameStr(TupleDescAttr(SysCache[cacheId]->cc_tupdesc, attributeNumber - 1)->attname));
     640             :     }
     641             : 
     642     2848016 :     return attr;
     643             : }
     644             : 
     645             : /*
     646             :  * GetSysCacheHashValue
     647             :  *
     648             :  * Get the hash value that would be used for a tuple in the specified cache
     649             :  * with the given search keys.
     650             :  *
     651             :  * The reason for exposing this as part of the API is that the hash value is
     652             :  * exposed in cache invalidation operations, so there are places outside the
     653             :  * catcache code that need to be able to compute the hash values.
     654             :  */
     655             : uint32
     656      996336 : GetSysCacheHashValue(int cacheId,
     657             :                      Datum key1,
     658             :                      Datum key2,
     659             :                      Datum key3,
     660             :                      Datum key4)
     661             : {
     662      996336 :     if (cacheId < 0 || cacheId >= SysCacheSize ||
     663      996336 :         !PointerIsValid(SysCache[cacheId]))
     664           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     665             : 
     666      996336 :     return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4);
     667             : }
     668             : 
     669             : /*
     670             :  * List-search interface
     671             :  */
     672             : struct catclist *
     673     3310470 : SearchSysCacheList(int cacheId, int nkeys,
     674             :                    Datum key1, Datum key2, Datum key3)
     675             : {
     676     3310470 :     if (cacheId < 0 || cacheId >= SysCacheSize ||
     677     3310470 :         !PointerIsValid(SysCache[cacheId]))
     678           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     679             : 
     680     3310470 :     return SearchCatCacheList(SysCache[cacheId], nkeys,
     681             :                               key1, key2, key3);
     682             : }
     683             : 
     684             : /*
     685             :  * SysCacheInvalidate
     686             :  *
     687             :  *  Invalidate entries in the specified cache, given a hash value.
     688             :  *  See CatCacheInvalidate() for more info.
     689             :  *
     690             :  *  This routine is only quasi-public: it should only be used by inval.c.
     691             :  */
     692             : void
     693    19204234 : SysCacheInvalidate(int cacheId, uint32 hashValue)
     694             : {
     695    19204234 :     if (cacheId < 0 || cacheId >= SysCacheSize)
     696           0 :         elog(ERROR, "invalid cache ID: %d", cacheId);
     697             : 
     698             :     /* if this cache isn't initialized yet, no need to do anything */
     699    19204234 :     if (!PointerIsValid(SysCache[cacheId]))
     700           0 :         return;
     701             : 
     702    19204234 :     CatCacheInvalidate(SysCache[cacheId], hashValue);
     703             : }
     704             : 
     705             : /*
     706             :  * Certain relations that do not have system caches send snapshot invalidation
     707             :  * messages in lieu of catcache messages.  This is for the benefit of
     708             :  * GetCatalogSnapshot(), which can then reuse its existing MVCC snapshot
     709             :  * for scanning one of those catalogs, rather than taking a new one, if no
     710             :  * invalidation has been received.
     711             :  *
     712             :  * Relations that have syscaches need not (and must not) be listed here.  The
     713             :  * catcache invalidation messages will also flush the snapshot.  If you add a
     714             :  * syscache for one of these relations, remove it from this list.
     715             :  */
     716             : bool
     717    14228604 : RelationInvalidatesSnapshotsOnly(Oid relid)
     718             : {
     719    14228604 :     switch (relid)
     720             :     {
     721     2401130 :         case DbRoleSettingRelationId:
     722             :         case DependRelationId:
     723             :         case SharedDependRelationId:
     724             :         case DescriptionRelationId:
     725             :         case SharedDescriptionRelationId:
     726             :         case SecLabelRelationId:
     727             :         case SharedSecLabelRelationId:
     728     2401130 :             return true;
     729    11827474 :         default:
     730    11827474 :             break;
     731             :     }
     732             : 
     733    11827474 :     return false;
     734             : }
     735             : 
     736             : /*
     737             :  * Test whether a relation has a system cache.
     738             :  */
     739             : bool
     740     8928232 : RelationHasSysCache(Oid relid)
     741             : {
     742     8928232 :     int         low = 0,
     743     8928232 :                 high = SysCacheRelationOidSize - 1;
     744             : 
     745    39465162 :     while (low <= high)
     746             :     {
     747    39023620 :         int         middle = low + (high - low) / 2;
     748             : 
     749    39023620 :         if (SysCacheRelationOid[middle] == relid)
     750     8486690 :             return true;
     751    30536930 :         if (SysCacheRelationOid[middle] < relid)
     752    10621336 :             low = middle + 1;
     753             :         else
     754    19915594 :             high = middle - 1;
     755             :     }
     756             : 
     757      441542 :     return false;
     758             : }
     759             : 
     760             : /*
     761             :  * Test whether a relation supports a system cache, ie it is either a
     762             :  * cached table or the index used for a cache.
     763             :  */
     764             : bool
     765     2232176 : RelationSupportsSysCache(Oid relid)
     766             : {
     767     2232176 :     int         low = 0,
     768     2232176 :                 high = SysCacheSupportingRelOidSize - 1;
     769             : 
     770    18699190 :     while (low <= high)
     771             :     {
     772    16918072 :         int         middle = low + (high - low) / 2;
     773             : 
     774    16918072 :         if (SysCacheSupportingRelOid[middle] == relid)
     775      451058 :             return true;
     776    16467014 :         if (SysCacheSupportingRelOid[middle] < relid)
     777    14992194 :             low = middle + 1;
     778             :         else
     779     1474820 :             high = middle - 1;
     780             :     }
     781             : 
     782     1781118 :     return false;
     783             : }
     784             : 
     785             : 
     786             : /*
     787             :  * OID comparator for qsort
     788             :  */
     789             : static int
     790    61848468 : oid_compare(const void *a, const void *b)
     791             : {
     792    61848468 :     Oid         oa = *((const Oid *) a);
     793    61848468 :     Oid         ob = *((const Oid *) b);
     794             : 
     795    61848468 :     return pg_cmp_u32(oa, ob);
     796             : }

Generated by: LCOV version 1.14