LCOV - code coverage report
Current view: top level - src/backend/utils/cache - syscache.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 93.5 % 185 173
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 27 27
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 67.4 % 92 62

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

Generated by: LCOV version 2.0-1