~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/backend/utils/cache/attoptcache.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-2011, 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
}