]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/attoptcache.c
Update copyright for 2014
[postgresql] / src / backend / utils / cache / attoptcache.c
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-2014, 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
26
27 /* Hash table for informations about each attribute's options */
28 static HTAB *AttoptCacheHash = NULL;
29
30 /* attrelid and attnum form the lookup key, and must appear first */
31 typedef struct
32 {
33         Oid                     attrelid;
34         int                     attnum;
35 } AttoptCacheKey;
36
37 typedef struct
38 {
39         AttoptCacheKey key;                     /* lookup key - must be first */
40         AttributeOpts *opts;            /* options, or NULL if none */
41 } AttoptCacheEntry;
42
43
44 /*
45  * InvalidateAttoptCacheCallback
46  *              Flush all cache entries when pg_attribute is updated.
47  *
48  * When pg_attribute is updated, we must flush the cache entry at least
49  * for that attribute.  Currently, we just flush them all.      Since attribute
50  * options are not currently used in performance-critical paths (such as
51  * query execution), this seems OK.
52  */
53 static void
54 InvalidateAttoptCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
55 {
56         HASH_SEQ_STATUS status;
57         AttoptCacheEntry *attopt;
58
59         hash_seq_init(&status, AttoptCacheHash);
60         while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
61         {
62                 if (attopt->opts)
63                         pfree(attopt->opts);
64                 if (hash_search(AttoptCacheHash,
65                                                 (void *) &attopt->key,
66                                                 HASH_REMOVE,
67                                                 NULL) == NULL)
68                         elog(ERROR, "hash table corrupted");
69         }
70 }
71
72 /*
73  * InitializeAttoptCache
74  *              Initialize the tablespace cache.
75  */
76 static void
77 InitializeAttoptCache(void)
78 {
79         HASHCTL         ctl;
80
81         /* Initialize the hash table. */
82         MemSet(&ctl, 0, sizeof(ctl));
83         ctl.keysize = sizeof(AttoptCacheKey);
84         ctl.entrysize = sizeof(AttoptCacheEntry);
85         ctl.hash = tag_hash;
86         AttoptCacheHash =
87                 hash_create("Attopt cache", 256, &ctl,
88                                         HASH_ELEM | HASH_FUNCTION);
89
90         /* Make sure we've initialized CacheMemoryContext. */
91         if (!CacheMemoryContext)
92                 CreateCacheMemoryContext();
93
94         /* Watch for invalidation events. */
95         CacheRegisterSyscacheCallback(ATTNUM,
96                                                                   InvalidateAttoptCacheCallback,
97                                                                   (Datum) 0);
98 }
99
100 /*
101  * get_attribute_options
102  *              Fetch attribute options for a specified table OID.
103  */
104 AttributeOpts *
105 get_attribute_options(Oid attrelid, int attnum)
106 {
107         AttoptCacheKey key;
108         AttoptCacheEntry *attopt;
109         AttributeOpts *result;
110         HeapTuple       tp;
111
112         /* Find existing cache entry, if any. */
113         if (!AttoptCacheHash)
114                 InitializeAttoptCache();
115         memset(&key, 0, sizeof(key));           /* make sure any padding bits are
116                                                                                  * unset */
117         key.attrelid = attrelid;
118         key.attnum = attnum;
119         attopt =
120                 (AttoptCacheEntry *) hash_search(AttoptCacheHash,
121                                                                                  (void *) &key,
122                                                                                  HASH_FIND,
123                                                                                  NULL);
124
125         /* Not found in Attopt cache.  Construct new cache entry. */
126         if (!attopt)
127         {
128                 AttributeOpts *opts;
129
130                 tp = SearchSysCache2(ATTNUM,
131                                                          ObjectIdGetDatum(attrelid),
132                                                          Int16GetDatum(attnum));
133
134                 /*
135                  * If we don't find a valid HeapTuple, it must mean someone has
136                  * managed to request attribute details for a non-existent attribute.
137                  * We treat that case as if no options were specified.
138                  */
139                 if (!HeapTupleIsValid(tp))
140                         opts = NULL;
141                 else
142                 {
143                         Datum           datum;
144                         bool            isNull;
145
146                         datum = SysCacheGetAttr(ATTNUM,
147                                                                         tp,
148                                                                         Anum_pg_attribute_attoptions,
149                                                                         &isNull);
150                         if (isNull)
151                                 opts = NULL;
152                         else
153                         {
154                                 bytea      *bytea_opts = attribute_reloptions(datum, false);
155
156                                 opts = MemoryContextAlloc(CacheMemoryContext,
157                                                                                   VARSIZE(bytea_opts));
158                                 memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
159                         }
160                         ReleaseSysCache(tp);
161                 }
162
163                 /*
164                  * It's important to create the actual cache entry only after reading
165                  * pg_attribute, since the read could cause a cache flush.
166                  */
167                 attopt = (AttoptCacheEntry *) hash_search(AttoptCacheHash,
168                                                                                                   (void *) &key,
169                                                                                                   HASH_ENTER,
170                                                                                                   NULL);
171                 attopt->opts = opts;
172         }
173
174         /* Return results in caller's memory context. */
175         if (attopt->opts == NULL)
176                 return NULL;
177         result = palloc(VARSIZE(attopt->opts));
178         memcpy(result, attopt->opts, VARSIZE(attopt->opts));
179         return result;
180 }