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 */