LCOV - code coverage report
Current view: top level - src/backend/utils/cache - attoptcache.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 97.2 % 71 69
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 4 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 73.1 % 26 19

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * attoptcache.c
       4                 :             :  *        Attribute options cache management.
       5                 :             :  *
       6                 :             :  * Attribute options are cached separately from the fixed-size portion of
       7                 :             :  * pg_attribute entries, which are handled by the relcache.
       8                 :             :  *
       9                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      10                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      11                 :             :  *
      12                 :             :  * IDENTIFICATION
      13                 :             :  *        src/backend/utils/cache/attoptcache.c
      14                 :             :  *
      15                 :             :  *-------------------------------------------------------------------------
      16                 :             :  */
      17                 :             : #include "postgres.h"
      18                 :             : 
      19                 :             : #include "access/reloptions.h"
      20                 :             : #include "utils/attoptcache.h"
      21                 :             : #include "utils/catcache.h"
      22                 :             : #include "utils/hsearch.h"
      23                 :             : #include "utils/inval.h"
      24                 :             : #include "utils/syscache.h"
      25                 :             : #include "varatt.h"
      26                 :             : 
      27                 :             : 
      28                 :             : /* Hash table for information about each attribute's options */
      29                 :             : static HTAB *AttoptCacheHash = NULL;
      30                 :             : 
      31                 :             : /* attrelid and attnum form the lookup key, and must appear first */
      32                 :             : typedef struct
      33                 :             : {
      34                 :             :         Oid                     attrelid;
      35                 :             :         int                     attnum;
      36                 :             : } AttoptCacheKey;
      37                 :             : 
      38                 :             : typedef struct
      39                 :             : {
      40                 :             :         AttoptCacheKey key;                     /* lookup key - must be first */
      41                 :             :         AttributeOpts *opts;            /* options, or NULL if none */
      42                 :             : } AttoptCacheEntry;
      43                 :             : 
      44                 :             : 
      45                 :             : /*
      46                 :             :  * InvalidateAttoptCacheCallback
      47                 :             :  *              Flush cache entry (or entries) when pg_attribute is updated.
      48                 :             :  *
      49                 :             :  * When pg_attribute is updated, we must flush the cache entry at least
      50                 :             :  * for that attribute.
      51                 :             :  */
      52                 :             : static void
      53                 :      161145 : InvalidateAttoptCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
      54                 :             : {
      55                 :      161145 :         HASH_SEQ_STATUS status;
      56                 :      161145 :         AttoptCacheEntry *attopt;
      57                 :             : 
      58                 :             :         /*
      59                 :             :          * By convention, zero hash value is passed to the callback as a sign that
      60                 :             :          * it's time to invalidate the whole cache. See sinval.c, inval.c and
      61                 :             :          * InvalidateSystemCachesExtended().
      62                 :             :          */
      63         [ +  + ]:      161145 :         if (hashvalue == 0)
      64                 :          19 :                 hash_seq_init(&status, AttoptCacheHash);
      65                 :             :         else
      66                 :      161126 :                 hash_seq_init_with_hash_value(&status, AttoptCacheHash, hashvalue);
      67                 :             : 
      68         [ +  + ]:      161881 :         while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
      69                 :             :         {
      70         [ +  + ]:         736 :                 if (attopt->opts)
      71                 :           1 :                         pfree(attopt->opts);
      72                 :        1472 :                 if (hash_search(AttoptCacheHash,
      73                 :         736 :                                                 &attopt->key,
      74                 :             :                                                 HASH_REMOVE,
      75         [ +  - ]:         736 :                                                 NULL) == NULL)
      76   [ #  #  #  # ]:           0 :                         elog(ERROR, "hash table corrupted");
      77                 :             :         }
      78                 :      161145 : }
      79                 :             : 
      80                 :             : /*
      81                 :             :  * Hash function compatible with two-arg system cache hash function.
      82                 :             :  */
      83                 :             : static uint32
      84                 :        4932 : relatt_cache_syshash(const void *key, Size keysize)
      85                 :             : {
      86                 :        4932 :         const AttoptCacheKey *ckey = key;
      87                 :             : 
      88         [ +  - ]:        4932 :         Assert(keysize == sizeof(*ckey));
      89                 :        9864 :         return GetSysCacheHashValue2(ATTNUM, ObjectIdGetDatum(ckey->attrelid), Int32GetDatum(ckey->attnum));
      90                 :        4932 : }
      91                 :             : 
      92                 :             : /*
      93                 :             :  * InitializeAttoptCache
      94                 :             :  *              Initialize the attribute options cache.
      95                 :             :  */
      96                 :             : static void
      97                 :          61 : InitializeAttoptCache(void)
      98                 :             : {
      99                 :          61 :         HASHCTL         ctl;
     100                 :             : 
     101                 :             :         /* Initialize the hash table. */
     102                 :          61 :         ctl.keysize = sizeof(AttoptCacheKey);
     103                 :          61 :         ctl.entrysize = sizeof(AttoptCacheEntry);
     104                 :             : 
     105                 :             :         /*
     106                 :             :          * AttoptCacheEntry takes hash value from the system cache. For
     107                 :             :          * AttoptCacheHash we use the same hash in order to speedup search by hash
     108                 :             :          * value. This is used by hash_seq_init_with_hash_value().
     109                 :             :          */
     110                 :          61 :         ctl.hash = relatt_cache_syshash;
     111                 :             : 
     112                 :          61 :         AttoptCacheHash =
     113                 :          61 :                 hash_create("Attopt cache", 256, &ctl,
     114                 :             :                                         HASH_ELEM | HASH_FUNCTION);
     115                 :             : 
     116                 :             :         /* Make sure we've initialized CacheMemoryContext. */
     117         [ +  - ]:          61 :         if (!CacheMemoryContext)
     118                 :           0 :                 CreateCacheMemoryContext();
     119                 :             : 
     120                 :             :         /* Watch for invalidation events. */
     121                 :          61 :         CacheRegisterSyscacheCallback(ATTNUM,
     122                 :             :                                                                   InvalidateAttoptCacheCallback,
     123                 :             :                                                                   (Datum) 0);
     124                 :          61 : }
     125                 :             : 
     126                 :             : /*
     127                 :             :  * get_attribute_options
     128                 :             :  *              Fetch attribute options for a specified table OID.
     129                 :             :  */
     130                 :             : AttributeOpts *
     131                 :        2471 : get_attribute_options(Oid attrelid, int attnum)
     132                 :             : {
     133                 :        2471 :         AttoptCacheKey key;
     134                 :        2471 :         AttoptCacheEntry *attopt;
     135                 :        2471 :         AttributeOpts *result;
     136                 :        2471 :         HeapTuple       tp;
     137                 :             : 
     138                 :             :         /* Find existing cache entry, if any. */
     139         [ +  + ]:        2471 :         if (!AttoptCacheHash)
     140                 :          61 :                 InitializeAttoptCache();
     141                 :        2471 :         memset(&key, 0, sizeof(key));       /* make sure any padding bits are unset */
     142                 :        2471 :         key.attrelid = attrelid;
     143                 :        2471 :         key.attnum = attnum;
     144                 :        2471 :         attopt =
     145                 :        2471 :                 (AttoptCacheEntry *) hash_search(AttoptCacheHash,
     146                 :             :                                                                                  &key,
     147                 :             :                                                                                  HASH_FIND,
     148                 :             :                                                                                  NULL);
     149                 :             : 
     150                 :             :         /* Not found in Attopt cache.  Construct new cache entry. */
     151         [ +  + ]:        2471 :         if (!attopt)
     152                 :             :         {
     153                 :        1725 :                 AttributeOpts *opts;
     154                 :             : 
     155                 :        1725 :                 tp = SearchSysCache2(ATTNUM,
     156                 :        1725 :                                                          ObjectIdGetDatum(attrelid),
     157                 :        1725 :                                                          Int16GetDatum(attnum));
     158                 :             : 
     159                 :             :                 /*
     160                 :             :                  * If we don't find a valid HeapTuple, it must mean someone has
     161                 :             :                  * managed to request attribute details for a non-existent attribute.
     162                 :             :                  * We treat that case as if no options were specified.
     163                 :             :                  */
     164         [ +  + ]:        1725 :                 if (!HeapTupleIsValid(tp))
     165                 :          12 :                         opts = NULL;
     166                 :             :                 else
     167                 :             :                 {
     168                 :        1713 :                         Datum           datum;
     169                 :        1713 :                         bool            isNull;
     170                 :             : 
     171                 :        1713 :                         datum = SysCacheGetAttr(ATTNUM,
     172                 :        1713 :                                                                         tp,
     173                 :             :                                                                         Anum_pg_attribute_attoptions,
     174                 :             :                                                                         &isNull);
     175         [ +  + ]:        1713 :                         if (isNull)
     176                 :        1712 :                                 opts = NULL;
     177                 :             :                         else
     178                 :             :                         {
     179                 :           1 :                                 bytea      *bytea_opts = attribute_reloptions(datum, false);
     180                 :             : 
     181                 :           2 :                                 opts = MemoryContextAlloc(CacheMemoryContext,
     182                 :           1 :                                                                                   VARSIZE(bytea_opts));
     183                 :           1 :                                 memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
     184                 :           1 :                         }
     185                 :        1713 :                         ReleaseSysCache(tp);
     186                 :        1713 :                 }
     187                 :             : 
     188                 :             :                 /*
     189                 :             :                  * It's important to create the actual cache entry only after reading
     190                 :             :                  * pg_attribute, since the read could cause a cache flush.
     191                 :             :                  */
     192                 :        1725 :                 attopt = (AttoptCacheEntry *) hash_search(AttoptCacheHash,
     193                 :             :                                                                                                   &key,
     194                 :             :                                                                                                   HASH_ENTER,
     195                 :             :                                                                                                   NULL);
     196                 :        1725 :                 attopt->opts = opts;
     197                 :        1725 :         }
     198                 :             : 
     199                 :             :         /* Return results in caller's memory context. */
     200         [ +  + ]:        2471 :         if (attopt->opts == NULL)
     201                 :        2470 :                 return NULL;
     202                 :           1 :         result = palloc(VARSIZE(attopt->opts));
     203                 :           1 :         memcpy(result, attopt->opts, VARSIZE(attopt->opts));
     204                 :           1 :         return result;
     205                 :        2471 : }
        

Generated by: LCOV version 2.3.2-1