Age Owner 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
4254 tgl 55 GIC 358802 : InvalidateAttoptCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
4825 rhaas 56 ECB : {
57 : HASH_SEQ_STATUS status;
58 : AttoptCacheEntry *attopt;
59 :
4825 rhaas 60 GIC 358802 : hash_seq_init(&status, AttoptCacheHash);
4825 rhaas 61 CBC 363678 : while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
4825 rhaas 62 ECB : {
4825 rhaas 63 GIC 4876 : if (attopt->opts)
4825 rhaas 64 CBC 3 : pfree(attopt->opts);
65 4876 : if (hash_search(AttoptCacheHash,
62 peter 66 GNC 4876 : &attopt->key,
4825 rhaas 67 ECB : HASH_REMOVE,
68 : NULL) == NULL)
4825 rhaas 69 UIC 0 : elog(ERROR, "hash table corrupted");
4825 rhaas 70 EUB : }
4825 rhaas 71 GIC 358802 : }
4825 rhaas 72 ECB :
73 : /*
74 : * InitializeAttoptCache
75 : * Initialize the attribute options cache.
76 : */
77 : static void
4825 rhaas 78 GIC 492 : InitializeAttoptCache(void)
4825 rhaas 79 ECB : {
80 : HASHCTL ctl;
81 :
82 : /* Initialize the hash table. */
4825 rhaas 83 GIC 492 : ctl.keysize = sizeof(AttoptCacheKey);
4825 rhaas 84 CBC 492 : ctl.entrysize = sizeof(AttoptCacheEntry);
85 492 : AttoptCacheHash =
86 492 : hash_create("Attopt cache", 256, &ctl,
3034 tgl 87 ECB : HASH_ELEM | HASH_BLOBS);
88 :
89 : /* Make sure we've initialized CacheMemoryContext. */
4825 rhaas 90 GIC 492 : if (!CacheMemoryContext)
4825 rhaas 91 LBC 0 : CreateCacheMemoryContext();
4825 rhaas 92 EUB :
93 : /* Watch for invalidation events. */
4825 rhaas 94 GIC 492 : CacheRegisterSyscacheCallback(ATTNUM,
4825 rhaas 95 ECB : InvalidateAttoptCacheCallback,
96 : (Datum) 0);
4825 rhaas 97 GIC 492 : }
4825 rhaas 98 ECB :
99 : /*
100 : * get_attribute_options
101 : * Fetch attribute options for a specified table OID.
102 : */
103 : AttributeOpts *
4825 rhaas 104 GIC 139108 : get_attribute_options(Oid attrelid, int attnum)
4825 rhaas 105 ECB : {
106 : AttoptCacheKey key;
107 : AttoptCacheEntry *attopt;
108 : AttributeOpts *result;
109 : HeapTuple tp;
110 :
111 : /* Find existing cache entry, if any. */
4825 rhaas 112 GIC 139108 : if (!AttoptCacheHash)
4825 rhaas 113 CBC 492 : InitializeAttoptCache();
2118 tgl 114 139108 : memset(&key, 0, sizeof(key)); /* make sure any padding bits are unset */
4825 rhaas 115 139108 : key.attrelid = attrelid;
116 139108 : key.attnum = attnum;
4825 rhaas 117 ECB : attopt =
4825 rhaas 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)
4825 rhaas 125 ECB : {
126 : AttributeOpts *opts;
127 :
4802 rhaas 128 GIC 138441 : tp = SearchSysCache2(ATTNUM,
4802 rhaas 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 : */
4825 rhaas 137 GIC 138441 : if (!HeapTupleIsValid(tp))
4825 rhaas 138 CBC 48 : opts = NULL;
4825 rhaas 139 ECB : else
140 : {
141 : Datum datum;
142 : bool isNull;
143 :
4825 rhaas 144 GIC 138393 : datum = SysCacheGetAttr(ATTNUM,
4825 rhaas 145 ECB : tp,
146 : Anum_pg_attribute_attoptions,
147 : &isNull);
4825 rhaas 148 GIC 138393 : if (isNull)
4825 rhaas 149 CBC 138390 : opts = NULL;
4825 rhaas 150 ECB : else
151 : {
4790 bruce 152 GIC 3 : bytea *bytea_opts = attribute_reloptions(datum, false);
4790 bruce 153 ECB :
4825 rhaas 154 GIC 3 : opts = MemoryContextAlloc(CacheMemoryContext,
4825 rhaas 155 CBC 3 : VARSIZE(bytea_opts));
156 3 : memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
4825 rhaas 157 ECB : }
4825 rhaas 158 GIC 138393 : ReleaseSysCache(tp);
4825 rhaas 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 : */
4825 rhaas 165 GIC 138441 : attopt = (AttoptCacheEntry *) hash_search(AttoptCacheHash,
166 : &key,
167 : HASH_ENTER,
168 : NULL);
169 138441 : attopt->opts = opts;
4825 rhaas 170 ECB : }
171 :
172 : /* Return results in caller's memory context. */
4825 rhaas 173 GIC 139108 : if (attopt->opts == NULL)
4825 rhaas 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;
4825 rhaas 178 ECB : }
|