aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/reloptions.c645
-rw-r--r--src/backend/access/gin/ginutil.c13
-rw-r--r--src/backend/access/gist/gistutil.c7
-rw-r--r--src/backend/access/hash/hashutil.c7
-rw-r--r--src/backend/access/nbtree/nbtutils.c6
-rw-r--r--src/include/access/reloptions.h167
-rw-r--r--src/include/catalog/catversion.h4
7 files changed, 716 insertions, 133 deletions
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index ec2abcb2984..3401667b9e4 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -8,13 +8,16 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.12 2009/01/01 17:23:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.13 2009/01/05 17:14:28 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include "access/gist_private.h"
+#include "access/hash.h"
+#include "access/nbtree.h"
#include "access/reloptions.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
@@ -22,8 +25,357 @@
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/memutils.h"
#include "utils/rel.h"
+/*
+ * Contents of pg_class.reloptions
+ *
+ * To add an option:
+ *
+ * (i) decide on a class (integer, real, bool, string), name, default value,
+ * upper and lower bounds (if applicable).
+ * (ii) add a record below.
+ * (iii) add it to StdRdOptions if appropriate
+ * (iv) add a block to the appropriate handling routine (probably
+ * default_reloptions)
+ * (v) don't forget to document the option
+ *
+ * Note that we don't handle "oids" in relOpts because it is handled by
+ * interpretOidsOption().
+ */
+
+static relopt_bool boolRelOpts[] =
+{
+ /* list terminator */
+ { { NULL } }
+};
+
+static relopt_int intRelOpts[] =
+{
+ {
+ {
+ "fillfactor",
+ "Packs table pages only to this percentage",
+ RELOPT_KIND_HEAP
+ },
+ HEAP_DEFAULT_FILLFACTOR, HEAP_MIN_FILLFACTOR, 100
+ },
+ {
+ {
+ "fillfactor",
+ "Packs btree index pages only to this percentage",
+ RELOPT_KIND_BTREE
+ },
+ BTREE_DEFAULT_FILLFACTOR, BTREE_MIN_FILLFACTOR, 100
+ },
+ {
+ {
+ "fillfactor",
+ "Packs hash index pages only to this percentage",
+ RELOPT_KIND_HASH
+ },
+ HASH_DEFAULT_FILLFACTOR, HASH_MIN_FILLFACTOR, 100
+ },
+ {
+ {
+ "fillfactor",
+ "Packs gist index pages only to this percentage",
+ RELOPT_KIND_GIST
+ },
+ GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100
+ },
+ /* list terminator */
+ { { NULL } }
+};
+
+static relopt_real realRelOpts[] =
+{
+ /* list terminator */
+ { { NULL } }
+};
+
+static relopt_string stringRelOpts[] =
+{
+ /* list terminator */
+ { { NULL } }
+};
+
+static relopt_gen **relOpts = NULL;
+static int last_assigned_kind = RELOPT_KIND_LAST_DEFAULT + 1;
+
+static int num_custom_options = 0;
+static relopt_gen **custom_options = NULL;
+static bool need_initialization = true;
+
+static void initialize_reloptions(void);
+static void parse_one_reloption(relopt_value *option, char *text_str,
+ int text_len, bool validate);
+
+/*
+ * initialize_reloptions
+ * initialization routine, must be called before parsing
+ *
+ * Initialize the relOpts array and fill each variable's type and name length.
+ */
+static void
+initialize_reloptions(void)
+{
+ int i;
+ int j = 0;
+
+ for (i = 0; boolRelOpts[i].gen.name; i++)
+ j++;
+ for (i = 0; intRelOpts[i].gen.name; i++)
+ j++;
+ for (i = 0; realRelOpts[i].gen.name; i++)
+ j++;
+ for (i = 0; stringRelOpts[i].gen.name; i++)
+ j++;
+ j += num_custom_options;
+
+ if (relOpts)
+ pfree(relOpts);
+ relOpts = MemoryContextAlloc(TopMemoryContext,
+ (j + 1) * sizeof(relopt_gen *));
+
+ j = 0;
+ for (i = 0; boolRelOpts[i].gen.name; i++)
+ {
+ relOpts[j] = &boolRelOpts[i].gen;
+ relOpts[j]->type = RELOPT_TYPE_BOOL;
+ relOpts[j]->namelen = strlen(relOpts[j]->name);
+ j++;
+ }
+
+ for (i = 0; intRelOpts[i].gen.name; i++)
+ {
+ relOpts[j] = &intRelOpts[i].gen;
+ relOpts[j]->type = RELOPT_TYPE_INT;
+ relOpts[j]->namelen = strlen(relOpts[j]->name);
+ j++;
+ }
+
+ for (i = 0; realRelOpts[i].gen.name; i++)
+ {
+ relOpts[j] = &realRelOpts[i].gen;
+ relOpts[j]->type = RELOPT_TYPE_REAL;
+ relOpts[j]->namelen = strlen(relOpts[j]->name);
+ j++;
+ }
+
+ for (i = 0; stringRelOpts[i].gen.name; i++)
+ {
+ relOpts[j] = &stringRelOpts[i].gen;
+ relOpts[j]->type = RELOPT_TYPE_STRING;
+ relOpts[j]->namelen = strlen(relOpts[j]->name);
+ j++;
+ }
+
+ for (i = 0; i < num_custom_options; i++)
+ {
+ relOpts[j] = custom_options[i];
+ j++;
+ }
+
+ /* add a list terminator */
+ relOpts[j] = NULL;
+}
+
+/*
+ * add_reloption_kind
+ * Create a new relopt_kind value, to be used in custom reloptions by
+ * user-defined AMs.
+ */
+int
+add_reloption_kind(void)
+{
+ if (last_assigned_kind >= RELOPT_KIND_MAX)
+ ereport(ERROR,
+ (errmsg("user-defined relation parameter types limit exceeded")));
+
+ return last_assigned_kind++;
+}
+
+/*
+ * add_reloption
+ * Add an already-created custom reloption to the list, and recompute the
+ * main parser table.
+ */
+static void
+add_reloption(relopt_gen *newoption)
+{
+ static int max_custom_options = 0;
+
+ if (num_custom_options >= max_custom_options)
+ {
+ MemoryContext oldcxt;
+
+ oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+
+ if (max_custom_options == 0)
+ {
+ max_custom_options = 8;
+ custom_options = palloc(max_custom_options * sizeof(relopt_gen *));
+ }
+ else
+ {
+ max_custom_options *= 2;
+ custom_options = repalloc(custom_options,
+ max_custom_options * sizeof(relopt_gen *));
+ }
+ MemoryContextSwitchTo(oldcxt);
+ }
+ custom_options[num_custom_options++] = newoption;
+
+ need_initialization = true;
+}
+
+/*
+ * allocate_reloption
+ * Allocate a new reloption and initialize the type-agnostic fields
+ * (for types other than string)
+ */
+static relopt_gen *
+allocate_reloption(int kind, int type, char *name, char *desc)
+{
+ MemoryContext oldcxt;
+ size_t size;
+ relopt_gen *newoption;
+
+ Assert(type != RELOPT_TYPE_STRING);
+
+ oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+
+ switch (type)
+ {
+ case RELOPT_TYPE_BOOL:
+ size = sizeof(relopt_bool);
+ break;
+ case RELOPT_TYPE_INT:
+ size = sizeof(relopt_int);
+ break;
+ case RELOPT_TYPE_REAL:
+ size = sizeof(relopt_real);
+ break;
+ default:
+ elog(ERROR, "unsupported option type");
+ return NULL; /* keep compiler quiet */
+ }
+
+ newoption = palloc(size);
+
+ newoption->name = pstrdup(name);
+ if (desc)
+ newoption->desc = pstrdup(desc);
+ else
+ newoption->desc = NULL;
+ newoption->kind = kind;
+ newoption->namelen = strlen(name);
+ newoption->type = type;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ return newoption;
+}
+
+/*
+ * add_bool_reloption
+ * Add a new boolean reloption
+ */
+void
+add_bool_reloption(int kind, char *name, char *desc, bool default_val)
+{
+ relopt_bool *newoption;
+
+ newoption = (relopt_bool *) allocate_reloption(kind, RELOPT_TYPE_BOOL,
+ name, desc);
+ newoption->default_val = default_val;
+
+ add_reloption((relopt_gen *) newoption);
+}
+
+/*
+ * add_int_reloption
+ * Add a new integer reloption
+ */
+void
+add_int_reloption(int kind, char *name, char *desc, int default_val,
+ int min_val, int max_val)
+{
+ relopt_int *newoption;
+
+ newoption = (relopt_int *) allocate_reloption(kind, RELOPT_TYPE_INT,
+ name, desc);
+ newoption->default_val = default_val;
+ newoption->min = min_val;
+ newoption->max = max_val;
+
+ add_reloption((relopt_gen *) newoption);
+}
+
+/*
+ * add_real_reloption
+ * Add a new float reloption
+ */
+void
+add_real_reloption(int kind, char *name, char *desc, double default_val,
+ double min_val, double max_val)
+{
+ relopt_real *newoption;
+
+ newoption = (relopt_real *) allocate_reloption(kind, RELOPT_TYPE_REAL,
+ name, desc);
+ newoption->default_val = default_val;
+ newoption->min = min_val;
+ newoption->max = max_val;
+
+ add_reloption((relopt_gen *) newoption);
+}
+
+/*
+ * add_string_reloption
+ * Add a new string reloption
+ */
+void
+add_string_reloption(int kind, char *name, char *desc, char *default_val)
+{
+ MemoryContext oldcxt;
+ relopt_string *newoption;
+ int default_len = 0;
+
+ oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+
+ if (default_val)
+ default_len = strlen(default_val);
+
+ newoption = palloc0(sizeof(relopt_string) + default_len);
+
+ newoption->gen.name = pstrdup(name);
+ if (desc)
+ newoption->gen.desc = pstrdup(desc);
+ else
+ newoption->gen.desc = NULL;
+ newoption->gen.kind = kind;
+ newoption->gen.namelen = strlen(name);
+ newoption->gen.type = RELOPT_TYPE_STRING;
+ if (default_val)
+ {
+ strcpy(newoption->default_val, default_val);
+ newoption->default_len = default_len;
+ newoption->default_isnull = false;
+ }
+ else
+ {
+ newoption->default_val[0] = '\0';
+ newoption->default_len = 0;
+ newoption->default_isnull = true;
+ }
+
+ MemoryContextSwitchTo(oldcxt);
+
+ add_reloption((relopt_gen *) newoption);
+}
/*
* Transform a relation options list (list of DefElem) into the text array
@@ -198,147 +550,244 @@ untransformRelOptions(Datum options)
/*
* 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.
+ * options is a reloption text array as constructed by transformRelOptions.
+ * kind specifies the family of options to be processed.
+ *
+ * The return value is a relopt_value * array on which the options actually
+ * set in the options array are marked with isset=true. The length of this
+ * array is returned in *numrelopts. Options not set are also present in the
+ * array; this is so that the caller can easily locate the default values.
*
- * 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.
+ * If there are no options of the given kind, numrelopts is set to 0 and NULL
+ * is returned.
+ *
+ * Note: values of type int, bool and real are allocated as part of the
+ * returned array. Values of type string are allocated separately and must
+ * be freed by the caller.
*/
-void
-parseRelOptions(Datum options, int numkeywords, const char *const * keywords,
- char **values, bool validate)
+relopt_value *
+parseRelOptions(Datum options, bool validate, relopt_kind kind,
+ int *numrelopts)
{
- ArrayType *array;
- Datum *optiondatums;
- int noptions;
+ relopt_value *reloptions;
+ int numoptions = 0;
int i;
+ int j;
- /* Initialize to "all defaulted" */
- MemSet(values, 0, numkeywords * sizeof(char *));
+ if (need_initialization)
+ initialize_reloptions();
- /* Done if no options */
- if (!PointerIsValid(DatumGetPointer(options)))
- return;
+ /* Build a list of expected options, based on kind */
- array = DatumGetArrayTypeP(options);
+ for (i = 0; relOpts[i]; i++)
+ if (relOpts[i]->kind == kind)
+ numoptions++;
- Assert(ARR_ELEMTYPE(array) == TEXTOID);
+ if (numoptions == 0)
+ {
+ *numrelopts = 0;
+ return NULL;
+ }
- deconstruct_array(array, TEXTOID, -1, false, 'i',
- &optiondatums, NULL, &noptions);
+ reloptions = palloc(numoptions * sizeof(relopt_value));
- for (i = 0; i < noptions; i++)
+ for (i = 0, j = 0; relOpts[i]; i++)
+ {
+ if (relOpts[i]->kind == kind)
+ {
+ reloptions[j].gen = relOpts[i];
+ reloptions[j].isset = false;
+ j++;
+ }
+ }
+
+ /* Done if no options */
+ if (PointerIsValid(DatumGetPointer(options)))
{
- text *optiontext = DatumGetTextP(optiondatums[i]);
- char *text_str = VARDATA(optiontext);
- int text_len = VARSIZE(optiontext) - VARHDRSZ;
- int j;
+ ArrayType *array;
+ Datum *optiondatums;
+ int noptions;
+
+ array = DatumGetArrayTypeP(options);
+
+ Assert(ARR_ELEMTYPE(array) == TEXTOID);
+
+ deconstruct_array(array, TEXTOID, -1, false, 'i',
+ &optiondatums, NULL, &noptions);
- /* Search for a match in keywords */
- for (j = 0; j < numkeywords; j++)
+ for (i = 0; i < noptions; i++)
{
- int kw_len = strlen(keywords[j]);
+ text *optiontext = DatumGetTextP(optiondatums[i]);
+ char *text_str = VARDATA(optiontext);
+ int text_len = VARSIZE(optiontext) - VARHDRSZ;
+ int j;
- if (text_len > kw_len && text_str[kw_len] == '=' &&
- pg_strncasecmp(text_str, keywords[j], kw_len) == 0)
+ /* Search for a match in reloptions */
+ for (j = 0; j < numoptions; j++)
{
- char *value;
- int value_len;
+ int kw_len = reloptions[j].gen->namelen;
- if (values[j] && validate)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("parameter \"%s\" specified more than once",
- 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 (text_len > kw_len && text_str[kw_len] == '=' &&
+ pg_strncasecmp(text_str, reloptions[j].gen->name,
+ kw_len) == 0)
+ {
+ parse_one_reloption(&reloptions[j], text_str, text_len,
+ validate);
+ break;
+ }
+ }
+
+ if (j >= numoptions && validate)
+ {
+ char *s;
+ char *p;
+
+ s = TextDatumGetCString(optiondatums[i]);
+ p = strchr(s, '=');
+ if (p)
+ *p = '\0';
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized parameter \"%s\"", s)));
}
- }
- if (j >= numkeywords && validate)
- {
- char *s;
- char *p;
-
- s = TextDatumGetCString(optiondatums[i]);
- p = strchr(s, '=');
- if (p)
- *p = '\0';
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("unrecognized parameter \"%s\"", s)));
}
}
+
+ *numrelopts = numoptions;
+ return reloptions;
}
+/*
+ * Subroutine for parseRelOptions, to parse and validate a single option's
+ * value
+ */
+static void
+parse_one_reloption(relopt_value *option, char *text_str, int text_len,
+ bool validate)
+{
+ char *value;
+ int value_len;
+ bool parsed;
+ bool nofree = false;
+
+ if (option->isset && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter \"%s\" specified more than once",
+ option->gen->name)));
+
+ value_len = text_len - option->gen->namelen - 1;
+ value = (char *) palloc(value_len + 1);
+ memcpy(value, text_str + option->gen->namelen + 1, value_len);
+ value[value_len] = '\0';
+
+ switch (option->gen->type)
+ {
+ case RELOPT_TYPE_BOOL:
+ {
+ parsed = parse_bool(value, &option->values.bool_val);
+ if (validate && !parsed)
+ ereport(ERROR,
+ (errmsg("invalid value for boolean option \"%s\": %s",
+ option->gen->name, value)));
+ }
+ break;
+ case RELOPT_TYPE_INT:
+ {
+ relopt_int *optint = (relopt_int *) option->gen;
+
+ parsed = parse_int(value, &option->values.int_val, 0, NULL);
+ if (validate && !parsed)
+ ereport(ERROR,
+ (errmsg("invalid value for integer option \"%s\": %s",
+ option->gen->name, value)));
+ if (validate && (option->values.int_val < optint->min ||
+ option->values.int_val > optint->max))
+ ereport(ERROR,
+ (errmsg("value %s out of bounds for option \"%s\"",
+ value, option->gen->name),
+ errdetail("Valid values are between \"%d\" and \"%d\".",
+ optint->min, optint->max)));
+ }
+ break;
+ case RELOPT_TYPE_REAL:
+ {
+ relopt_real *optreal = (relopt_real *) option->gen;
+
+ parsed = parse_real(value, &option->values.real_val);
+ if (validate && !parsed)
+ ereport(ERROR,
+ (errmsg("invalid value for floating point option \"%s\": %s",
+ option->gen->name, value)));
+ if (validate && (option->values.real_val < optreal->min ||
+ option->values.real_val > optreal->max))
+ ereport(ERROR,
+ (errmsg("value %s out of bounds for option \"%s\"",
+ value, option->gen->name),
+ errdetail("Valid values are between \"%f\" and \"%f\".",
+ optreal->min, optreal->max)));
+ }
+ break;
+ case RELOPT_TYPE_STRING:
+ option->values.string_val = value;
+ nofree = true;
+ parsed = true;
+ /* no validation possible */
+ break;
+ default:
+ elog(ERROR, "unsupported reloption type %d", option->gen->type);
+ break;
+ }
+
+ if (parsed)
+ option->isset = true;
+ if (!nofree)
+ pfree(value);
+}
/*
- * Parse reloptions for anything using StdRdOptions (ie, fillfactor only)
+ * Option parser for anything that uses StdRdOptions (i.e. fillfactor only)
*/
bytea *
-default_reloptions(Datum reloptions, bool validate,
- int minFillfactor, int defaultFillfactor)
+default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{
- static const char *const default_keywords[1] = {"fillfactor"};
- char *values[1];
- int fillfactor;
- StdRdOptions *result;
+ relopt_value *options;
+ StdRdOptions *rdopts;
+ StdRdOptions lopts;
+ int numoptions;
+ int len;
+ int i;
- parseRelOptions(reloptions, 1, default_keywords, values, validate);
+ options = parseRelOptions(reloptions, validate, kind, &numoptions);
- /*
- * 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)
+ /* if none set, we're done */
+ if (numoptions == 0)
return NULL;
- if (!parse_int(values[0], &fillfactor, 0, NULL))
- {
- if (validate)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("fillfactor must be an integer: \"%s\"",
- values[0])));
- return NULL;
- }
+ MemSet(&lopts, 0, sizeof(StdRdOptions));
- if (fillfactor < minFillfactor || fillfactor > 100)
+ for (i = 0; i < numoptions; i++)
{
- 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;
+ HANDLE_INT_RELOPTION("fillfactor", lopts.fillfactor, options[i]);
}
- result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
- SET_VARSIZE(result, sizeof(StdRdOptions));
+ pfree(options);
- result->fillfactor = fillfactor;
+ len = sizeof(StdRdOptions);
+ rdopts = palloc(len);
+ memcpy(rdopts, &lopts, len);
+ SET_VARSIZE(rdopts, len);
- return (bytea *) result;
+ return (bytea *) rdopts;
}
-
/*
* 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);
+ return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
}
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index 1886aa26691..222ea677883 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.19 2009/01/01 17:23:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.20 2009/01/05 17:14:28 alvherre Exp $
*-------------------------------------------------------------------------
*/
@@ -317,16 +317,7 @@ ginoptions(PG_FUNCTION_ARGS)
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 10
-#define GIN_DEFAULT_FILLFACTOR 100
-
- result = default_reloptions(reloptions, validate,
- GIN_MIN_FILLFACTOR,
- GIN_DEFAULT_FILLFACTOR);
+ result = default_reloptions(reloptions, validate, RELOPT_KIND_GIN);
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 0d66492601f..fa1e3088ad4 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.32 2009/01/01 17:23:35 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.33 2009/01/05 17:14:28 alvherre Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@@ -670,9 +670,8 @@ gistoptions(PG_FUNCTION_ARGS)
bool validate = PG_GETARG_BOOL(1);
bytea *result;
- result = default_reloptions(reloptions, validate,
- GIST_MIN_FILLFACTOR,
- GIST_DEFAULT_FILLFACTOR);
+ result = default_reloptions(reloptions, validate, RELOPT_KIND_GIST);
+
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c
index 4261f0c75e1..42e79376f8f 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.58 2009/01/01 17:23:35 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.59 2009/01/05 17:14:28 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -224,9 +224,8 @@ hashoptions(PG_FUNCTION_ARGS)
bool validate = PG_GETARG_BOOL(1);
bytea *result;
- result = default_reloptions(reloptions, validate,
- HASH_MIN_FILLFACTOR,
- HASH_DEFAULT_FILLFACTOR);
+ result = default_reloptions(reloptions, validate, RELOPT_KIND_HASH);
+
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 3963ce847cf..1649307251c 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.92 2009/01/01 17:23:36 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.93 2009/01/05 17:14:28 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1402,9 +1402,7 @@ btoptions(PG_FUNCTION_ARGS)
bool validate = PG_GETARG_BOOL(1);
bytea *result;
- result = default_reloptions(reloptions, validate,
- BTREE_MIN_FILLFACTOR,
- BTREE_DEFAULT_FILLFACTOR);
+ result = default_reloptions(reloptions, validate, RELOPT_KIND_BTREE);
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index ee1f9f2d574..8a2e2286bec 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.6 2009/01/01 17:23:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.7 2009/01/05 17:14:28 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,21 +20,168 @@
#include "nodes/pg_list.h"
+/* types supported by reloptions */
+typedef enum relopt_type
+{
+ RELOPT_TYPE_BOOL,
+ RELOPT_TYPE_INT,
+ RELOPT_TYPE_REAL,
+ RELOPT_TYPE_STRING
+} relopt_type;
+
+/* kinds supported by reloptions */
+typedef enum relopt_kind
+{
+ RELOPT_KIND_HEAP,
+ /* XXX do we need a separate kind for TOAST tables? */
+ RELOPT_KIND_BTREE,
+ RELOPT_KIND_HASH,
+ RELOPT_KIND_GIN,
+ RELOPT_KIND_GIST,
+ /* if you add a new kind, make sure you update "last_default" too */
+ RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_GIST,
+ RELOPT_KIND_MAX = 255
+} relopt_kind;
+
+/* generic struct to hold shared data */
+typedef struct relopt_gen
+{
+ const char *name; /* must be first (used as list termination marker) */
+ const char *desc;
+ relopt_kind kind;
+ int namelen;
+ relopt_type type;
+} relopt_gen;
+
+/* holds a parsed value */
+typedef struct relopt_value
+{
+ relopt_gen *gen;
+ bool isset;
+ union
+ {
+ bool bool_val;
+ int int_val;
+ double real_val;
+ char *string_val; /* allocated separately */
+ } values;
+} relopt_value;
+
+/* reloptions records for specific variable types */
+typedef struct relopt_bool
+{
+ relopt_gen gen;
+ bool default_val;
+} relopt_bool;
+
+typedef struct relopt_int
+{
+ relopt_gen gen;
+ int default_val;
+ int min;
+ int max;
+} relopt_int;
+
+typedef struct relopt_real
+{
+ relopt_gen gen;
+ double default_val;
+ double min;
+ double max;
+} relopt_real;
+
+typedef struct relopt_string
+{
+ relopt_gen gen;
+ int default_len;
+ bool default_isnull;
+ char default_val[1]; /* variable length */
+} relopt_string;
+
+/*
+ * These macros exist for the convenience of amoptions writers. See
+ * default_reloptions for an example of the intended usage. Beware of
+ * multiple evaluation of arguments!
+ *
+ * Most of the time there's no need to call HAVE_RELOPTION manually, but it's
+ * possible that an amoptions routine needs to walk the array with a different
+ * purpose (say, to compute the size of a struct to allocate beforehand.)
+ */
+#define HAVE_RELOPTION(optname, option) \
+ (pg_strncasecmp(option.gen->name, optname, option.gen->namelen) == 0)
+
+#define HANDLE_INT_RELOPTION(optname, var, option) \
+ do { \
+ if (HAVE_RELOPTION(optname, option)) \
+ { \
+ if (option.isset) \
+ var = option.values.int_val; \
+ else \
+ var = ((relopt_int *) option.gen)->default_val; \
+ continue; \
+ } \
+ } while (0)
+
+#define HANDLE_BOOL_RELOPTION(optname, var, option) \
+ do { \
+ if (HAVE_RELOPTION(optname, option)) \
+ { \
+ if (option.isset) \
+ var = option.values.bool_val; \
+ else \
+ var = ((relopt_bool *) option.gen)->default_val; \
+ continue; \
+ } \
+ } while (0)
+
+#define HANDLE_REAL_RELOPTION(optname, var, option) \
+ do { \
+ if (HAVE_RELOPTION(optname, option)) \
+ { \
+ if (option.isset) \
+ var = option.values.real_val; \
+ else \
+ var = ((relopt_real *) option.gen)->default_val; \
+ continue; \
+ } \
+ } while (0)
+
+/* Note that this assumes that the variable is already allocated! */
+#define HANDLE_STRING_RELOPTION(optname, var, option) \
+ do { \
+ if (HAVE_RELOPTION(optname, option)) \
+ { \
+ relopt_string *optstring = (relopt_string *) option.gen;\
+ if (optstring->default_isnull) \
+ var[0] = '\0'; \
+ else \
+ strcpy(var, \
+ option.isset ? option.values.string_val : \
+ optstring->default_val); \
+ continue; \
+ } \
+ } while (0)
+
+extern int add_reloption_kind(void);
+extern void add_bool_reloption(int kind, char *name, char *desc,
+ bool default_val);
+extern void add_int_reloption(int kind, char *name, char *desc,
+ int default_val, int min_val, int max_val);
+extern void add_real_reloption(int kind, char *name, char *desc,
+ double default_val, double min_val, double max_val);
+extern void add_string_reloption(int kind, char *name, char *desc,
+ char *default_val);
+
extern Datum transformRelOptions(Datum oldOptions, List *defList,
bool ignoreOids, bool isReset);
-
extern List *untransformRelOptions(Datum options);
-
-extern void parseRelOptions(Datum options, int numkeywords,
- const char *const * keywords,
- char **values, bool validate);
+extern relopt_value *parseRelOptions(Datum options, bool validate,
+ relopt_kind kind, int *numrelopts);
extern bytea *default_reloptions(Datum reloptions, bool validate,
- int minFillfactor, int defaultFillfactor);
-
+ relopt_kind kind);
extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
-
extern bytea *index_reloptions(RegProcedure amoptions, Datum reloptions,
- bool validate);
+ bool validate);
#endif /* RELOPTIONS_H */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 9a11d875a2f..13e47f0399c 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.516 2009/01/01 17:23:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.517 2009/01/05 17:14:28 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200812301
+#define CATALOG_VERSION_NO 200901051
#endif