]> granicus.if.org Git - postgresql/commitdiff
Fix several oversights in previous commit - attribute options patch.
authorRobert Haas <rhaas@postgresql.org>
Fri, 22 Jan 2010 16:42:31 +0000 (16:42 +0000)
committerRobert Haas <rhaas@postgresql.org>
Fri, 22 Jan 2010 16:42:31 +0000 (16:42 +0000)
I failed to 'cvs add' the new files and also neglected to bump catversion.

src/backend/utils/cache/attoptcache.c [new file with mode: 0644]
src/include/catalog/catversion.h
src/include/utils/attoptcache.h [new file with mode: 0644]

diff --git a/src/backend/utils/cache/attoptcache.c b/src/backend/utils/cache/attoptcache.c
new file mode 100644 (file)
index 0000000..f553655
--- /dev/null
@@ -0,0 +1,181 @@
+/*-------------------------------------------------------------------------
+ *
+ * attoptcache.c
+ *       Attribute options cache management.
+ *
+ * Attribute options are cached separately from the fixed-size portion of
+ * pg_attribute entries, which are handled by the relcache.
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/attoptcache.c,v 1.1 2010/01/22 16:42:31 rhaas Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/reloptions.h"
+#include "catalog/pg_attribute.h"
+#include "utils/attoptcache.h"
+#include "utils/catcache.h"
+#include "utils/hsearch.h"
+#include "utils/inval.h"
+#include "utils/rel.h"
+#include "utils/syscache.h"
+
+
+/* Hash table for informations about each attribute's options */
+static HTAB *AttoptCacheHash = NULL;
+
+/* attrelid and attnum form the lookup key, and must appear first */
+typedef struct
+{
+       Oid                     attrelid;
+       int                     attnum;
+} AttoptCacheKey;
+
+typedef struct
+{
+       AttoptCacheKey key;                     /* lookup key - must be first */
+       AttributeOpts *opts;            /* options, or NULL if none */
+} AttoptCacheEntry;
+
+
+/*
+ * InvalidateAttoptCacheCallback
+ *             Flush all cache entries when pg_attribute is updated.
+ *
+ * When pg_attribute is updated, we must flush the cache entry at least
+ * for that attribute.  Currently, we just flush them all.  Since attribute
+ * options are not currently used in performance-critical paths (such as
+ * query execution), this seems OK.
+ */
+static void
+InvalidateAttoptCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
+{
+       HASH_SEQ_STATUS status;
+       AttoptCacheEntry *attopt;
+
+       hash_seq_init(&status, AttoptCacheHash);
+       while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL)
+       {
+               if (attopt->opts)
+                       pfree(attopt->opts);
+               if (hash_search(AttoptCacheHash,
+                                               (void *) &attopt->key,
+                                               HASH_REMOVE,
+                                               NULL) == NULL)
+                       elog(ERROR, "hash table corrupted");
+       }
+}
+
+/*
+ * InitializeAttoptCache
+ *             Initialize the tablespace cache.
+ */
+static void
+InitializeAttoptCache(void)
+{
+       HASHCTL ctl;
+
+       /* Initialize the hash table. */
+       MemSet(&ctl, 0, sizeof(ctl));
+       ctl.keysize = sizeof(AttoptCacheKey);
+       ctl.entrysize = sizeof(AttoptCacheEntry);
+       ctl.hash = tag_hash;
+       AttoptCacheHash =
+               hash_create("Attopt cache", 256, &ctl,
+                                   HASH_ELEM | HASH_FUNCTION);
+
+       /* Make sure we've initialized CacheMemoryContext. */
+       if (!CacheMemoryContext)
+               CreateCacheMemoryContext();
+
+       /* Watch for invalidation events. */
+       CacheRegisterSyscacheCallback(ATTNUM,
+                                                                 InvalidateAttoptCacheCallback,
+                                                                 (Datum) 0);
+}
+
+/*
+ * get_attribute_options
+ *             Fetch attribute options for a specified table OID.
+ */
+AttributeOpts *
+get_attribute_options(Oid attrelid, int attnum)
+{
+       AttoptCacheKey key;
+       AttoptCacheEntry *attopt;
+       AttributeOpts  *result;
+       HeapTuple       tp;
+
+       /* Find existing cache entry, if any. */
+       if (!AttoptCacheHash)
+               InitializeAttoptCache();
+       memset(&key, 0, sizeof(key));   /* make sure any padding bits are unset */
+       key.attrelid = attrelid;
+       key.attnum = attnum;
+       attopt =
+               (AttoptCacheEntry *) hash_search(AttoptCacheHash,
+                                                                        (void *) &key,
+                                                                                HASH_FIND,
+                                                                                NULL);
+
+       /* Not found in Attopt cache.  Construct new cache entry. */
+       if (!attopt)
+       {
+               AttributeOpts *opts;
+
+               tp = SearchSysCache(ATTNUM,
+                                                       ObjectIdGetDatum(attrelid),
+                                                       Int16GetDatum(attnum),
+                                                       0, 0);
+
+               /*
+                * If we don't find a valid HeapTuple, it must mean someone has
+                * managed to request attribute details for a non-existent attribute.
+                * We treat that case as if no options were specified.
+                */
+               if (!HeapTupleIsValid(tp))
+                       opts = NULL;
+               else
+               {
+                       Datum   datum;
+                       bool    isNull;
+
+                       datum = SysCacheGetAttr(ATTNUM,
+                                                                       tp,
+                                                                       Anum_pg_attribute_attoptions,
+                                                                       &isNull);
+                       if (isNull)
+                               opts = NULL;
+                       else
+                       {
+                               bytea *bytea_opts = attribute_reloptions(datum, false);
+                               opts = MemoryContextAlloc(CacheMemoryContext,
+                                                                                 VARSIZE(bytea_opts));
+                               memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
+                       }
+                       ReleaseSysCache(tp);
+               }
+
+               /*
+                * It's important to create the actual cache entry only after
+                * reading pg_attribute, since the read could cause a cache flush.
+                */
+               attopt = (AttoptCacheEntry *) hash_search(AttoptCacheHash,
+                                                                                                  (void *) &key,
+                                                                                                  HASH_ENTER,
+                                                                                                  NULL);
+               attopt->opts = opts;
+       }
+
+       /* Return results in caller's memory context. */
+       if (attopt->opts == NULL)
+               return NULL;
+       result = palloc(VARSIZE(attopt->opts));
+       memcpy(result, attopt->opts, VARSIZE(attopt->opts));
+       return result;
+}
index 29e04bea01081cd306a9399b70e2322c84bb9317..33ce64090620a71e99a89342a765dc3929a0b273 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.577 2010/01/22 15:45:15 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.578 2010/01/22 16:42:31 rhaas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201001221
+#define CATALOG_VERSION_NO     201001222
 
 #endif
diff --git a/src/include/utils/attoptcache.h b/src/include/utils/attoptcache.h
new file mode 100644 (file)
index 0000000..017bcbd
--- /dev/null
@@ -0,0 +1,28 @@
+/*-------------------------------------------------------------------------
+ *
+ * attoptcache.h
+ *       Attribute options cache.
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/utils/attoptcache.h,v 1.1 2010/01/22 16:42:31 rhaas Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SPCCACHE_H
+#define SPCCACHE_H
+
+/*
+ * Attribute options.
+ */
+typedef struct AttributeOpts
+{
+       int32           vl_len_;                /* varlena header (do not touch directly!) */
+       float8          n_distinct;
+       float8          n_distinct_inherited;
+} AttributeOpts;
+
+AttributeOpts *get_attribute_options(Oid spcid, int attnum);
+
+#endif   /* SPCCACHE_H */