1 /*-------------------------------------------------------------------------
4 * Attribute options cache management.
6 * Attribute options are cached separately from the fixed-size portion of
7 * pg_attribute entries, which are handled by the relcache.
9 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
13 * src/backend/utils/cache/attoptcache.c
15 *-------------------------------------------------------------------------
19 #include "access/reloptions.h"
20 #include "catalog/pg_attribute.h"
21 #include "utils/attoptcache.h"
22 #include "utils/catcache.h"
23 #include "utils/hsearch.h"
24 #include "utils/inval.h"
25 #include "utils/rel.h"
26 #include "utils/syscache.h"
29 /* Hash table for informations about each attribute's options */
30 static HTAB *AttoptCacheHash = NULL;
32 /* attrelid and attnum form the lookup key, and must appear first */
41 AttoptCacheKey key; /* lookup key - must be first */
42 AttributeOpts *opts; /* options, or NULL if none */
47 * InvalidateAttoptCacheCallback
48 * Flush all cache entries when pg_attribute is updated.
50 * When pg_attribute is updated, we must flush the cache entry at least
51 * for that attribute. Currently, we just flush them all. Since attribute
52 * options are not currently used in performance-critical paths (such as
53 * query execution), this seems OK.
56 InvalidateAttoptCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
58 HASH_SEQ_STATUS status;
59 AttoptCacheEntry *attopt;
61 hash_seq_init(&status, AttoptCacheHash);
62 while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
66 if (hash_search(AttoptCacheHash,
67 (void *) &attopt->key,
70 elog(ERROR, "hash table corrupted");
75 * InitializeAttoptCache
76 * Initialize the tablespace cache.
79 InitializeAttoptCache(void)
83 /* Initialize the hash table. */
84 MemSet(&ctl, 0, sizeof(ctl));
85 ctl.keysize = sizeof(AttoptCacheKey);
86 ctl.entrysize = sizeof(AttoptCacheEntry);
89 hash_create("Attopt cache", 256, &ctl,
90 HASH_ELEM | HASH_FUNCTION);
92 /* Make sure we've initialized CacheMemoryContext. */
93 if (!CacheMemoryContext)
94 CreateCacheMemoryContext();
96 /* Watch for invalidation events. */
97 CacheRegisterSyscacheCallback(ATTNUM,
98 InvalidateAttoptCacheCallback,
103 * get_attribute_options
104 * Fetch attribute options for a specified table OID.
107 get_attribute_options(Oid attrelid, int attnum)
110 AttoptCacheEntry *attopt;
111 AttributeOpts *result;
114 /* Find existing cache entry, if any. */
115 if (!AttoptCacheHash)
116 InitializeAttoptCache();
117 memset(&key, 0, sizeof(key)); /* make sure any padding bits are
119 key.attrelid = attrelid;
122 (AttoptCacheEntry *) hash_search(AttoptCacheHash,
127 /* Not found in Attopt cache. Construct new cache entry. */
132 tp = SearchSysCache2(ATTNUM,
133 ObjectIdGetDatum(attrelid),
134 Int16GetDatum(attnum));
137 * If we don't find a valid HeapTuple, it must mean someone has
138 * managed to request attribute details for a non-existent attribute.
139 * We treat that case as if no options were specified.
141 if (!HeapTupleIsValid(tp))
148 datum = SysCacheGetAttr(ATTNUM,
150 Anum_pg_attribute_attoptions,
156 bytea *bytea_opts = attribute_reloptions(datum, false);
158 opts = MemoryContextAlloc(CacheMemoryContext,
159 VARSIZE(bytea_opts));
160 memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
166 * It's important to create the actual cache entry only after reading
167 * pg_attribute, since the read could cause a cache flush.
169 attopt = (AttoptCacheEntry *) hash_search(AttoptCacheHash,
176 /* Return results in caller's memory context. */
177 if (attopt->opts == NULL)
179 result = palloc(VARSIZE(attopt->opts));
180 memcpy(result, attopt->opts, VARSIZE(attopt->opts));