summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/common/Makefile4
-rw-r--r--src/backend/access/common/heaptuple.c58
-rw-r--r--src/backend/access/common/reloptions.c326
-rw-r--r--src/backend/access/gin/ginutil.c32
-rw-r--r--src/backend/access/gist/gist.c20
-rw-r--r--src/backend/access/gist/gistutil.c24
-rw-r--r--src/backend/access/hash/hashpage.c14
-rw-r--r--src/backend/access/hash/hashutil.c23
-rw-r--r--src/backend/access/heap/heapam.c62
-rw-r--r--src/backend/access/heap/hio.c35
-rw-r--r--src/backend/access/index/genam.c47
-rw-r--r--src/backend/access/nbtree/nbtinsert.c17
-rw-r--r--src/backend/access/nbtree/nbtsort.c34
-rw-r--r--src/backend/access/nbtree/nbtutils.c24
-rw-r--r--src/backend/access/transam/xlogutils.c4
-rw-r--r--src/backend/bootstrap/bootparse.y9
-rw-r--r--src/backend/catalog/heap.c118
-rw-r--r--src/backend/catalog/index.c90
-rw-r--r--src/backend/catalog/indexing.c5
-rw-r--r--src/backend/commands/cluster.c28
-rw-r--r--src/backend/commands/define.c37
-rw-r--r--src/backend/commands/indexcmds.c18
-rw-r--r--src/backend/commands/prepare.c3
-rw-r--r--src/backend/commands/sequence.c14
-rw-r--r--src/backend/commands/tablecmds.c121
-rw-r--r--src/backend/commands/vacuum.c12
-rw-r--r--src/backend/commands/vacuumlazy.c4
-rw-r--r--src/backend/executor/execMain.c23
-rw-r--r--src/backend/nodes/copyfuncs.c4
-rw-r--r--src/backend/nodes/equalfuncs.c4
-rw-r--r--src/backend/nodes/outfuncs.c3
-rw-r--r--src/backend/nodes/readfuncs.c3
-rw-r--r--src/backend/parser/analyze.c5
-rw-r--r--src/backend/parser/gram.y45
-rw-r--r--src/backend/parser/parse_clause.c274
-rw-r--r--src/backend/utils/adt/ruleutils.c73
-rw-r--r--src/backend/utils/cache/relcache.c234
37 files changed, 905 insertions, 946 deletions
diff --git a/src/backend/access/common/Makefile b/src/backend/access/common/Makefile
index 7cd4a4ab0e..103bae2f5b 100644
--- a/src/backend/access/common/Makefile
+++ b/src/backend/access/common/Makefile
@@ -4,7 +4,7 @@
# Makefile for access/common
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/access/common/Makefile,v 1.21 2006/01/14 22:03:35 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/access/common/Makefile,v 1.22 2006/07/03 22:45:36 tgl Exp $
#
#-------------------------------------------------------------------------
@@ -12,7 +12,7 @@ subdir = src/backend/access/common
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
-OBJS = heaptuple.o indextuple.o printtup.o scankey.o tupdesc.o
+OBJS = heaptuple.o indextuple.o printtup.o reloptions.o scankey.o tupdesc.o
all: SUBSYS.o
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index edd90c8a56..70e8fd948d 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -16,7 +16,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.108 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.109 2006/07/03 22:45:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1694,9 +1694,8 @@ minimal_tuple_from_heap_tuple(HeapTuple htup)
* presumed to contain no null fields and no varlena fields.
*
* This routine is really only useful for certain system tables that are
- * known to be fixed-width and null-free. It is used in some places for
- * pg_class, but that is a gross hack (it only works because relacl can
- * be omitted from the tuple entirely in those places).
+ * known to be fixed-width and null-free. Currently it is only used for
+ * pg_attribute tuples.
* ----------------
*/
HeapTuple
@@ -1738,54 +1737,3 @@ heap_addheader(int natts, /* max domain index */
return tuple;
}
-
-/*
- * build_class_tuple
- *
- * XXX Natts_pg_class_fixed is a hack - see pg_class.h
- */
-HeapTuple
-build_class_tuple(Form_pg_class pgclass, ArrayType *options)
-{
- HeapTuple tuple;
- HeapTupleHeader td;
- Form_pg_class data; /* contents of tuple */
- Size len;
- Size size;
- int hoff;
-
- /* size of pg_class tuple with options */
- if (options)
- size = offsetof(FormData_pg_class, reloptions) + VARATT_SIZE(options);
- else
- size = CLASS_TUPLE_SIZE;
-
- /* header needs no null bitmap */
- hoff = offsetof(HeapTupleHeaderData, t_bits);
- hoff += sizeof(Oid);
- hoff = MAXALIGN(hoff);
- len = hoff + size;
-
- tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
- tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
-
- tuple->t_len = len;
- ItemPointerSetInvalid(&(tuple->t_self));
- tuple->t_tableOid = InvalidOid;
-
- /* we don't bother to fill the Datum fields */
-
- td->t_natts = Natts_pg_class_fixed;
- td->t_hoff = hoff;
- td->t_infomask = HEAP_HASOID;
-
- data = (Form_pg_class) ((char *) td + hoff);
- memcpy(data, pgclass, CLASS_TUPLE_SIZE);
- if (options)
- {
- td->t_natts++;
- memcpy(data->reloptions, options, VARATT_SIZE(options));
- }
-
- return tuple;
-}
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
new file mode 100644
index 0000000000..8506070f10
--- /dev/null
+++ b/src/backend/access/common/reloptions.c
@@ -0,0 +1,326 @@
+/*-------------------------------------------------------------------------
+ *
+ * reloptions.c
+ * Core support for relation options (pg_class.reloptions)
+ *
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.1 2006/07/03 22:45:36 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/reloptions.h"
+#include "catalog/pg_type.h"
+#include "commands/defrem.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/rel.h"
+
+
+/*
+ * Transform a relation options list (list of DefElem) into the text array
+ * format that is kept in pg_class.reloptions.
+ *
+ * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
+ * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
+ * reloptions value (possibly NULL), and we replace or remove entries
+ * as needed.
+ *
+ * If ignoreOids is true, then we should ignore any occurrence of "oids"
+ * in the list (it will be or has been handled by interpretOidsOption()).
+ *
+ * Note that this is not responsible for determining whether the options
+ * are valid.
+ *
+ * Both oldOptions and the result are text arrays (or NULL for "default"),
+ * but we declare them as Datums to avoid including array.h in reloptions.h.
+ */
+Datum
+transformRelOptions(Datum oldOptions, List *defList,
+ bool ignoreOids, bool isReset)
+{
+ Datum result;
+ ArrayBuildState *astate;
+ ListCell *cell;
+
+ /* no change if empty list */
+ if (defList == NIL)
+ return oldOptions;
+
+ /* We build new array using accumArrayResult */
+ astate = NULL;
+
+ /* Copy any oldOptions that aren't to be replaced */
+ if (oldOptions != (Datum) 0)
+ {
+ ArrayType *array = DatumGetArrayTypeP(oldOptions);
+ Datum *oldoptions;
+ int noldoptions;
+ int i;
+
+ Assert(ARR_ELEMTYPE(array) == TEXTOID);
+
+ deconstruct_array(array, TEXTOID, -1, false, 'i',
+ &oldoptions, NULL, &noldoptions);
+
+ for (i = 0; i < noldoptions; i++)
+ {
+ text *oldoption = DatumGetTextP(oldoptions[i]);
+ char *text_str = (char *) VARATT_DATA(oldoption);
+ int text_len = VARATT_SIZE(oldoption) - VARHDRSZ;
+
+ /* Search for a match in defList */
+ foreach(cell, defList)
+ {
+ DefElem *def = lfirst(cell);
+ int kw_len = strlen(def->defname);
+
+ if (text_len > kw_len && text_str[kw_len] == '=' &&
+ pg_strncasecmp(text_str, def->defname, kw_len) == 0)
+ break;
+ }
+ if (!cell)
+ {
+ /* No match, so keep old option */
+ astate = accumArrayResult(astate, oldoptions[i],
+ false, TEXTOID,
+ CurrentMemoryContext);
+ }
+ }
+ }
+
+ /*
+ * If CREATE/SET, add new options to array; if RESET, just check that
+ * the user didn't say RESET (option=val). (Must do this because the
+ * grammar doesn't enforce it.)
+ */
+ foreach(cell, defList)
+ {
+ DefElem *def = lfirst(cell);
+
+ if (isReset)
+ {
+ if (def->arg != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("RESET must not include values for parameters")));
+ }
+ else
+ {
+ text *t;
+ const char *value;
+ Size len;
+
+ if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
+ continue;
+
+ /*
+ * Flatten the DefElem into a text string like "name=arg".
+ * If we have just "name", assume "name=true" is meant.
+ */
+ if (def->arg != NULL)
+ value = defGetString(def);
+ else
+ value = "true";
+ len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
+ /* +1 leaves room for sprintf's trailing null */
+ t = (text *) palloc(len + 1);
+ VARATT_SIZEP(t) = len;
+ sprintf((char *) VARATT_DATA(t), "%s=%s", def->defname, value);
+
+ astate = accumArrayResult(astate, PointerGetDatum(t),
+ false, TEXTOID,
+ CurrentMemoryContext);
+ }
+ }
+
+ if (astate)
+ result = makeArrayResult(astate, CurrentMemoryContext);
+ else
+ result = (Datum) 0;
+
+ return result;
+}
+
+
+/*
+ * Interpret reloptions that are given in text-array format.
+ *
+ * options: array of "keyword=value" strings, as built by transformRelOptions
+ * numkeywords: number of legal keywords
+ * keywords: the allowed keywords
+ * values: output area
+ * validate: if true, throw error for unrecognized keywords.
+ *
+ * The keywords and values arrays must both be of length numkeywords.
+ * The values entry corresponding to a keyword is set to a palloc'd string
+ * containing the corresponding value, or NULL if the keyword does not appear.
+ */
+void
+parseRelOptions(Datum options, int numkeywords, const char * const *keywords,
+ char **values, bool validate)
+{
+ ArrayType *array;
+ Datum *optiondatums;
+ int noptions;
+ int i;
+
+ /* Initialize to "all defaulted" */
+ MemSet(values, 0, numkeywords * sizeof(char *));
+
+ /* Done if no options */
+ if (options == (Datum) 0)
+ return;
+
+ array = DatumGetArrayTypeP(options);
+
+ Assert(ARR_ELEMTYPE(array) == TEXTOID);
+
+ deconstruct_array(array, TEXTOID, -1, false, 'i',
+ &optiondatums, NULL, &noptions);
+
+ for (i = 0; i < noptions; i++)
+ {
+ text *optiontext = DatumGetTextP(optiondatums[i]);
+ char *text_str = (char *) VARATT_DATA(optiontext);
+ int text_len = VARATT_SIZE(optiontext) - VARHDRSZ;
+ int j;
+
+ /* Search for a match in keywords */
+ for (j = 0; j < numkeywords; j++)
+ {
+ int kw_len = strlen(keywords[j]);
+
+ if (text_len > kw_len && text_str[kw_len] == '=' &&
+ pg_strncasecmp(text_str, keywords[j], kw_len) == 0)
+ {
+ char *value;
+ int value_len;
+
+ if (values[j] && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("duplicate parameter \"%s\"",
+ keywords[j])));
+ value_len = text_len - kw_len - 1;
+ value = (char *) palloc(value_len + 1);
+ memcpy(value, text_str + kw_len + 1, value_len);
+ value[value_len] = '\0';
+ values[j] = value;
+ break;
+ }
+ }
+ if (j >= numkeywords && validate)
+ {
+ char *s;
+ char *p;
+
+ s = DatumGetCString(DirectFunctionCall1(textout, optiondatums[i]));
+ p = strchr(s, '=');
+ if (p)
+ *p = '\0';
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized parameter \"%s\"", s)));
+ }
+ }
+}
+
+
+/*
+ * Parse reloptions for anything using StdRdOptions (ie, fillfactor only)
+ */
+bytea *
+default_reloptions(Datum reloptions, bool validate,
+ int minFillfactor, int defaultFillfactor)
+{
+ static const char * const default_keywords[1] = { "fillfactor" };
+ char *values[1];
+ int32 fillfactor;
+ StdRdOptions *result;
+
+ parseRelOptions(reloptions, 1, default_keywords, values, validate);
+
+ /*
+ * If no options, we can just return NULL rather than doing anything.
+ * (defaultFillfactor is thus not used, but we require callers to pass
+ * it anyway since we would need it if more options were added.)
+ */
+ if (values[0] == NULL)
+ return NULL;
+
+ fillfactor = pg_atoi(values[0], sizeof(int32), 0);
+ if (fillfactor < minFillfactor || fillfactor > 100)
+ {
+ if (validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("fillfactor=%d is out of range (should be between %d and 100)",
+ fillfactor, minFillfactor)));
+ return NULL;
+ }
+
+ result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
+ VARATT_SIZEP(result) = sizeof(StdRdOptions);
+
+ result->fillfactor = fillfactor;
+
+ return (bytea *) result;
+}
+
+
+/*
+ * Parse options for heaps (and perhaps someday toast tables).
+ */
+bytea *
+heap_reloptions(char relkind, Datum reloptions, bool validate)
+{
+ return default_reloptions(reloptions, validate,
+ HEAP_MIN_FILLFACTOR,
+ HEAP_DEFAULT_FILLFACTOR);
+}
+
+
+/*
+ * Parse options for indexes.
+ *
+ * amoptions Oid of option parser
+ * reloptions options as text[] datum
+ * validate error flag
+ */
+bytea *
+index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
+{
+ FmgrInfo flinfo;
+ FunctionCallInfoData fcinfo;
+ Datum result;
+
+ Assert(RegProcedureIsValid(amoptions));
+
+ /* Assume function is strict */
+ if (reloptions == (Datum) 0)
+ return NULL;
+
+ /* Can't use OidFunctionCallN because we might get a NULL result */
+ fmgr_info(amoptions, &flinfo);
+
+ InitFunctionCallInfoData(fcinfo, &flinfo, 2, NULL, NULL);
+
+ fcinfo.arg[0] = reloptions;
+ fcinfo.arg[1] = BoolGetDatum(validate);
+ fcinfo.argnull[0] = false;
+ fcinfo.argnull[1] = false;
+
+ result = FunctionCallInvoke(&fcinfo);
+
+ if (fcinfo.isnull || DatumGetPointer(result) == NULL)
+ return NULL;
+
+ return DatumGetByteaP(result);
+}
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index 17e041bc4a..544956c84e 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.2 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.3 2006/07/03 22:45:36 tgl Exp $
*-------------------------------------------------------------------------
*/
@@ -16,7 +16,7 @@
#include "access/genam.h"
#include "access/gin.h"
#include "access/heapam.h"
-#include "catalog/index.h"
+#include "access/reloptions.h"
#include "miscadmin.h"
#include "storage/freespace.h"
@@ -203,15 +203,23 @@ GinPageGetCopyPage( Page page ) {
}
Datum
-ginoption(PG_FUNCTION_ARGS)
+ginoptions(PG_FUNCTION_ARGS)
{
- ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0);
-
- if (options != NULL)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("GIN does not support parameters at all")));
-
- /* Do not use PG_RETURN_NULL. */
- PG_RETURN_BYTEA_P(NULL);
+ Datum reloptions = PG_GETARG_DATUM(0);
+ bool validate = PG_GETARG_BOOL(1);
+ bytea *result;
+
+ /*
+ * It's not clear that fillfactor is useful for GIN, but for the moment
+ * we'll accept it anyway. (It won't do anything...)
+ */
+#define GIN_MIN_FILLFACTOR 50
+#define GIN_DEFAULT_FILLFACTOR 100
+
+ result = default_reloptions(reloptions, validate,
+ GIN_MIN_FILLFACTOR,
+ GIN_DEFAULT_FILLFACTOR);
+ if (result)
+ PG_RETURN_BYTEA_P(result);
+ PG_RETURN_NULL();
}
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 4137ab4426..bc915332b5 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.140 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.141 2006/07/03 22:45:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -197,9 +197,13 @@ gistbuildCallback(Relation index,
* which locks the relation for write. This is the right thing to do if
* you're inserting single tups, but not when you're initializing the
* whole index at once.
+ *
+ * In this path we respect the fillfactor setting, whereas insertions
+ * after initial build do not.
*/
- gistdoinsert(index, itup, IndexGetPageFreeSpace(index),
- &buildstate->giststate);
+ gistdoinsert(index, itup,
+ RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
+ &buildstate->giststate);
buildstate->indtuples += 1;
MemoryContextSwitchTo(oldCtx);
@@ -283,7 +287,6 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
bool is_splitted = false;
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
-
/*
* if (!is_leaf) remove old key:
* This node's key has been modified, either because a child split
@@ -294,14 +297,13 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
* setting up a one-element todelete array; in the split case, it's
* handled implicitly because the tuple vector passed to gistSplit
* won't include this tuple.
- */
-
-
- /*
+ *
* XXX: If we want to change fillfactors between node and leaf,
* fillfactor = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
*/
- if (gistnospace(state->stack->page, state->itup, state->ituplen, (is_leaf) ? InvalidOffsetNumber : state->stack->childoffnum, state->freespace))
+ if (gistnospace(state->stack->page, state->itup, state->ituplen,
+ is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
+ state->freespace))
{
/* no space for insertion */
IndexTuple *itvec;
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index ae1fbc7320..33cdae37c3 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.17 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.18 2006/07/03 22:45:36 tgl Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@@ -17,7 +17,7 @@
#include "access/gist_private.h"
#include "access/gistscan.h"
#include "access/heapam.h"
-#include "catalog/index.h"
+#include "access/reloptions.h"
#include "miscadmin.h"
#include "storage/freespace.h"
@@ -637,14 +637,16 @@ gistNewBuffer(Relation r)
}
Datum
-gistoption(PG_FUNCTION_ARGS)
+gistoptions(PG_FUNCTION_ARGS)
{
-#define GIST_DEFAULT_FILLFACTOR 90
-#define GIST_MIN_FILLFACTOR 50
-
- ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0);
-
- /* Use index common routine. */
- PG_RETURN_BYTEA_P(genam_option(options,
- GIST_MIN_FILLFACTOR, GIST_DEFAULT_FILLFACTOR));
+ Datum reloptions = PG_GETARG_DATUM(0);
+ bool validate = PG_GETARG_BOOL(1);
+ bytea *result;
+
+ result = default_reloptions(reloptions, validate,
+ GIST_MIN_FILLFACTOR,
+ GIST_DEFAULT_FILLFACTOR);
+ if (result)
+ PG_RETURN_BYTEA_P(result);
+ PG_RETURN_NULL();
}
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index bed0b5dbd7..f5a1fcfd81 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.58 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.59 2006/07/03 22:45:36 tgl Exp $
*
* NOTES
* Postgres hash pages look like ordinary relation pages. The opaque
@@ -30,7 +30,6 @@
#include "access/genam.h"
#include "access/hash.h"
-#include "catalog/index.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
@@ -223,16 +222,17 @@ _hash_metapinit(Relation rel)
RelationGetRelationName(rel));
/*
- * Determine the target fill factor (tuples per bucket) for this index.
- * The idea is to make the fill factor correspond to pages about 3/4ths
- * full. We can compute it exactly if the index datatype is fixed-width,
- * but for var-width there's some guessing involved.
+ * Determine the target fill factor (in tuples per bucket) for this index.
+ * The idea is to make the fill factor correspond to pages about as full
+ * as the user-settable fillfactor parameter says. We can compute it
+ * exactly if the index datatype is fixed-width, but for var-width there's
+ * some guessing involved.
*/
data_width = get_typavgwidth(RelationGetDescr(rel)->attrs[0]->atttypid,
RelationGetDescr(rel)->attrs[0]->atttypmod);
item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) +
sizeof(ItemIdData); /* include the line pointer */
- ffactor = BLCKSZ * IndexGetFillFactor(rel) / 100 / item_width;
+ ffactor = RelationGetTargetPageUsage(rel, HASH_DEFAULT_FILLFACTOR) / item_width;
/* keep to a sane range */
if (ffactor < 10)
ffactor = 10;
diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c
index fbee1fdc2a..a1a03ddcf3 100644
--- a/src/backend/access/hash/hashutil.c
+++ b/src/backend/access/hash/hashutil.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.48 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.49 2006/07/03 22:45:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,6 +16,7 @@
#include "access/genam.h"
#include "access/hash.h"
+#include "access/reloptions.h"
#include "executor/execdebug.h"
@@ -175,14 +176,16 @@ _hash_checkpage(Relation rel, Buffer buf, int flags)
}
Datum
-hashoption(PG_FUNCTION_ARGS)
+hashoptions(PG_FUNCTION_ARGS)
{
-#define HASH_MIN_FILLFACTOR 50
-#define HASH_DEFAULT_FILLFACTOR 75
-
- ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0);
-
- /* Use index common routine. */
- PG_RETURN_BYTEA_P(genam_option(options,
- HASH_MIN_FILLFACTOR, HASH_DEFAULT_FILLFACTOR));
+ Datum reloptions = PG_GETARG_DATUM(0);
+ bool validate = PG_GETARG_BOOL(1);
+ bytea *result;
+
+ result = default_reloptions(reloptions, validate,
+ HASH_MIN_FILLFACTOR,
+ HASH_DEFAULT_FILLFACTOR);
+ if (result)
+ PG_RETURN_BYTEA_P(result);
+ PG_RETURN_NULL();
}
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index cf3344c200..cf4b920f7d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.214 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.215 2006/07/03 22:45:37 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -46,13 +46,9 @@
#include "access/xlogutils.h"
#include "catalog/catalog.h"
#include "catalog/namespace.h"
-#include "commands/defrem.h"
#include "miscadmin.h"
-#include "nodes/parsenodes.h"
-#include "parser/parse_clause.h"
#include "pgstat.h"
#include "storage/procarray.h"
-#include "utils/catcache.h"
#include "utils/inval.h"
#include "utils/relcache.h"
@@ -3592,59 +3588,3 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
else
appendStringInfo(buf, "UNKNOWN");
}
-
-/*
- * Parse options for heaps.
- *
- * relkind Kind of relation
- * options Options as text[]
- */
-bytea *
-heap_option(char relkind, ArrayType *options)
-{
- /*
- * XXX: What fillfactor should be default?
- * overriding databases:
- * - Oracle, DB2 = 90%
- * - SQL Server = 100%
- * non-overriding database:
- * - Firebird = 70%
- */
-#define HEAP_MIN_FILLFACTOR 50
-#define HEAP_DEFAULT_FILLFACTOR 100
-
- int fillfactor;
- HeapOption *result;
-
- DefElem kwds[] =
- {
- { T_DefElem, "fillfactor" },
- };
-
- /*
- * parse options
- */
- OptionParse(options, lengthof(kwds), kwds, true);
-
- /* 0: fillfactor */
- if (kwds[0].arg)
- fillfactor = (int) defGetInt64(&kwds[0]);
- else
- fillfactor = HEAP_DEFAULT_FILLFACTOR;
- if (fillfactor < HEAP_MIN_FILLFACTOR || 100 < fillfactor)
- {
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("fillfactor=%d should be between %d and 100",
- fillfactor, HEAP_MIN_FILLFACTOR)));
- }
-
- /*
- * build option
- */
- result = (HeapOption *)
- MemoryContextAlloc(CacheMemoryContext, sizeof(HeapOption));
- VARATT_SIZEP(result) = sizeof(HeapOption);
- result->fillfactor = fillfactor;
- return (bytea *) result;
-}
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index 82fb0a3268..aaaec863ba 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.62 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.63 2006/07/03 22:45:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -93,6 +93,11 @@ RelationPutHeapTuple(Relation relation,
* any committed data of other transactions. (See heap_insert's comments
* for additional constraints needed for safe usage of this behavior.)
*
+ * We always try to avoid filling existing pages further than the fillfactor.
+ * This is OK since this routine is not consulted when updating a tuple and
+ * keeping it on the same page, which is the scenario fillfactor is meant
+ * to reserve space for.
+ *
* ereport(ERROR) is allowed here, so this routine *must* be called
* before any (unlogged) changes are made in buffer pool.
*/
@@ -103,17 +108,12 @@ RelationGetBufferForTuple(Relation relation, Size len,
Buffer buffer = InvalidBuffer;
Page pageHeader;
Size pageFreeSpace,
- freespace;
+ saveFreeSpace;
BlockNumber targetBlock,
otherBlock;
bool needLock;
- if (relation->rd_options == NULL)
- elog(ERROR, "RelationGetBufferForTuple %s IS NULL", RelationGetRelationName(relation));
- Assert(relation->rd_options != NULL);
-
len = MAXALIGN(len); /* be conservative */
- freespace = HeapGetPageFreeSpace(relation);
/*
* If we're gonna fail for oversize tuple, do it right away
@@ -125,6 +125,10 @@ RelationGetBufferForTuple(Relation relation, Size len,
(unsigned long) len,
(unsigned long) MaxTupleSize)));
+ /* Compute desired extra freespace due to fillfactor option */
+ saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
+ HEAP_DEFAULT_FILLFACTOR);
+
if (otherBuffer != InvalidBuffer)
otherBlock = BufferGetBlockNumber(otherBuffer);
else
@@ -143,8 +147,14 @@ RelationGetBufferForTuple(Relation relation, Size len,
* When use_fsm is false, we either put the tuple onto the existing target
* page or extend the relation.
*/
-
- targetBlock = relation->rd_targblock;
+ if (len + saveFreeSpace <= MaxTupleSize)
+ targetBlock = relation->rd_targblock;
+ else
+ {
+ /* can't fit, don't screw up FSM request tracking by trying */
+ targetBlock = InvalidBlockNumber;
+ use_fsm = false;
+ }
if (targetBlock == InvalidBlockNumber && use_fsm)
{
@@ -152,7 +162,8 @@ RelationGetBufferForTuple(Relation relation, Size len,
* We have no cached target page, so ask the FSM for an initial
* target.
*/
- targetBlock = GetPageWithFreeSpace(&relation->rd_node, len + freespace);
+ targetBlock = GetPageWithFreeSpace(&relation->rd_node,
+ len + saveFreeSpace);
/*
* If the FSM knows nothing of the rel, try the last page before we
@@ -208,7 +219,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
*/
pageHeader = (Page) BufferGetPage(buffer);
pageFreeSpace = PageGetFreeSpace(pageHeader);
- if (len + freespace <= pageFreeSpace)
+ if (len + saveFreeSpace <= pageFreeSpace)
{
/* use this page as future insert target, too */
relation->rd_targblock = targetBlock;
@@ -241,7 +252,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
targetBlock = RecordAndGetPageWithFreeSpace(&relation->rd_node,
targetBlock,
pageFreeSpace,
- len + freespace);
+ len + saveFreeSpace);
}
/*
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index cfc2a833cd..399386c856 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.56 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.57 2006/07/03 22:45:37 tgl Exp $
*
* NOTES
* many of the old access method routines have been turned into
@@ -21,12 +21,8 @@
#include "access/genam.h"
#include "access/heapam.h"
-#include "commands/defrem.h"
#include "miscadmin.h"
-#include "nodes/parsenodes.h"
-#include "parser/parse_clause.h"
#include "pgstat.h"
-#include "utils/catcache.h"
/* ----------------------------------------------------------------
@@ -264,44 +260,3 @@ systable_endscan(SysScanDesc sysscan)
pfree(sysscan);
}
-
-/*
- * Parse options for generic indexes.
- */
-bytea *
-genam_option(ArrayType *options,
- int minFillfactor, int defaultFillfactor)
-{
- int fillfactor;
- IndexOption *result;
-
- DefElem kwds[] =
- {
- { T_DefElem, "fillfactor" },
- };
-
- /*
- * parse options
- */
- OptionParse(options, lengthof(kwds), kwds, true);
-
- /* 0: fillfactor */
- if (kwds[0].arg)
- fillfactor = (int) defGetInt64(&kwds[0]);
- else
- fillfactor = defaultFillfactor;
- if (fillfactor < minFillfactor || 100 < fillfactor)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("fillfactor=%d should be between %d and 100",
- fillfactor, minFillfactor)));
-
- /*
- * build options
- */
- result = (IndexOption *)
- MemoryContextAlloc(CacheMemoryContext, sizeof(IndexOption));
- VARATT_SIZEP(result) = sizeof(IndexOption);
- result->fillfactor = fillfactor;
- return (bytea *) result;
-}
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 3b78843101..a176888691 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -8,14 +8,13 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.138 2006/07/02 02:23:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.139 2006/07/03 22:45:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "access/genam.h"
#include "access/heapam.h"
#include "access/nbtree.h"
#include "miscadmin.h"
@@ -26,7 +25,7 @@ typedef struct
{
/* context data for _bt_checksplitloc */
Size newitemsz; /* size of new item to be inserted */
- int fillfactor; /* used when insert at right most */
+ int fillfactor; /* needed when splitting rightmost page */
bool is_leaf; /* T if splitting a leaf page */
bool is_rightmost; /* T if splitting a rightmost page */
@@ -988,11 +987,11 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
* it needs to go into!)
*
* If the page is the rightmost page on its level, we instead try to arrange
- * for reserving (100-fillfactor)% of free space on left page. In this way,
- * when we are inserting successively increasing keys (consider sequences,
- * timestamps, etc) we will end up with a tree whose pages are about fillfactor% full,
+ * to leave the left split page fillfactor% full. In this way, when we are
+ * inserting successively increasing keys (consider sequences, timestamps,
+ * etc) we will end up with a tree whose pages are about fillfactor% full,
* instead of the 50% full result that we'd get without this special case.
- * This is the same as initially-loaded tree.
+ * This is the same as nbtsort.c produces for a newly-created tree.
*
* We are passed the intended insert position of the new tuple, expressed as
* the offsetnumber of the tuple it must go in front of. (This could be
@@ -1026,7 +1025,7 @@ _bt_findsplitloc(Relation rel,
/* Passed-in newitemsz is MAXALIGNED but does not include line pointer */
newitemsz += sizeof(ItemIdData);
state.newitemsz = newitemsz;
- state.fillfactor = IndexGetFillFactor(rel);
+ state.fillfactor = RelationGetFillFactor(rel, BTREE_DEFAULT_FILLFACTOR);
state.is_leaf = P_ISLEAF(opaque);
state.is_rightmost = P_RIGHTMOST(opaque);
state.have_split = false;
@@ -1157,7 +1156,7 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
if (state->is_rightmost)
{
/*
- * On a rightmost page, try to reserve (100-fillfactor)% of
+ * If splitting a rightmost page, try to put (100-fillfactor)% of
* free space on left page. See comments for _bt_findsplitloc.
*/
delta = (state->fillfactor * leftfree)
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index 05785d98eb..1dd3be0a63 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -27,9 +27,10 @@
* insertion would cause a split (and not only of the leaf page; the need
* for a split would cascade right up the tree). The steady-state load
* factor for btrees is usually estimated at 70%. We choose to pack leaf
- * pages to 90% and upper pages to 70%. This gives us reasonable density
- * (there aren't many upper pages if the keys are reasonable-size) without
- * incurring a lot of cascading splits during early insertions.
+ * pages to the user-controllable fill factor while upper pages are always
+ * packed to 70%. This gives us reasonable density (there aren't many upper
+ * pages if the keys are reasonable-size) without incurring a lot of cascading
+ * splits during early insertions.
*
* Formerly the index pages being built were kept in shared buffers, but
* that is of no value (since other backends have no interest in them yet)
@@ -56,14 +57,13 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.103 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.104 2006/07/03 22:45:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "access/genam.h"
#include "access/nbtree.h"
#include "access/xlog.h"
#include "miscadmin.h"
@@ -121,7 +121,6 @@ typedef struct BTWriteState
static Page _bt_blnewpage(uint32 level);
-static Size _bt_full_threshold(Relation index, Size pagesize, bool leaf);
static BTPageState *_bt_pagestate(BTWriteState *wstate, uint32 level);
static void _bt_slideleft(Page page);
static void _bt_sortaddtup(Page page, Size itemsize,
@@ -330,22 +329,6 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
}
/*
- * The steady-state load factor for btrees is usually estimated at 70%.
- * We choose to pack leaf pages to 90% and upper pages to 70% as defaults.
- */
-static Size
-_bt_full_threshold(Relation index, Size pagesize, bool leaf)
-{
- int fillfactor = IndexGetFillFactor(index);
- if (!leaf)
- {
- /* XXX: Is this reasonable? */
- fillfactor = Max(70, 3 * fillfactor - 200);
- }
- return pagesize * (100 - fillfactor) / 100;
-}
-
-/*
* allocate and initialize a new BTPageState. the returned structure
* is suitable for immediate use by _bt_buildadd.
*/
@@ -365,8 +348,11 @@ _bt_pagestate(BTWriteState *wstate, uint32 level)
state->btps_lastoff = P_HIKEY;
state->btps_level = level;
/* set "full" threshold based on level. See notes at head of file. */
- state->btps_full = _bt_full_threshold(wstate->index,
- PageGetPageSize(state->btps_page), level == 0);
+ if (level > 0)
+ state->btps_full = (BLCKSZ * (100 - BTREE_MIN_FILLFACTOR) / 100);
+ else
+ state->btps_full = RelationGetTargetPageFreeSpace(wstate->index,
+ BTREE_DEFAULT_FILLFACTOR);
/* no parent level, yet */
state->btps_next = NULL;
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 93a9b0df65..6750a982d7 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.75 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.76 2006/07/03 22:45:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,7 +19,7 @@
#include "access/genam.h"
#include "access/nbtree.h"
-#include "catalog/catalog.h"
+#include "access/reloptions.h"
#include "executor/execdebug.h"
#include "miscadmin.h"
@@ -1081,14 +1081,16 @@ BTreeShmemInit(void)
}
Datum
-btoption(PG_FUNCTION_ARGS)
+btoptions(PG_FUNCTION_ARGS)
{
-#define BTREE_MIN_FILLFACTOR 50
-#define BTREE_DEFAULT_FILLFACTOR 90
-
- ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0);
-
- /* Use index common routine. */
- PG_RETURN_BYTEA_P(genam_option(options,
- BTREE_MIN_FILLFACTOR, BTREE_DEFAULT_FILLFACTOR));
+ Datum reloptions = PG_GETARG_DATUM(0);
+ bool validate = PG_GETARG_BOOL(1);
+ bytea *result;
+
+ result = default_reloptions(reloptions, validate,
+ BTREE_MIN_FILLFACTOR,
+ BTREE_DEFAULT_FILLFACTOR);
+ if (result)
+ PG_RETURN_BYTEA_P(result);
+ PG_RETURN_NULL();
}
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index da30e39b42..b6fd45d6df 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.45 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.46 2006/07/03 22:45:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -337,7 +337,7 @@ _xl_remove_hash_entry(XLogRelDesc *rdesc)
RelationCloseSmgr(&(rdesc->reldata));
memset(rdesc, 0, sizeof(XLogRelDesc));
- memset(tpgc, 0, CLASS_TUPLE_SIZE);
+ memset(tpgc, 0, sizeof(FormData_pg_class));
rdesc->reldata.rd_rel = tpgc;
}
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 901c392d7e..9bb8f01b1e 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.81 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.82 2006/07/03 22:45:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,7 +19,6 @@
#include <unistd.h>
#include "access/attnum.h"
-#include "access/heapam.h"
#include "access/htup.h"
#include "access/itup.h"
#include "access/skey.h"
@@ -193,8 +192,6 @@ Boot_CreateStmt:
RELKIND_RELATION,
$3,
true);
- boot_reldesc->rd_options =
- heap_option(RELKIND_RELATION, NULL);
elog(DEBUG4, "bootstrap relation created");
}
else
@@ -212,8 +209,8 @@ Boot_CreateStmt:
true,
0,
ONCOMMIT_NOOP,
- true,
- NULL);
+ (Datum) 0,
+ true);
elog(DEBUG4, "relation created with oid %u", id);
}
do_end();
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e2eed023e0..3a6bc46a69 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.303 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.304 2006/07/03 22:45:37 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -44,24 +44,20 @@
#include "catalog/pg_type.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
-#include "commands/defrem.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/var.h"
#include "parser/parse_coerce.h"
-#include "parser/parse_clause.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "rewrite/rewriteRemove.h"
#include "storage/smgr.h"
-#include "utils/catcache.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
-#include "utils/memutils.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
@@ -71,7 +67,7 @@ static void AddNewRelationTuple(Relation pg_class_desc,
Oid new_rel_oid, Oid new_type_oid,
Oid relowner,
char relkind,
- ArrayType *options);
+ Datum reloptions);
static Oid AddNewRelationType(const char *typeName,
Oid typeNamespace,
Oid new_rel_oid,
@@ -551,6 +547,80 @@ AddNewAttributeTuples(Oid new_rel_oid,
}
/* --------------------------------
+ * InsertPgClassTuple
+ *
+ * Construct and insert a new tuple in pg_class.
+ *
+ * Caller has already opened and locked pg_class.
+ * Tuple data is taken from new_rel_desc->rd_rel, except for the
+ * variable-width fields which are not present in a cached reldesc.
+ * We alway initialize relacl to NULL (i.e., default permissions),
+ * and reloptions is set to the passed-in text array (if any).
+ * --------------------------------
+ */
+void
+InsertPgClassTuple(Relation pg_class_desc,
+ Relation new_rel_desc,
+ Oid new_rel_oid,
+ Datum reloptions)
+{
+ Form_pg_class rd_rel = new_rel_desc->rd_rel;
+ Datum values[Natts_pg_class];
+ char nulls[Natts_pg_class];
+ HeapTuple tup;
+
+ /* This is a tad tedious, but way cleaner than what we used to do... */
+ memset(values, 0, sizeof(values));
+ memset(nulls, ' ', sizeof(nulls));
+
+ values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname);
+ values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace);
+ values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype);
+ values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner);
+ values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam);
+ values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode);
+ values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace);
+ values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages);
+ values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
+ values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
+ values[Anum_pg_class_reltoastidxid - 1] = ObjectIdGetDatum(rd_rel->reltoastidxid);
+ values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
+ values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
+ values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
+ values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
+ values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
+ values[Anum_pg_class_reltriggers - 1] = Int16GetDatum(rd_rel->reltriggers);
+ values[Anum_pg_class_relukeys - 1] = Int16GetDatum(rd_rel->relukeys);
+ values[Anum_pg_class_relfkeys - 1] = Int16GetDatum(rd_rel->relfkeys);
+ values[Anum_pg_class_relrefs - 1] = Int16GetDatum(rd_rel->relrefs);
+ values[Anum_pg_class_relhasoids - 1] = BoolGetDatum(rd_rel->relhasoids);
+ values[Anum_pg_class_relhaspkey - 1] = BoolGetDatum(rd_rel->relhaspkey);
+ values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
+ values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
+ /* start out with empty permissions */
+ nulls[Anum_pg_class_relacl - 1] = 'n';
+ if (reloptions != (Datum) 0)
+ values[Anum_pg_class_reloptions - 1] = reloptions;
+ else
+ nulls[Anum_pg_class_reloptions - 1] = 'n';
+
+ tup = heap_formtuple(RelationGetDescr(pg_class_desc), values, nulls);
+
+ /*
+ * The new tuple must have the oid already chosen for the rel. Sure
+ * would be embarrassing to do this sort of thing in polite company.
+ */
+ HeapTupleSetOid(tup, new_rel_oid);
+
+ /* finally insert the new tuple, update the indexes, and clean up */
+ simple_heap_insert(pg_class_desc, tup);
+
+ CatalogUpdateIndexes(pg_class_desc, tup);
+
+ heap_freetuple(tup);
+}
+
+/* --------------------------------
* AddNewRelationTuple
*
* this registers the new relation in the catalogs by
@@ -564,10 +634,9 @@ AddNewRelationTuple(Relation pg_class_desc,
Oid new_type_oid,
Oid relowner,
char relkind,
- ArrayType *options)
+ Datum reloptions)
{
Form_pg_class new_rel_reltup;
- HeapTuple tup;
/*
* first we update some of the information in our uncataloged relation's
@@ -602,20 +671,8 @@ AddNewRelationTuple(Relation pg_class_desc,
new_rel_desc->rd_att->tdtypeid = new_type_oid;
- /* now form a tuple to add to pg_class */
- tup = build_class_tuple(new_rel_reltup, options);
-
- /* force tuple to have the desired OID */
- HeapTupleSetOid(tup, new_rel_oid);
-
- /*
- * finally insert the new tuple, update the indexes, and clean up.
- */
- simple_heap_insert(pg_class_desc, tup);
-
- CatalogUpdateIndexes(pg_class_desc, tup);
-
- heap_freetuple(tup);
+ /* Now build and insert the tuple */
+ InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
}
@@ -660,8 +717,6 @@ AddNewRelationType(const char *typeName,
* heap_create_with_catalog
*
* creates a new cataloged relation. see comments above.
- *
- * if opaque is specified, it must be allocated in CacheMemoryContext.
* --------------------------------
*/
Oid
@@ -676,12 +731,11 @@ heap_create_with_catalog(const char *relname,
bool oidislocal,
int oidinhcount,
OnCommitAction oncommit,
- bool allow_system_table_mods,
- ArrayType *options)
+ Datum reloptions,
+ bool allow_system_table_mods)
{
Relation pg_class_desc;
Relation new_rel_desc;
- bytea *new_rel_options;
Oid new_type_oid;
pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
@@ -699,13 +753,6 @@ heap_create_with_catalog(const char *relname,
errmsg("relation \"%s\" already exists", relname)));
/*
- * Parse options to check if option is valid.
- */
- new_rel_options = heap_option(relkind, options);
- Assert(!new_rel_options ||
- GetMemoryChunkContext(new_rel_options) == CacheMemoryContext);
-
- /*
* Allocate an OID for the relation, unless we were told what to use.
*
* The OID will be the relfilenode as well, so make sure it doesn't
@@ -728,7 +775,6 @@ heap_create_with_catalog(const char *relname,
relkind,
shared_relation,
allow_system_table_mods);
- new_rel_desc->rd_options = new_rel_options;
Assert(relid == RelationGetRelid(new_rel_desc));
@@ -757,7 +803,7 @@ heap_create_with_catalog(const char *relname,
new_type_oid,
ownerid,
relkind,
- options);
+ reloptions);
/*
* now add tuples to pg_attribute for the attributes in our new relation.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9143f6068a..f047f58b01 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.267 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.268 2006/07/03 22:45:37 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -37,7 +37,6 @@
#include "executor/executor.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
-#include "parser/parse_clause.h"
#include "parser/parse_expr.h"
#include "storage/procarray.h"
#include "storage/smgr.h"
@@ -54,8 +53,6 @@
static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
IndexInfo *indexInfo,
Oid *classObjectId);
-static void UpdateRelationRelation(Relation pg_class, Relation indexRelation,
- ArrayType *options);
static void InitializeAttributeOids(Relation indexRelation,
int numatts, Oid indexoid);
static void AppendAttributeTuples(Relation indexRelation, int numatts);
@@ -239,32 +236,6 @@ ConstructTupleDescriptor(Relation heapRelation,
}
/* ----------------------------------------------------------------
- * UpdateRelationRelation
- * ----------------------------------------------------------------
- */
-static void
-UpdateRelationRelation(Relation pg_class, Relation indexRelation,
- ArrayType *options)
-{
- HeapTuple tuple;
-
- tuple = build_class_tuple(indexRelation->rd_rel, options);
-
- /*
- * the new tuple must have the oid already chosen for the index. sure
- * would be embarrassing to do this sort of thing in polite company.
- */
- HeapTupleSetOid(tuple, RelationGetRelid(indexRelation));
-
- simple_heap_insert(pg_class, tuple);
-
- /* update the system catalog indexes */
- CatalogUpdateIndexes(pg_class, tuple);
-
- heap_freetuple(tuple);
-}
-
-/* ----------------------------------------------------------------
* InitializeAttributeOids
* ----------------------------------------------------------------
*/
@@ -449,6 +420,7 @@ UpdateIndexRelation(Oid indexoid,
* accessMethodObjectId: OID of index AM to use
* tableSpaceId: OID of tablespace to use
* classObjectId: array of index opclass OIDs, one per index column
+ * reloptions: AM-specific options
* isprimary: index is a PRIMARY KEY
* istoast: index is a toast table's index
* isconstraint: index is owned by a PRIMARY KEY or UNIQUE constraint
@@ -466,7 +438,7 @@ index_create(Oid heapRelationId,
Oid accessMethodObjectId,
Oid tableSpaceId,
Oid *classObjectId,
- List *options,
+ Datum reloptions,
bool isprimary,
bool istoast,
bool isconstraint,
@@ -481,9 +453,6 @@ index_create(Oid heapRelationId,
Oid namespaceId;
int i;
- ArrayType *array;
- RegProcedure amoption;
-
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
/*
@@ -582,40 +551,13 @@ index_create(Oid heapRelationId,
indexRelation->rd_rel->relhasoids = false;
/*
- * AM specific options.
- */
- array = OptionBuild(NULL, options);
- if (indexRelation->rd_am)
- {
- amoption = indexRelation->rd_am->amoption;
- }
- else
- {
- HeapTuple tuple;
-
- /*
- * We may use the access method before initializing relation,
- * so we pick up AM from syscache directly.
- */
- tuple = SearchSysCache(AMOID,
- ObjectIdGetDatum(accessMethodObjectId),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for access method %u",
- accessMethodObjectId);
- amoption = ((Form_pg_am) GETSTRUCT(tuple))->amoption;
- ReleaseSysCache(tuple);
- }
- indexRelation->rd_options = index_option(amoption, array);
-
- /*
* store index's pg_class entry
*/
- UpdateRelationRelation(pg_class, indexRelation, array);
+ InsertPgClassTuple(pg_class, indexRelation,
+ RelationGetRelid(indexRelation),
+ reloptions);
/* done with pg_class */
- if (array)
- pfree(array);
heap_close(pg_class, RowExclusiveLock);
/*
@@ -1783,23 +1725,3 @@ reindex_relation(Oid relid, bool toast_too)
return result;
}
-
-/*
- * Parse options for indexes.
- *
- * amoption Oid of option parser.
- * options Options as text[]
- */
-bytea *index_option(RegProcedure amoption, ArrayType *options)
-{
- Datum datum;
-
- Assert(RegProcedureIsValid(amoption));
-
- datum = OidFunctionCall1(amoption, PointerGetDatum(options));
-
- if (DatumGetPointer(datum) == NULL)
- return NULL;
-
- return DatumGetByteaP(datum);
-}
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index 2ed1a156a4..5724467d70 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -9,19 +9,16 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/indexing.c,v 1.112 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/indexing.c,v 1.113 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
-#include "access/heapam.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "executor/executor.h"
-#include "utils/syscache.h"
-#include "commands/defrem.h"
/*
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 08b76e96d5..fa41de3a2d 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.148 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.149 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -567,7 +567,8 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
Oid OIDNewHeap;
Relation OldHeap;
HeapTuple tuple;
- ArrayType *options;
+ Datum reloptions;
+ bool isNull;
OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
OldHeapDesc = RelationGetDescr(OldHeap);
@@ -584,19 +585,12 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(OIDOldHeap),
0, 0, 0);
- if (tuple)
- {
- Datum datum;
- bool isNull;
- datum = SysCacheGetAttr(RELOID, tuple,
- Anum_pg_class_reloptions, &isNull);
- options = isNull ? NULL : DatumGetArrayTypeP(datum);
- }
- else
- {
- /* should not happen */
- options = NULL;
- }
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
+ reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
+ &isNull);
+ if (isNull)
+ reloptions = (Datum) 0;
OIDNewHeap = heap_create_with_catalog(NewName,
RelationGetNamespace(OldHeap),
@@ -609,8 +603,8 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
true,
0,
ONCOMMIT_NOOP,
- allowSystemTableMods,
- options);
+ reloptions,
+ allowSystemTableMods);
ReleaseSysCache(tuple);
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index ebde8f1095..149e1b6dae 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.96 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.97 2006/07/03 22:45:38 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -110,7 +110,6 @@ defGetNumeric(DefElem *def)
case T_Integer:
return (double) intVal(def->arg);
case T_Float:
- case T_String: /* XXX: needs strict check? */
return floatVal(def->arg);
default:
ereport(ERROR,
@@ -128,27 +127,39 @@ bool
defGetBoolean(DefElem *def)
{
/*
- * Presently, boolean flags must simply be present/absent or
- * integer 0/1. Later we could allow 'flag = t', 'flag = f', etc.
+ * If no parameter given, assume "true" is meant.
*/
if (def->arg == NULL)
return true;
+ /*
+ * Allow 0, 1, "true", "false"
+ */
switch (nodeTag(def->arg))
{
case T_Integer:
switch (intVal(def->arg))
{
- case 0:
- return false;
- case 1:
- return true;
+ case 0:
+ return false;
+ case 1:
+ return true;
+ default:
+ /* otherwise, error out below */
+ break;
}
break;
default:
+ {
+ char *sval = defGetString(def);
+
+ if (pg_strcasecmp(sval, "true") == 0)
+ return true;
+ if (pg_strcasecmp(sval, "false") == 0)
+ return false;
+
+ }
break;
}
-
- /* on error */
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a boolean value",
@@ -172,7 +183,7 @@ defGetInt64(DefElem *def)
case T_Integer:
return (int64) intVal(def->arg);
case T_Float:
- case T_String: /* XXX: needs strict check? */
+
/*
* Values too large for int4 will be represented as Float
* constants by the lexer. Accept these if they are valid int8
@@ -293,10 +304,14 @@ defGetTypeLength(DefElem *def)
return 0; /* keep compiler quiet */
}
+/*
+ * Create a DefElem setting "oids" to the specified value.
+ */
DefElem *
defWithOids(bool value)
{
DefElem *f = makeNode(DefElem);
+
f->defname = "oids";
f->arg = (Node *)makeInteger(value);
return f;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 7e35258ac0..d2c4bf8905 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.142 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.143 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,6 +17,7 @@
#include "access/genam.h"
#include "access/heapam.h"
+#include "access/reloptions.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
@@ -72,12 +73,12 @@ static bool relationHasPrimaryKey(Relation rel);
* to index on.
* 'predicate': the partial-index condition, or NULL if none.
* 'rangetable': needed to interpret the predicate.
+ * 'options': reloptions from WITH (in list-of-DefElem form).
* 'unique': make the index enforce uniqueness.
* 'primary': mark the index as a primary key in the catalogs.
* 'isconstraint': index is for a PRIMARY KEY or UNIQUE constraint,
* so build a pg_constraint entry for it.
* 'is_alter_table': this is due to an ALTER rather than a CREATE operation.
- * 'options': options passed by WITH.
* 'check_rights': check for CREATE rights in the namespace. (This should
* be true except when ALTER is deleting/recreating an index.)
* 'skip_build': make the catalog entries but leave the index file empty;
@@ -110,6 +111,8 @@ DefineIndex(RangeVar *heapRelation,
Relation rel;
HeapTuple tuple;
Form_pg_am accessMethodForm;
+ RegProcedure amoptions;
+ Datum reloptions;
IndexInfo *indexInfo;
int numberOfAttributes;
@@ -261,6 +264,8 @@ DefineIndex(RangeVar *heapRelation,
errmsg("access method \"%s\" does not support multicolumn indexes",
accessMethodName)));
+ amoptions = accessMethodForm->amoptions;
+
ReleaseSysCache(tuple);
/*
@@ -368,6 +373,13 @@ DefineIndex(RangeVar *heapRelation,
}
/*
+ * Parse AM-specific options, convert to text array form, validate.
+ */
+ reloptions = transformRelOptions((Datum) 0, options, false, false);
+
+ (void) index_reloptions(amoptions, reloptions, true);
+
+ /*
* Prepare arguments for index_create, primarily an IndexInfo structure.
* Note that ii_Predicate must be in implicit-AND format.
*/
@@ -399,7 +411,7 @@ DefineIndex(RangeVar *heapRelation,
index_create(relationId, indexRelationName, indexRelationId,
indexInfo, accessMethodId, tablespaceId, classObjectId,
- options, primary, false, isconstraint,
+ reloptions, primary, false, isconstraint,
allowSystemTableMods, skip_build);
}
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 27ccb3fb87..78ec950f23 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
* Copyright (c) 2002-2006, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.54 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.55 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -197,7 +197,6 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params,
errmsg("prepared statement is not a SELECT")));
query->into = copyObject(stmt->into);
query->intoOptions = copyObject(stmt->intoOptions);
- query->intoHasOids = stmt->into_has_oids;
query->intoOnCommit = stmt->into_on_commit;
if (stmt->into_tbl_space)
query->intoTableSpaceName = pstrdup(stmt->into_tbl_space);
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 65712c2092..cae956c22d 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.133 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.134 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -205,17 +205,7 @@ DefineSequence(CreateSeqStmt *seq)
/* Now form & insert sequence tuple */
tuple = heap_formtuple(tupDesc, value, null);
-
- {
- /*
- * HACK: Sequences insert only one tuple during initialize.
- * We treat sequences as heaps then.
- */
- HeapOption opaque = { sizeof(HeapOption), 100 };
- rel->rd_options = (bytea *) &opaque;
- simple_heap_insert(rel, tuple);
- rel->rd_options = NULL;
- }
+ simple_heap_insert(rel, tuple);
Assert(ItemPointerGetOffsetNumber(&(tuple->t_self)) == FirstOffsetNumber);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 7b2a0508fe..f67f1b62ec 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,13 +8,14 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.191 2006/07/02 05:17:26 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.192 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
+#include "access/reloptions.h"
#include "access/tuptoaster.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
@@ -62,6 +63,7 @@
#include "utils/relcache.h"
#include "utils/syscache.h"
+
/*
* ON COMMIT action list
*/
@@ -248,7 +250,7 @@ static void ATExecDropCluster(Relation rel);
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
char *tablespacename);
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);
-static void ATExecSetOptions(Relation rel, List *newOptions);
+static void ATExecSetRelOptions(Relation rel, List *defList, bool isReset);
static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
bool enable, bool skip_system);
static void ATExecAddInherits(Relation rel, RangeVar *parent);
@@ -283,10 +285,10 @@ DefineRelation(CreateStmt *stmt, char relkind)
bool localHasOids;
int parentOidCount;
List *rawDefaults;
+ Datum reloptions;
ListCell *listptr;
int i;
AttrNumber attnum;
- ArrayType *options;
/*
* Truncate relname to appropriate length (probably a waste of time, as
@@ -339,6 +341,13 @@ DefineRelation(CreateStmt *stmt, char relkind)
/* note InvalidOid is OK in this case */
}
+ /*
+ * Parse and validate reloptions, if any.
+ */
+ reloptions = transformRelOptions((Datum) 0, stmt->options, true, false);
+
+ (void) heap_reloptions(relkind, reloptions, true);
+
/* Check permissions except when using database's default */
if (OidIsValid(tablespaceId))
{
@@ -428,7 +437,6 @@ DefineRelation(CreateStmt *stmt, char relkind)
}
}
- options = OptionBuild(NULL, stmt->options);
relationId = heap_create_with_catalog(relname,
namespaceId,
tablespaceId,
@@ -440,10 +448,8 @@ DefineRelation(CreateStmt *stmt, char relkind)
localHasOids,
parentOidCount,
stmt->oncommit,
- allowSystemTableMods,
- options);
- if (options)
- pfree(options);
+ reloptions,
+ allowSystemTableMods);
StoreCatalogInheritance(relationId, inheritOids);
@@ -2103,7 +2109,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
ATPrepSetTableSpace(tab, rel, cmd->name);
pass = AT_PASS_MISC; /* doesn't actually matter */
break;
- case AT_SetOptions: /* SET (...) */
+ case AT_SetRelOptions: /* SET (...) */
+ case AT_ResetRelOptions: /* RESET (...) */
ATSimplePermissionsRelationOrIndex(rel);
/* This command never recurses */
/* No command-specific prep needed */
@@ -2279,8 +2286,11 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd)
* Nothing to do here; Phase 3 does the work
*/
break;
- case AT_SetOptions: /* SET (...) */
- ATExecSetOptions(rel, (List *) cmd->def);
+ case AT_SetRelOptions: /* SET (...) */
+ ATExecSetRelOptions(rel, (List *) cmd->def, false);
+ break;
+ case AT_ResetRelOptions: /* RESET (...) */
+ ATExecSetRelOptions(rel, (List *) cmd->def, true);
break;
case AT_EnableTrig: /* ENABLE TRIGGER name */
ATExecEnableDisableTrigger(rel, cmd->name, true, false);
@@ -5757,24 +5767,29 @@ ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename)
}
/*
- * ALTER TABLE/INDEX SET (...)
+ * ALTER TABLE/INDEX SET (...) or RESET (...)
*/
static void
-ATExecSetOptions(Relation rel, List *newOptions)
+ATExecSetRelOptions(Relation rel, List *defList, bool isReset)
{
Oid relid;
Relation pgclass;
HeapTuple tuple;
+ HeapTuple newtuple;
Datum datum;
bool isnull;
- ArrayType *mergedOptions;
- bytea *options;
+ Datum newOptions;
+ Datum repl_val[Natts_pg_class];
+ char repl_null[Natts_pg_class];
+ char repl_repl[Natts_pg_class];
- if (list_length(newOptions) == 0)
- return; /* do nothing */
+ if (defList == NIL)
+ return; /* nothing to do */
- relid = RelationGetRelid(rel);
pgclass = heap_open(RelationRelationId, RowExclusiveLock);
+
+ /* Get the old reloptions */
+ relid = RelationGetRelid(rel);
tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
@@ -5783,59 +5798,54 @@ ATExecSetOptions(Relation rel, List *newOptions)
datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull);
- mergedOptions = OptionBuild(
- isnull ? NULL : DatumGetArrayTypeP(datum), newOptions);
+ /* Generate new proposed reloptions (text array) */
+ newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
+ defList, false, isReset);
+ /* Validate */
switch (rel->rd_rel->relkind)
{
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
- options = heap_option(rel->rd_rel->relkind, mergedOptions);
+ (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
break;
case RELKIND_INDEX:
- options = index_option(rel->rd_am->amoption, mergedOptions);
+ (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
break;
default:
- elog(ERROR, "unexpected RELKIND=%c", rel->rd_rel->relkind);
- options = NULL; /* keep compiler quiet */
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a table, index, or TOAST table",
+ RelationGetRelationName(rel))));
break;
}
- if (rel->rd_options != options)
- {
- HeapTuple newtuple;
- Datum repl_val[Natts_pg_class];
- char repl_null[Natts_pg_class];
- char repl_repl[Natts_pg_class];
-
- /* XXX: This is not necessarily required. */
- if (rel->rd_options)
- pfree(rel->rd_options);
- rel->rd_options = options;
+ /*
+ * All we need do here is update the pg_class row; the new options will be
+ * propagated into relcaches during post-commit cache inval.
+ */
+ memset(repl_val, 0, sizeof(repl_val));
+ memset(repl_null, ' ', sizeof(repl_null));
+ memset(repl_repl, ' ', sizeof(repl_repl));
- memset(repl_repl, ' ', sizeof(repl_repl));
- memset(repl_null, ' ', sizeof(repl_null));
- repl_repl[Anum_pg_class_reloptions - 1] = 'r';
+ if (newOptions != (Datum) 0)
+ repl_val[Anum_pg_class_reloptions - 1] = newOptions;
+ else
+ repl_null[Anum_pg_class_reloptions - 1] = 'n';
- if (mergedOptions)
- repl_val[Anum_pg_class_reloptions - 1] =
- PointerGetDatum(mergedOptions);
- else
- repl_null[Anum_pg_class_reloptions - 1] = 'n';
+ repl_repl[Anum_pg_class_reloptions - 1] = 'r';
- newtuple = heap_modifytuple(tuple, RelationGetDescr(pgclass),
- repl_val, repl_null, repl_repl);
+ newtuple = heap_modifytuple(tuple, RelationGetDescr(pgclass),
+ repl_val, repl_null, repl_repl);
- simple_heap_update(pgclass, &newtuple->t_self, newtuple);
- CatalogUpdateIndexes(pgclass, newtuple);
+ simple_heap_update(pgclass, &newtuple->t_self, newtuple);
- heap_freetuple(newtuple);
- }
+ CatalogUpdateIndexes(pgclass, newtuple);
- if (mergedOptions)
- pfree(mergedOptions);
+ heap_freetuple(newtuple);
ReleaseSysCache(tuple);
+
heap_close(pgclass, RowExclusiveLock);
}
@@ -6642,6 +6652,9 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
* even if its master relation is a temp table. There cannot be any
* naming collision, and the toast rel will be destroyed when its master
* is, so there's no need to handle the toast rel as temp.
+ *
+ * XXX would it make sense to apply the master's reloptions to the toast
+ * table?
*/
toast_relid = heap_create_with_catalog(toast_relname,
PG_TOAST_NAMESPACE,
@@ -6654,8 +6667,8 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
true,
0,
ONCOMMIT_NOOP,
- true,
- NULL);
+ (Datum) 0,
+ true);
/* make the toast relation visible, else index creation will fail */
CommandCounterIncrement();
@@ -6689,7 +6702,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
indexInfo,
BTREE_AM_OID,
rel->rd_rel->reltablespace,
- classObjectId, NIL,
+ classObjectId, (Datum) 0,
true, true, false, true, false);
/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 24a93e998d..17a802dc30 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.331 2006/07/02 02:23:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.332 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3119,8 +3119,6 @@ vac_update_fsm(Relation onerel, VacPageList fraged_pages,
* vacuumlazy.c does, we'd be skewing that statistic.
*/
threshold = GetAvgFSMRequestSize(&onerel->rd_node);
- if (threshold < HeapGetPageFreeSpace(onerel))
- threshold = HeapGetPageFreeSpace(onerel);
pageSpaces = (PageFreeSpaceInfo *)
palloc(nPages * sizeof(PageFreeSpaceInfo));
@@ -3391,11 +3389,13 @@ static Size
PageGetFreeSpaceWithFillFactor(Relation relation, Page page)
{
PageHeader pd = (PageHeader) page;
- Size pagefree = HeapGetPageFreeSpace(relation);
Size freespace = pd->pd_upper - pd->pd_lower;
+ Size targetfree;
- if (freespace > pagefree)
- return freespace - pagefree;
+ targetfree = RelationGetTargetPageFreeSpace(relation,
+ HEAP_DEFAULT_FILLFACTOR);
+ if (freespace > targetfree)
+ return freespace - targetfree;
else
return 0;
}
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 8e97fa4756..264cb43778 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -31,7 +31,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.71 2006/07/02 02:23:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.72 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -149,8 +149,6 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
/* Set threshold for interesting free space = average request size */
/* XXX should we scale it up or down? Adjust vacuum.c too, if so */
vacrelstats->threshold = GetAvgFSMRequestSize(&onerel->rd_node);
- if (vacrelstats->threshold < HeapGetPageFreeSpace(onerel))
- vacrelstats->threshold = HeapGetPageFreeSpace(onerel);
/* Open all indexes of the relation */
vac_open_indexes(onerel, ShareUpdateExclusiveLock, &nindexes, &Irel);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index bb03b9358c..3c9f0798ba 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,13 +26,14 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.272 2006/07/02 02:23:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.273 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
+#include "access/reloptions.h"
#include "access/xlog.h"
#include "catalog/heap.h"
#include "catalog/namespace.h"
@@ -45,8 +46,8 @@
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "optimizer/var.h"
-#include "parser/parse_clause.h"
#include "parser/parsetree.h"
+#include "parser/parse_clause.h"
#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/guc.h"
@@ -543,7 +544,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
{
do_select_into = true;
estate->es_select_into = true;
- estate->es_into_oids = parseTree->intoHasOids;
+ estate->es_into_oids = interpretOidsOption(parseTree->intoOptions);
}
/*
@@ -727,10 +728,10 @@ InitPlan(QueryDesc *queryDesc, int eflags)
char *intoName;
Oid namespaceId;
Oid tablespaceId;
+ Datum reloptions;
AclResult aclresult;
Oid intoRelationId;
TupleDesc tupdesc;
- ArrayType *options;
/*
* Check consistency of arguments
@@ -770,6 +771,13 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/* note InvalidOid is OK in this case */
}
+ /* Parse and validate any reloptions */
+ reloptions = transformRelOptions((Datum) 0,
+ parseTree->intoOptions,
+ true,
+ false);
+ (void) heap_reloptions(RELKIND_RELATION, reloptions, true);
+
/* Check permissions except when using the database's default */
if (OidIsValid(tablespaceId))
{
@@ -788,7 +796,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
*/
tupdesc = CreateTupleDescCopy(tupType);
- options = OptionBuild(NULL, parseTree->intoOptions);
intoRelationId = heap_create_with_catalog(intoName,
namespaceId,
tablespaceId,
@@ -800,10 +807,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
true,
0,
parseTree->intoOnCommit,
- allowSystemTableMods,
- options);
- if (options)
- pfree(options);
+ reloptions,
+ allowSystemTableMods);
FreeTupleDesc(tupdesc);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 8ca24c17aa..f818e4a332 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.341 2006/07/02 05:17:26 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.342 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1680,7 +1680,6 @@ _copyQuery(Query *from)
COPY_NODE_FIELD(utilityStmt);
COPY_SCALAR_FIELD(resultRelation);
COPY_NODE_FIELD(into);
- COPY_SCALAR_FIELD(intoHasOids);
COPY_NODE_FIELD(intoOptions);
COPY_SCALAR_FIELD(intoOnCommit);
COPY_STRING_FIELD(intoTableSpaceName);
@@ -2641,7 +2640,6 @@ _copyExecuteStmt(ExecuteStmt *from)
COPY_STRING_FIELD(name);
COPY_NODE_FIELD(into);
- COPY_SCALAR_FIELD(into_has_oids);
COPY_NODE_FIELD(intoOptions);
COPY_SCALAR_FIELD(into_on_commit);
COPY_STRING_FIELD(into_tbl_space);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 424e546b4b..b753fb148c 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.275 2006/07/02 05:17:26 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.276 2006/07/03 22:45:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -658,7 +658,6 @@ _equalQuery(Query *a, Query *b)
COMPARE_NODE_FIELD(utilityStmt);
COMPARE_SCALAR_FIELD(resultRelation);
COMPARE_NODE_FIELD(into);
- COMPARE_SCALAR_FIELD(intoHasOids);
COMPARE_NODE_FIELD(intoOptions);
COMPARE_SCALAR_FIELD(intoOnCommit);
COMPARE_STRING_FIELD(intoTableSpaceName);
@@ -1474,7 +1473,6 @@ _equalExecuteStmt(ExecuteStmt *a, ExecuteStmt *b)
{
COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(into);
- COMPARE_SCALAR_FIELD(into_has_oids);
COMPARE_NODE_FIELD(intoOptions);
COMPARE_SCALAR_FIELD(into_on_commit);
COMPARE_STRING_FIELD(into_tbl_space);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index d865360563..b51127fba9 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.276 2006/07/02 02:23:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.277 2006/07/03 22:45:39 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1509,7 +1509,6 @@ _outQuery(StringInfo str, Query *node)
WRITE_INT_FIELD(resultRelation);
WRITE_NODE_FIELD(into);
- WRITE_BOOL_FIELD(intoHasOids);
WRITE_NODE_FIELD(intoOptions);
WRITE_ENUM_FIELD(intoOnCommit, OnCommitAction);
WRITE_STRING_FIELD(intoTableSpaceName);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 0e061c44c5..883155dcd0 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.190 2006/07/02 02:23:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.191 2006/07/03 22:45:39 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
@@ -140,7 +140,6 @@ _readQuery(void)
READ_NODE_FIELD(utilityStmt);
READ_INT_FIELD(resultRelation);
READ_NODE_FIELD(into);
- READ_BOOL_FIELD(intoHasOids);
READ_NODE_FIELD(intoOptions);
READ_ENUM_FIELD(intoOnCommit, OnCommitAction);
READ_STRING_FIELD(intoTableSpaceName);
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 9e66ca1ab6..0d1adeac18 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.337 2006/07/02 02:23:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.338 2006/07/03 22:45:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1882,7 +1882,6 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
if (stmt->intoColNames)
applyColumnNames(qry->targetList, stmt->intoColNames);
- qry->intoHasOids = interpretOidsOption(stmt->intoOptions);
qry->intoOptions = copyObject(stmt->intoOptions);
qry->intoOnCommit = stmt->intoOnCommit;
qry->intoTableSpaceName = stmt->intoTableSpaceName;
@@ -2754,8 +2753,6 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
paramtypes = FetchPreparedStatementParams(stmt->name);
- stmt->into_has_oids = interpretOidsOption(stmt->intoOptions);
-
if (stmt->params || paramtypes)
{
int nparams = list_length(stmt->params);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index f09a7a6b2d..754777c57b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.550 2006/07/02 02:23:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.551 2006/07/03 22:45:39 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -232,7 +232,7 @@ static void doNegateFloat(Value *v);
func_as createfunc_opt_list alterfunc_opt_list
aggr_args aggr_args_list old_aggr_definition old_aggr_list
oper_argtypes RuleActionList RuleActionMulti
- opt_column_list columnList opt_name_list
+ opt_column_list columnList opt_name_list
sort_clause opt_sort_clause sortby_list index_params
name_list from_clause from_list opt_array_bounds
qualified_name_list any_name any_name_list
@@ -1562,25 +1562,15 @@ alter_rel_cmd:
| SET definition
{
AlterTableCmd *n = makeNode(AlterTableCmd);
- n->subtype = AT_SetOptions;
+ n->subtype = AT_SetRelOptions;
n->def = (Node *)$2;
$$ = (Node *)n;
}
+ /* ALTER [TABLE|INDEX] <name> RESET (...) */
| RESET definition
{
- AlterTableCmd *n;
- ListCell *cell;
-
- foreach(cell, $2)
- {
- if (((DefElem *) lfirst(cell))->arg != NULL)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("parameters for RESET should not take values")));
- }
-
- n = makeNode(AlterTableCmd);
- n->subtype = AT_SetOptions;
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_ResetRelOptions;
n->def = (Node *)$2;
$$ = (Node *)n;
}
@@ -1919,7 +1909,7 @@ ColConstraintElem:
n->indexspace = NULL;
$$ = (Node *)n;
}
- | UNIQUE OptConsTableSpace
+ | UNIQUE opt_definition OptConsTableSpace
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
@@ -1927,7 +1917,8 @@ ColConstraintElem:
n->raw_expr = NULL;
n->cooked_expr = NULL;
n->keys = NULL;
- n->indexspace = $2;
+ n->options = $2;
+ n->indexspace = $3;
$$ = (Node *)n;
}
| PRIMARY KEY opt_definition OptConsTableSpace
@@ -2100,7 +2091,7 @@ ConstraintElem:
n->indexspace = NULL;
$$ = (Node *)n;
}
- | UNIQUE '(' columnList ')' OptConsTableSpace
+ | UNIQUE '(' columnList ')' opt_definition OptConsTableSpace
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
@@ -2108,7 +2099,8 @@ ConstraintElem:
n->raw_expr = NULL;
n->cooked_expr = NULL;
n->keys = $3;
- n->indexspace = $5;
+ n->options = $5;
+ n->indexspace = $6;
$$ = (Node *)n;
}
| PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace
@@ -2214,13 +2206,12 @@ OptInherit: INHERITS '(' qualified_name_list ')' { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
;
+/* WITH (options) is preferred, WITH OIDS and WITHOUT OIDS are legacy forms */
OptWith:
- WITH OIDS { $$ = list_make1(defWithOids(true)); }
- | WITHOUT OIDS { $$ = list_make1(defWithOids(false)); }
- | WITH definition { $$ = $2; }
- | WITH OIDS WITH definition { $$ = lappend($4, defWithOids(true)); }
- | WITHOUT OIDS WITH definition { $$ = lappend($4, defWithOids(false)); }
- | /*EMPTY*/ { $$ = NIL; }
+ WITH definition { $$ = $2; }
+ | WITH OIDS { $$ = list_make1(defWithOids(true)); }
+ | WITHOUT OIDS { $$ = list_make1(defWithOids(false)); }
+ | /*EMPTY*/ { $$ = NIL; }
;
OnCommitOption: ON COMMIT DROP { $$ = ONCOMMIT_DROP; }
@@ -2874,6 +2865,8 @@ def_elem: ColLabel '=' def_arg
/* Note: any simple identifier will be returned as a type name! */
def_arg: func_type { $$ = (Node *)$1; }
+ | func_name_keyword { $$ = (Node *)makeString(pstrdup($1)); }
+ | reserved_keyword { $$ = (Node *)makeString(pstrdup($1)); }
| qual_all_Op { $$ = (Node *)$1; }
| NumericOnly { $$ = (Node *)$1; }
| Sconst { $$ = (Node *)makeString($1); }
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index a4fe1999fe..b83780408e 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.150 2006/07/02 02:23:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.151 2006/07/03 22:45:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,7 +34,6 @@
#include "rewrite/rewriteManip.h"
#include "utils/builtins.h"
#include "utils/guc.h"
-#include "utils/memutils.h"
#define ORDER_CLAUSE 0
@@ -66,8 +65,6 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
Var *l_colvar, Var *r_colvar);
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
List **tlist, int clause);
-static bool OptionMatches(text *t, const char* kw, char **str, Size *len);
-static Datum OptionToText(DefElem *def);
/*
@@ -216,18 +213,18 @@ interpretInhOption(InhOption inhOpt)
}
/*
- * Given a List that indicates whether WITH / WITHOUT OIDS was
- * specified by the user, return true iff the specified table/result
- * set should be created with OIDs. This needs to be done after
- * parsing the query string because the return value can depend upon
- * the default_with_oids GUC var.
+ * Given a relation-options list (of DefElems), return true iff the specified
+ * table/result set should be created with OIDs. This needs to be done after
+ * parsing the query string because the return value can depend upon the
+ * default_with_oids GUC var.
*/
bool
-interpretOidsOption(List *options)
+interpretOidsOption(List *defList)
{
ListCell *cell;
- foreach(cell, options)
+ /* Scan list to see if OIDS was included */
+ foreach(cell, defList)
{
DefElem *def = (DefElem *) lfirst(cell);
@@ -235,264 +232,11 @@ interpretOidsOption(List *options)
return defGetBoolean(def);
}
- /* oids option is not specified. */
+ /* OIDS option was not specified, so use default. */
return default_with_oids;
}
/*
- * Test if t is start with 'kw='.
- */
-static bool
-OptionMatches(text *t, const char* kw, char **str, Size *len)
-{
- char *text_str = (char *) VARATT_DATA(t);
- int text_len = VARATT_SIZE(t) - VARHDRSZ;
- Size kwlen = strlen(kw);
-
- if (text_len > kwlen && text_str[kwlen] == '=' &&
- pg_strncasecmp(text_str, kw, kwlen) == 0)
- {
- *str = text_str + kwlen + 1;
- *len = text_len - kwlen - 1;
- return true;
- }
-
- return false;
-}
-
-/*
- * Flatten a DefElem to a text like as 'defname=arg'.
- */
-static Datum
-OptionToText(DefElem *def)
-{
- text *t;
- char *value = defGetString(def);
- Size len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
-
- t = palloc(len + 1);
- VARATT_SIZEP(t) = len;
- sprintf((char *) VARATT_DATA(t), "%s=%s", def->defname, value);
-
- return PointerGetDatum(t);
-}
-
-/*
- * Merge option array and option list.
- *
- * array Existing option, or NULL if new option.
- * list List of DefElems to be added to array.
- */
-ArrayType *
-OptionBuild(ArrayType *array, List *list)
-{
- ListCell *cell;
- bool *used;
- int index;
- int o;
- ArrayType *result;
- ArrayBuildState *astate;
- MemoryContext myContext;
- MemoryContext oldContext;
-
- if (list_length(list) == 0)
- {
- /* no additinal elements, so just clone. */
- if (array == NULL)
- return NULL;
- result = palloc(VARATT_SIZE(array));
- memcpy(result, array, VARATT_SIZE(array));
- return result;
- }
-
- /* Make a temporary context to hold all the junk */
- myContext = AllocSetContextCreate(CurrentMemoryContext,
- "OptionBuild",
- ALLOCSET_DEFAULT_MINSIZE,
- ALLOCSET_DEFAULT_INITSIZE,
- ALLOCSET_DEFAULT_MAXSIZE);
- oldContext = MemoryContextSwitchTo(myContext);
-
- astate = NULL;
- used = (bool *) palloc0(sizeof(bool) * list_length(list));
-
- if (array)
- {
- Assert(ARR_ELEMTYPE(array) == TEXTOID);
- Assert(ARR_NDIM(array) == 1);
- Assert(ARR_LBOUND(array)[0] == 1);
-
- for (o = 1; o <= ARR_DIMS(array)[0]; o++)
- {
- bool isnull;
- Datum datum;
-
- datum = array_ref(array, 1, &o,
- -1 /* varlenarray */ ,
- -1 /* TEXT's typlen */ ,
- false /* TEXT's typbyval */ ,
- 'i' /* TEXT's typalign */ ,
- &isnull);
- if (isnull)
- continue;
-
- index = 0;
- foreach(cell, list)
- {
- DefElem *def = lfirst(cell);
-
- /*
- * We ignore 'oids' item because it is stored
- * in pg_class.relhasoids.
- */
- if (!used[index] &&
- pg_strcasecmp(def->defname, "oids") != 0)
- {
- char *value_str;
- Size value_len;
- if (OptionMatches(DatumGetTextP(datum),
- def->defname, &value_str, &value_len))
- {
- used[index] = true;
- if (def->arg)
- {
- /* Replace an existing option. */
- datum = OptionToText(def);
- goto next; /* skip remain items in list */
- }
- else
- {
- /* Remove the option from array. */
- goto skip;
- }
- }
- }
-
- index++;
- }
-
- /*
- * The datum is an existing parameter and is not modified.
- * Fall down.
- */
-
-next:
- astate = accumArrayResult(astate, datum, false, TEXTOID, myContext);
-skip:
- ;
- }
- }
-
- /*
- * add options not in array
- */
- index = 0;
- foreach(cell, list)
- {
- DefElem *def = lfirst(cell);
-
- if (!used[index] && def->arg &&
- pg_strcasecmp(def->defname, "oids") != 0)
- {
- astate = accumArrayResult(astate, OptionToText(def),
- false, TEXTOID, myContext);
- }
-
- index++;
- }
-
- if (astate)
- result = DatumGetArrayTypeP(makeArrayResult(astate, oldContext));
- else
- result = NULL;
-
- MemoryContextSwitchTo(oldContext);
- MemoryContextDelete(myContext);
- return result;
-}
-
-/*
- * Support routine to parse options.
- *
- * options List of DefElems
- * num length of kwds
- * kwds supported keywords
- * strict Throw error if unsupported option is found.
- *
- * FIXME: memory is leaked in kwds[].arg.
- */
-void
-OptionParse(ArrayType *options, Size num, DefElem kwds[], bool strict)
-{
- Size k;
- int o;
-
- for (k = 0; k < num; k++)
- {
- Assert(kwds[k].defname);
- kwds[k].arg = NULL;
- }
-
- if (options == NULL)
- return; /* use default for all */
-
- Assert(ARR_ELEMTYPE(options) == TEXTOID);
- Assert(ARR_NDIM(options) == 1);
- Assert(ARR_LBOUND(options)[0] == 1);
-
- for (o = 1; o <= ARR_DIMS(options)[0]; o++)
- {
- bool isnull;
- Datum datum;
-
- datum = array_ref(options, 1, &o,
- -1 /* varlenarray */ ,
- -1 /* TEXT's typlen */ ,
- false /* TEXT's typbyval */ ,
- 'i' /* TEXT's typalign */ ,
- &isnull);
- if (isnull)
- continue;
-
- for (k = 0; k < num; k++)
- {
- char *value_str;
- Size value_len;
-
- if (OptionMatches(DatumGetTextP(datum),
- kwds[k].defname, &value_str, &value_len))
- {
- char *value;
-
- if (kwds[k].arg != NULL)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("duplicated parameter %s",
- kwds[k].defname)));
-
- /* copy value as Value node */
- value = (char *) palloc(value_len + 1);
- strncpy(value, value_str, value_len);
- value[value_len] = '\0';
- kwds[k].arg = (Node *) makeString(value);
- goto next; /* skip remain keywords */
- }
- }
-
- /* parameter is not in kwds */
- if (strict)
- {
- char *c = DatumGetCString(DirectFunctionCall1(textout, datum));
-
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("unsupported parameter %s", c)));
- }
-next:;
- }
-}
-
-/*
* Extract all not-in-common columns from column lists of a source table
*/
static void
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 2ddbb64763..8e51b40d71 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.225 2006/07/02 02:23:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.226 2006/07/03 22:45:39 tgl Exp $
**********************************************************************/
#include "postgres.h"
@@ -757,20 +757,23 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
}
if (!colno)
+ {
appendStringInfoChar(&buf, ')');
- /*
- * If it has options, append "WITH (options)"
- */
- str = flatten_reloptions(indexrelid);
- if (str)
- {
- appendStringInfo(&buf, " WITH (%s)", str);
- pfree(str);
- }
+ /*
+ * If it has options, append "WITH (options)"
+ */
+ str = flatten_reloptions(indexrelid);
+ if (str)
+ {
+ appendStringInfo(&buf, " WITH (%s)", str);
+ pfree(str);
+ }
+
+ /*
+ * XXX we don't include the tablespace ... this is for pg_dump
+ */
- if (!colno)
- {
/*
* If it's a partial index, decompile and append the predicate
*/
@@ -1020,6 +1023,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
if (fullCommand && OidIsValid(conForm->conrelid))
{
char *options = flatten_reloptions(conForm->conrelid);
+
if (options)
{
appendStringInfo(&buf, " WITH (%s)", options);
@@ -4937,35 +4941,42 @@ string_to_text(char *str)
return result;
}
+/*
+ * Generate a C string representing a relation's reloptions, or NULL if none.
+ */
static char *
flatten_reloptions(Oid relid)
{
- HeapTuple tuple;
char *result = NULL;
+ HeapTuple tuple;
+ Datum reloptions;
+ bool isnull;
tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
- if (tuple)
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+
+ reloptions = SysCacheGetAttr(RELOID, tuple,
+ Anum_pg_class_reloptions, &isnull);
+ if (!isnull)
{
- bool isnull;
- Datum reloptions;
- reloptions = SysCacheGetAttr(RELOID, tuple,
- Anum_pg_class_reloptions, &isnull);
- if (!isnull)
- {
- Datum sep,
- txt;
- sep = DirectFunctionCall1(textin, CStringGetDatum(", "));
- /*
- * OID 395 = array_to_text.
- * DirectFunctionCall2(array_to_text) is not available here.
- */
- txt = OidFunctionCall2(395, reloptions, sep);
- result = DatumGetCString(DirectFunctionCall1(textout, txt));
- }
- ReleaseSysCache(tuple);
+ Datum sep,
+ txt;
+
+ /*
+ * We want to use array_to_text(reloptions, ', ') --- but
+ * DirectFunctionCall2(array_to_text) does not work, because
+ * array_to_text() relies on flinfo to be valid. So use
+ * OidFunctionCall2.
+ */
+ sep = DirectFunctionCall1(textin, CStringGetDatum(", "));
+ txt = OidFunctionCall2(F_ARRAY_TO_TEXT, reloptions, sep);
+ result = DatumGetCString(DirectFunctionCall1(textout, txt));
}
+ ReleaseSysCache(tuple);
+
return result;
}
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 50edf7691a..a806080fd0 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.243 2006/07/02 02:23:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.244 2006/07/03 22:45:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,6 +32,7 @@
#include "access/genam.h"
#include "access/heapam.h"
+#include "access/reloptions.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
@@ -47,8 +48,6 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_type.h"
-#include "catalog/heap.h"
-#include "catalog/index.h"
#include "commands/trigger.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
@@ -56,7 +55,6 @@
#include "optimizer/prep.h"
#include "storage/fd.h"
#include "storage/smgr.h"
-#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/fmgroids.h"
@@ -186,17 +184,19 @@ static void RelationClearRelation(Relation relation, bool rebuild);
static void RelationReloadClassinfo(Relation relation);
static void RelationFlushRelation(Relation relation);
static bool load_relcache_init_file(void);
-static void write_item(const void *data, Size len, FILE *fp);
static void write_relcache_init_file(void);
+static void write_item(const void *data, Size len, FILE *fp);
static void formrdesc(const char *relationName, Oid relationReltype,
bool hasoids, int natts, FormData_pg_attribute *att);
static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK);
static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
+static void RelationParseRelOptions(Relation relation, HeapTuple tuple);
static void RelationBuildTupleDesc(Relation relation);
static Relation RelationBuildDesc(Oid targetRelId, Relation oldrelation);
static void RelationInitPhysicalAddr(Relation relation);
+static TupleDesc GetPgClassDescriptor(void);
static TupleDesc GetPgIndexDescriptor(void);
static void AttrDefaultFetch(Relation relation);
static void CheckConstraintFetch(Relation relation);
@@ -210,7 +210,6 @@ static void IndexSupportInitialize(oidvector *indclass,
static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
StrategyNumber numStrats,
StrategyNumber numSupport);
-static void RelationParseOptions(Relation relation, HeapTuple tuple);
/*
@@ -303,10 +302,13 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp)
* Copy the relation tuple form
*
* We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE.
- * relacl is NOT stored in the relcache --- there'd be little point in it,
- * since we don't copy the tuple's nullvalues bitmap and hence wouldn't
- * know if the value is valid ... bottom line is that relacl *cannot* be
- * retrieved from the relcache. Get it from the syscache if you need it.
+ * The variable-length fields (relacl, reloptions) are NOT stored in the
+ * relcache --- there'd be little point in it, since we don't copy the
+ * tuple's nulls bitmap and hence wouldn't know if the values are valid.
+ * Bottom line is that relacl *cannot* be retrieved from the relcache.
+ * Get it from the syscache if you need it. The same goes for the
+ * original form of reloptions (however, we do store the parsed form
+ * of reloptions in rd_options).
*/
relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
@@ -314,7 +316,6 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp)
/* initialize relation tuple form */
relation->rd_rel = relationForm;
- relation->rd_options = NULL;
/* and allocate attribute tuple form storage */
relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,
@@ -328,49 +329,71 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp)
}
/*
- * RelationParseOptions
+ * RelationParseRelOptions
+ * Convert pg_class.reloptions into pre-parsed rd_options
+ *
+ * tuple is the real pg_class tuple (not rd_rel!) for relation
+ *
+ * Note: rd_rel and (if an index) rd_am must be valid already
*/
static void
-RelationParseOptions(Relation relation, HeapTuple tuple)
+RelationParseRelOptions(Relation relation, HeapTuple tuple)
{
- ArrayType *options;
+ Datum datum;
+ bool isnull;
+ bytea *options;
- Assert(tuple);
+ relation->rd_options = NULL;
+ /* Fall out if relkind should not have options */
switch (relation->rd_rel->relkind)
{
- case RELKIND_RELATION:
- case RELKIND_TOASTVALUE:
- case RELKIND_UNCATALOGED:
- case RELKIND_INDEX:
- break;
- default:
- /* other relation should not have options. */
- relation->rd_options = NULL;
- return;
+ case RELKIND_RELATION:
+ case RELKIND_TOASTVALUE:
+ case RELKIND_UNCATALOGED:
+ case RELKIND_INDEX:
+ break;
+ default:
+ return;
}
- /* SysCacheGetAttr is not available here. */
- if (heap_attisnull(tuple, Anum_pg_class_reloptions))
- options = NULL;
- else
- options = (ArrayType *) ((Form_pg_class) GETSTRUCT(tuple))->reloptions;
+ /*
+ * Fetch reloptions from tuple; have to use a hardwired descriptor
+ * because we might not have any other for pg_class yet (consider
+ * executing this code for pg_class itself)
+ */
+ datum = fastgetattr(tuple,
+ Anum_pg_class_reloptions,
+ GetPgClassDescriptor(),
+ &isnull);
+ if (isnull)
+ return;
+ /* Parse into appropriate format; don't error out here */
switch (relation->rd_rel->relkind)
{
- case RELKIND_RELATION:
- case RELKIND_TOASTVALUE:
- case RELKIND_UNCATALOGED:
- relation->rd_options = heap_option(
- relation->rd_rel->relkind, options);
- break;
- case RELKIND_INDEX:
- relation->rd_options = index_option(
- relation->rd_am->amoption, options);
- break;
- default:
- /* should not happen */
- break;
+ case RELKIND_RELATION:
+ case RELKIND_TOASTVALUE:
+ case RELKIND_UNCATALOGED:
+ options = heap_reloptions(relation->rd_rel->relkind, datum,
+ false);
+ break;
+ case RELKIND_INDEX:
+ options = index_reloptions(relation->rd_am->amoptions, datum,
+ false);
+ break;
+ default:
+ Assert(false); /* can't get here */
+ options = NULL; /* keep compiler quiet */
+ break;
+ }
+
+ /* Copy parsed data into CacheMemoryContext */
+ if (options)
+ {
+ relation->rd_options = MemoryContextAlloc(CacheMemoryContext,
+ VARSIZE(options));
+ memcpy(relation->rd_options, options, VARSIZE(options));
}
}
@@ -820,6 +843,9 @@ RelationBuildDesc(Oid targetRelId, Relation oldrelation)
if (OidIsValid(relation->rd_rel->relam))
RelationInitIndexAccessInfo(relation);
+ /* extract reloptions if any */
+ RelationParseRelOptions(relation, pg_class_tuple);
+
/*
* initialize the relation lock manager information
*/
@@ -833,9 +859,6 @@ RelationBuildDesc(Oid targetRelId, Relation oldrelation)
/* make sure relation is marked as having no open file yet */
relation->rd_smgr = NULL;
- /* Build AM-specific fields. */
- RelationParseOptions(relation, pg_class_tuple);
-
/*
* now we can free the memory allocated for pg_class_tuple
*/
@@ -1266,7 +1289,6 @@ formrdesc(const char *relationName, Oid relationReltype,
* data from pg_class and replace what we've done here.
*/
relation->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE);
- relation->rd_options = NULL;
namestrcpy(&relation->rd_rel->relname, relationName);
relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE;
@@ -1355,11 +1377,6 @@ formrdesc(const char *relationName, Oid relationReltype,
}
/*
- * initialize the rd_options field to default value
- */
- relation->rd_options = heap_option(RELKIND_RELATION, NULL);
-
- /*
* add new reldesc to relcache
*/
RelationCacheInsert(relation);
@@ -1537,9 +1554,11 @@ RelationReloadClassinfo(Relation relation)
RelationGetRelid(relation));
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
+ /* Reload reloptions in case they changed */
if (relation->rd_options)
pfree(relation->rd_options);
- RelationParseOptions(relation, pg_class_tuple);
+ RelationParseRelOptions(relation, pg_class_tuple);
+ /* done with pg_class tuple */
heap_freetuple(pg_class_tuple);
/* We must recalculate physical address in case it changed */
RelationInitPhysicalAddr(relation);
@@ -2178,7 +2197,6 @@ RelationBuildLocalRelation(const char *relname,
* initialize relation tuple form (caller may add/override data later)
*/
rel->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE);
- rel->rd_options = NULL;
namestrcpy(&rel->rd_rel->relname, relname);
rel->rd_rel->relnamespace = relnamespace;
@@ -2412,6 +2430,11 @@ RelationCacheInitializePhase2(void)
Assert(relation->rd_rel != NULL);
memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
+ /* Update rd_options while we have the tuple */
+ if (relation->rd_options)
+ pfree(relation->rd_options);
+ RelationParseRelOptions(relation, htup);
+
/*
* Also update the derived fields in rd_att.
*/
@@ -2450,49 +2473,72 @@ RelationCacheInitializePhase2(void)
}
/*
+ * GetPgClassDescriptor -- get a predefined tuple descriptor for pg_class
* GetPgIndexDescriptor -- get a predefined tuple descriptor for pg_index
*
* We need this kluge because we have to be able to access non-fixed-width
- * fields of pg_index before we have the standard catalog caches available.
- * We use predefined data that's set up in just the same way as the
- * bootstrapped reldescs used by formrdesc(). The resulting tupdesc is
- * not 100% kosher: it does not have the correct rowtype OID in tdtypeid,
- * nor does it have a TupleConstr field. But it's good enough for the
- * purpose of extracting fields.
+ * fields of pg_class and pg_index before we have the standard catalog caches
+ * available. We use predefined data that's set up in just the same way as
+ * the bootstrapped reldescs used by formrdesc(). The resulting tupdesc is
+ * not 100% kosher: it does not have the correct rowtype OID in tdtypeid, nor
+ * does it have a TupleConstr field. But it's good enough for the purpose of
+ * extracting fields.
*/
static TupleDesc
-GetPgIndexDescriptor(void)
+BuildHardcodedDescriptor(int natts, Form_pg_attribute attrs, bool hasoids)
{
- static TupleDesc pgindexdesc = NULL;
+ TupleDesc result;
MemoryContext oldcxt;
int i;
- /* Already done? */
- if (pgindexdesc)
- return pgindexdesc;
-
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
- pgindexdesc = CreateTemplateTupleDesc(Natts_pg_index, false);
- pgindexdesc->tdtypeid = RECORDOID; /* not right, but we don't care */
- pgindexdesc->tdtypmod = -1;
+ result = CreateTemplateTupleDesc(natts, hasoids);
+ result->tdtypeid = RECORDOID; /* not right, but we don't care */
+ result->tdtypmod = -1;
- for (i = 0; i < Natts_pg_index; i++)
+ for (i = 0; i < natts; i++)
{
- memcpy(pgindexdesc->attrs[i],
- &Desc_pg_index[i],
- ATTRIBUTE_TUPLE_SIZE);
+ memcpy(result->attrs[i], &attrs[i], ATTRIBUTE_TUPLE_SIZE);
/* make sure attcacheoff is valid */
- pgindexdesc->attrs[i]->attcacheoff = -1;
+ result->attrs[i]->attcacheoff = -1;
}
/* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
- pgindexdesc->attrs[0]->attcacheoff = 0;
+ result->attrs[0]->attcacheoff = 0;
/* Note: we don't bother to set up a TupleConstr entry */
MemoryContextSwitchTo(oldcxt);
+ return result;
+}
+
+static TupleDesc
+GetPgClassDescriptor(void)
+{
+ static TupleDesc pgclassdesc = NULL;
+
+ /* Already done? */
+ if (pgclassdesc == NULL)
+ pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
+ Desc_pg_class,
+ true);
+
+ return pgclassdesc;
+}
+
+static TupleDesc
+GetPgIndexDescriptor(void)
+{
+ static TupleDesc pgindexdesc = NULL;
+
+ /* Already done? */
+ if (pgindexdesc == NULL)
+ pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
+ Desc_pg_index,
+ false);
+
return pgindexdesc;
}
@@ -3109,7 +3155,7 @@ load_relcache_init_file(void)
if ((nread = fread(rel->rd_options, 1, len, fp)) != len)
goto read_failed;
if (len != VARATT_SIZE(rel->rd_options))
- goto read_failed;
+ goto read_failed; /* sanity check */
}
else
{
@@ -3299,15 +3345,6 @@ read_failed:
return false;
}
-static void
-write_item(const void *data, Size len, FILE *fp)
-{
- if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
- elog(FATAL, "could not write init file");
- if (fwrite(data, 1, len, fp) != len)
- elog(FATAL, "could not write init file");
-}
-
/*
* Write out a new initialization file with the current contents
* of the relcache.
@@ -3380,13 +3417,13 @@ write_relcache_init_file(void)
/* next, do all the attribute tuple form data entries */
for (i = 0; i < relform->relnatts; i++)
{
- write_item(rel->rd_att->attrs[i],
- ATTRIBUTE_TUPLE_SIZE, fp);
+ write_item(rel->rd_att->attrs[i], ATTRIBUTE_TUPLE_SIZE, fp);
}
/* next, do the access method specific field */
write_item(rel->rd_options,
- (rel->rd_options ? VARATT_SIZE(rel->rd_options) : 0), fp);
+ (rel->rd_options ? VARATT_SIZE(rel->rd_options) : 0),
+ fp);
/* If it's an index, there's more to do */
if (rel->rd_rel->relkind == RELKIND_INDEX)
@@ -3396,18 +3433,21 @@ write_relcache_init_file(void)
/* write the pg_index tuple */
/* we assume this was created by heap_copytuple! */
write_item(rel->rd_indextuple,
- HEAPTUPLESIZE + rel->rd_indextuple->t_len, fp);
+ HEAPTUPLESIZE + rel->rd_indextuple->t_len,
+ fp);
/* next, write the access method tuple form */
write_item(am, sizeof(FormData_pg_am), fp);
/* next, write the vector of operator OIDs */
- write_item(rel->rd_operator, relform->relnatts *
- (am->amstrategies * sizeof(Oid)), fp);
+ write_item(rel->rd_operator,
+ relform->relnatts * (am->amstrategies * sizeof(Oid)),
+ fp);
/* finally, write the vector of support procedures */
- write_item(rel->rd_support, relform->relnatts *
- (am->amsupport * sizeof(RegProcedure)), fp);
+ write_item(rel->rd_support,
+ relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
+ fp);
}
/* also make a list of their OIDs, for RelationIdIsInInitFile */
@@ -3463,6 +3503,16 @@ write_relcache_init_file(void)
LWLockRelease(RelCacheInitLock);
}
+/* write a chunk of data preceded by its length */
+static void
+write_item(const void *data, Size len, FILE *fp)
+{
+ if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+ elog(FATAL, "could not write init file");
+ if (fwrite(data, 1, len, fp) != len)
+ elog(FATAL, "could not write init file");
+}
+
/*
* Detect whether a given relation (identified by OID) is one of the ones
* we store in the init file.