LCOV - differential code coverage report
Current view: top level - src/backend/utils/cache - attoptcache.c (source / functions) Coverage Total Hit LBC UIC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 95.5 % 44 42 1 1 23 1 18 2 20 3
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 3 3 3 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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 all cache 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.  Currently, we just flush them all.  Since attribute
      51                 :  * options are not currently used in performance-critical paths (such as
      52                 :  * query execution), this seems OK.
      53                 :  */
      54                 : static void
      55 GIC      358802 : InvalidateAttoptCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
      56 ECB             : {
      57                 :     HASH_SEQ_STATUS status;
      58                 :     AttoptCacheEntry *attopt;
      59                 : 
      60 GIC      358802 :     hash_seq_init(&status, AttoptCacheHash);
      61 CBC      363678 :     while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
      62 ECB             :     {
      63 GIC        4876 :         if (attopt->opts)
      64 CBC           3 :             pfree(attopt->opts);
      65            4876 :         if (hash_search(AttoptCacheHash,
      66 GNC        4876 :                         &attopt->key,
      67 ECB             :                         HASH_REMOVE,
      68                 :                         NULL) == NULL)
      69 UIC           0 :             elog(ERROR, "hash table corrupted");
      70 EUB             :     }
      71 GIC      358802 : }
      72 ECB             : 
      73                 : /*
      74                 :  * InitializeAttoptCache
      75                 :  *      Initialize the attribute options cache.
      76                 :  */
      77                 : static void
      78 GIC         492 : InitializeAttoptCache(void)
      79 ECB             : {
      80                 :     HASHCTL     ctl;
      81                 : 
      82                 :     /* Initialize the hash table. */
      83 GIC         492 :     ctl.keysize = sizeof(AttoptCacheKey);
      84 CBC         492 :     ctl.entrysize = sizeof(AttoptCacheEntry);
      85             492 :     AttoptCacheHash =
      86             492 :         hash_create("Attopt cache", 256, &ctl,
      87 ECB             :                     HASH_ELEM | HASH_BLOBS);
      88                 : 
      89                 :     /* Make sure we've initialized CacheMemoryContext. */
      90 GIC         492 :     if (!CacheMemoryContext)
      91 LBC           0 :         CreateCacheMemoryContext();
      92 EUB             : 
      93                 :     /* Watch for invalidation events. */
      94 GIC         492 :     CacheRegisterSyscacheCallback(ATTNUM,
      95 ECB             :                                   InvalidateAttoptCacheCallback,
      96                 :                                   (Datum) 0);
      97 GIC         492 : }
      98 ECB             : 
      99                 : /*
     100                 :  * get_attribute_options
     101                 :  *      Fetch attribute options for a specified table OID.
     102                 :  */
     103                 : AttributeOpts *
     104 GIC      139108 : get_attribute_options(Oid attrelid, int attnum)
     105 ECB             : {
     106                 :     AttoptCacheKey key;
     107                 :     AttoptCacheEntry *attopt;
     108                 :     AttributeOpts *result;
     109                 :     HeapTuple   tp;
     110                 : 
     111                 :     /* Find existing cache entry, if any. */
     112 GIC      139108 :     if (!AttoptCacheHash)
     113 CBC         492 :         InitializeAttoptCache();
     114          139108 :     memset(&key, 0, sizeof(key));   /* make sure any padding bits are unset */
     115          139108 :     key.attrelid = attrelid;
     116          139108 :     key.attnum = attnum;
     117 ECB             :     attopt =
     118 GIC      139108 :         (AttoptCacheEntry *) hash_search(AttoptCacheHash,
     119                 :                                          &key,
     120                 :                                          HASH_FIND,
     121                 :                                          NULL);
     122                 : 
     123                 :     /* Not found in Attopt cache.  Construct new cache entry. */
     124          139108 :     if (!attopt)
     125 ECB             :     {
     126                 :         AttributeOpts *opts;
     127                 : 
     128 GIC      138441 :         tp = SearchSysCache2(ATTNUM,
     129 ECB             :                              ObjectIdGetDatum(attrelid),
     130                 :                              Int16GetDatum(attnum));
     131                 : 
     132                 :         /*
     133                 :          * If we don't find a valid HeapTuple, it must mean someone has
     134                 :          * managed to request attribute details for a non-existent attribute.
     135                 :          * We treat that case as if no options were specified.
     136                 :          */
     137 GIC      138441 :         if (!HeapTupleIsValid(tp))
     138 CBC          48 :             opts = NULL;
     139 ECB             :         else
     140                 :         {
     141                 :             Datum       datum;
     142                 :             bool        isNull;
     143                 : 
     144 GIC      138393 :             datum = SysCacheGetAttr(ATTNUM,
     145 ECB             :                                     tp,
     146                 :                                     Anum_pg_attribute_attoptions,
     147                 :                                     &isNull);
     148 GIC      138393 :             if (isNull)
     149 CBC      138390 :                 opts = NULL;
     150 ECB             :             else
     151                 :             {
     152 GIC           3 :                 bytea      *bytea_opts = attribute_reloptions(datum, false);
     153 ECB             : 
     154 GIC           3 :                 opts = MemoryContextAlloc(CacheMemoryContext,
     155 CBC           3 :                                           VARSIZE(bytea_opts));
     156               3 :                 memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
     157 ECB             :             }
     158 GIC      138393 :             ReleaseSysCache(tp);
     159 ECB             :         }
     160                 : 
     161                 :         /*
     162                 :          * It's important to create the actual cache entry only after reading
     163                 :          * pg_attribute, since the read could cause a cache flush.
     164                 :          */
     165 GIC      138441 :         attopt = (AttoptCacheEntry *) hash_search(AttoptCacheHash,
     166                 :                                                   &key,
     167                 :                                                   HASH_ENTER,
     168                 :                                                   NULL);
     169          138441 :         attopt->opts = opts;
     170 ECB             :     }
     171                 : 
     172                 :     /* Return results in caller's memory context. */
     173 GIC      139108 :     if (attopt->opts == NULL)
     174 CBC      139105 :         return NULL;
     175               3 :     result = palloc(VARSIZE(attopt->opts));
     176               3 :     memcpy(result, attopt->opts, VARSIZE(attopt->opts));
     177               3 :     return result;
     178 ECB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a