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