PostgreSQL Source Code git master
attoptcache.c
Go to the documentation of this file.
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-2025, 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 */
29static HTAB *AttoptCacheHash = NULL;
30
31/* attrelid and attnum form the lookup key, and must appear first */
32typedef struct
33{
35 int attnum;
37
38typedef struct
39{
40 AttoptCacheKey key; /* lookup key - must be first */
41 AttributeOpts *opts; /* options, or NULL if none */
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 */
52static void
54{
55 HASH_SEQ_STATUS status;
56 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 if (hashvalue == 0)
65 else
67
68 while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
69 {
70 if (attopt->opts)
71 pfree(attopt->opts);
73 &attopt->key,
75 NULL) == NULL)
76 elog(ERROR, "hash table corrupted");
77 }
78}
79
80/*
81 * Hash function compatible with two-arg system cache hash function.
82 */
83static uint32
84relatt_cache_syshash(const void *key, Size keysize)
85{
86 const AttoptCacheKey *ckey = key;
87
88 Assert(keysize == sizeof(*ckey));
89 return GetSysCacheHashValue2(ATTNUM, ckey->attrelid, ckey->attnum);
90}
91
92/*
93 * InitializeAttoptCache
94 * Initialize the attribute options cache.
95 */
96static void
98{
100
101 /* Initialize the hash table. */
102 ctl.keysize = sizeof(AttoptCacheKey);
103 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 */
111
113 hash_create("Attopt cache", 256, &ctl,
115
116 /* Make sure we've initialized CacheMemoryContext. */
119
120 /* Watch for invalidation events. */
123 (Datum) 0);
124}
125
126/*
127 * get_attribute_options
128 * Fetch attribute options for a specified table OID.
129 */
132{
134 AttoptCacheEntry *attopt;
135 AttributeOpts *result;
136 HeapTuple tp;
137
138 /* Find existing cache entry, if any. */
139 if (!AttoptCacheHash)
141 memset(&key, 0, sizeof(key)); /* make sure any padding bits are unset */
142 key.attrelid = attrelid;
143 key.attnum = attnum;
144 attopt =
146 &key,
147 HASH_FIND,
148 NULL);
149
150 /* Not found in Attopt cache. Construct new cache entry. */
151 if (!attopt)
152 {
154
155 tp = SearchSysCache2(ATTNUM,
156 ObjectIdGetDatum(attrelid),
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 if (!HeapTupleIsValid(tp))
165 opts = NULL;
166 else
167 {
168 Datum datum;
169 bool isNull;
170
171 datum = SysCacheGetAttr(ATTNUM,
172 tp,
173 Anum_pg_attribute_attoptions,
174 &isNull);
175 if (isNull)
176 opts = NULL;
177 else
178 {
179 bytea *bytea_opts = attribute_reloptions(datum, false);
180
182 VARSIZE(bytea_opts));
183 memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
184 }
185 ReleaseSysCache(tp);
186 }
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 */
193 &key,
195 NULL);
196 attopt->opts = opts;
197 }
198
199 /* Return results in caller's memory context. */
200 if (attopt->opts == NULL)
201 return NULL;
202 result = palloc(VARSIZE(attopt->opts));
203 memcpy(result, attopt->opts, VARSIZE(attopt->opts));
204 return result;
205}
static uint32 relatt_cache_syshash(const void *key, Size keysize)
Definition: attoptcache.c:84
AttributeOpts * get_attribute_options(Oid attrelid, int attnum)
Definition: attoptcache.c:131
static HTAB * AttoptCacheHash
Definition: attoptcache.c:29
static void InvalidateAttoptCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: attoptcache.c:53
static void InitializeAttoptCache(void)
Definition: attoptcache.c:97
#define Assert(condition)
Definition: c.h:815
uint32_t uint32
Definition: c.h:488
size_t Size
Definition: c.h:562
void CreateCacheMemoryContext(void)
Definition: catcache.c:708
void hash_seq_init_with_hash_value(HASH_SEQ_STATUS *status, HTAB *hashp, uint32 hashvalue)
Definition: dynahash.c:1405
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1420
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_FUNCTION
Definition: hsearch.h:98
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1707
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
static AmcheckOptions opts
Definition: pg_amcheck.c:112
int16 attnum
Definition: pg_attribute.h:74
void * arg
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
unsigned int Oid
Definition: postgres_ext.h:32
tree ctl
Definition: radixtree.h:1838
bytea * attribute_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:2092
AttributeOpts * opts
Definition: attoptcache.c:41
AttoptCacheKey key
Definition: attoptcache.c:40
Definition: dynahash.c:220
Definition: c.h:644
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232
#define GetSysCacheHashValue2(cacheId, key1, key2)
Definition: syscache.h:120
#define VARSIZE(PTR)
Definition: varatt.h:279