qualifier, and add support for this in pg_dump.
This allows TOAST tables to have user-defined fillfactor, and will also
enable us to move the autovacuum parameters to reloptions without taking
away the possibility of setting values for TOAST tables.
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.69 2008/11/14 10:22:46 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.70 2009/02/02 19:31:38 alvherre Exp $
PostgreSQL documentation
-->
<listitem>
<para>
The name of an index-method-specific storage parameter. See
- below for details.
+ <xref linkend="sql-createindex-storage-parameters" endterm="sql-createindex-storage-parameters-title">
+ for details.
</para>
</listitem>
</varlistentry>
<para>
The <literal>WITH</> clause can specify <firstterm>storage parameters</>
for indexes. Each index method can have its own set of allowed storage
- parameters. The built-in index methods all accept a single parameter:
+ parameters. The <literal>B-tree</literal>, <literal>hash</literal> and
+ <literal>GiST</literal> built-in index methods all accept a single parameter:
</para>
<variablelist>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.111 2008/11/14 10:22:46 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.112 2009/02/02 19:31:38 alvherre Exp $
PostgreSQL documentation
-->
for tables, and for indexes associated with a <literal>UNIQUE</literal> or
<literal>PRIMARY KEY</literal> constraint. Storage parameters for
indexes are documented in <xref linkend="SQL-CREATEINDEX"
- endterm="sql-createindex-title">. The only storage parameter currently
- available for tables is:
+ endterm="sql-createindex-title">. The storage parameters currently
+ available for tables are:
</para>
<variablelist>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>TOAST.FILLFACTOR</literal></term>
+ <listitem>
+ <para>
+ Same as above, for the supplementary storage table, if any; see
+ <xref linkend="storage-toast">.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect2>
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.19 2009/01/26 19:41:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.20 2009/02/02 19:31:38 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
}
/*
- * Transform a relation options list (list of DefElem) into the text array
- * format that is kept in pg_class.reloptions.
+ * Transform a relation options list (list of ReloptElem) into the text array
+ * format that is kept in pg_class.reloptions, including only those options
+ * that are in the passed namespace. The output values do not include the
+ * namespace.
*
* This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
* ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
* 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.
+ * are valid, but it does check that namespaces for all the options given are
+ * listed in validnsps. The NULL namespace is always valid and needs not be
+ * explicitely listed. Passing a NULL pointer means that only the NULL
+ * namespace is 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)
+transformRelOptions(Datum oldOptions, List *defList, char *namspace,
+ char *validnsps[], bool ignoreOids, bool isReset)
{
Datum result;
ArrayBuildState *astate;
/* Search for a match in defList */
foreach(cell, defList)
{
- DefElem *def = lfirst(cell);
- int kw_len = strlen(def->defname);
+ ReloptElem *def = lfirst(cell);
+ int kw_len;
+ /* ignore if not in the same namespace */
+ if (namspace == NULL)
+ {
+ if (def->nmspc != NULL)
+ continue;
+ }
+ else if (def->nmspc == NULL)
+ continue;
+ else if (pg_strcasecmp(def->nmspc, namspace) != 0)
+ continue;
+
+ kw_len = strlen(def->optname);
if (text_len > kw_len && text_str[kw_len] == '=' &&
- pg_strncasecmp(text_str, def->defname, kw_len) == 0)
+ pg_strncasecmp(text_str, def->optname, kw_len) == 0)
break;
}
if (!cell)
*/
foreach(cell, defList)
{
- DefElem *def = lfirst(cell);
+ ReloptElem *def = lfirst(cell);
+
if (isReset)
{
const char *value;
Size len;
- if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
+ /*
+ * Error out if the namespace is not valid. A NULL namespace
+ * is always valid.
+ */
+ if (def->nmspc != NULL)
+ {
+ bool valid = false;
+ int i;
+
+ if (validnsps)
+ {
+ for (i = 0; validnsps[i]; i++)
+ {
+ if (pg_strcasecmp(def->nmspc, validnsps[i]) == 0)
+ {
+ valid = true;
+ break;
+ }
+ }
+ }
+
+ if (!valid)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized parameter namespace \"%s\"",
+ def->nmspc)));
+ }
+
+ if (ignoreOids && pg_strcasecmp(def->optname, "oids") == 0)
+ continue;
+
+ /* ignore if not in the same namespace */
+ if (namspace == NULL)
+ {
+ if (def->nmspc != NULL)
+ continue;
+ }
+ else if (def->nmspc == NULL)
+ continue;
+ else if (pg_strcasecmp(def->nmspc, namspace) != 0)
continue;
/*
- * Flatten the DefElem into a text string like "name=arg". If we
- * have just "name", assume "name=true" is meant.
+ * Flatten the ReloptElem into a text string like "name=arg". If we
+ * have just "name", assume "name=true" is meant. Note: the
+ * namespace is not output.
*/
if (def->arg != NULL)
- value = defGetString(def);
+ value = reloptGetString(def);
else
value = "true";
- len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
+ len = VARHDRSZ + strlen(def->optname) + 1 + strlen(value);
/* +1 leaves room for sprintf's trailing null */
t = (text *) palloc(len + 1);
SET_VARSIZE(t, len);
- sprintf(VARDATA(t), "%s=%s", def->defname, value);
+ sprintf(VARDATA(t), "%s=%s", def->optname, value);
astate = accumArrayResult(astate, PointerGetDatum(t),
false, TEXTOID,
}
/*
- * Parse options for heaps (and perhaps someday toast tables).
+ * Parse options for heaps and toast tables.
*/
bytea *
heap_reloptions(char relkind, Datum reloptions, bool validate)
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.12 2009/01/01 17:23:37 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.13 2009/02/02 19:31:38 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/syscache.h"
-static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid);
+static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
+ Datum reloptions);
static bool needs_toast_table(Relation rel);
* to end with CommandCounterIncrement if it makes any changes.
*/
void
-AlterTableCreateToastTable(Oid relOid)
+AlterTableCreateToastTable(Oid relOid, Datum reloptions)
{
Relation rel;
rel = heap_open(relOid, AccessExclusiveLock);
/* create_toast_table does all the work */
- (void) create_toast_table(rel, InvalidOid, InvalidOid);
+ (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions);
heap_close(rel, NoLock);
}
relName)));
/* create_toast_table does all the work */
- if (!create_toast_table(rel, toastOid, toastIndexOid))
+ if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0))
elog(ERROR, "\"%s\" does not require a toast table",
relName);
* bootstrap they can be nonzero to specify hand-assigned OIDs
*/
static bool
-create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid)
+create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptions)
{
Oid relOid = RelationGetRelid(rel);
HeapTuple reltup;
else
namespaceid = PG_TOAST_NAMESPACE;
- /*
- * XXX would it make sense to apply the master's reloptions to the toast
- * table? Or maybe some toast-specific reloptions?
- */
toast_relid = heap_create_with_catalog(toast_relname,
namespaceid,
rel->rd_rel->reltablespace,
true,
0,
ONCOMMIT_NOOP,
- (Datum) 0,
+ reloptions,
true);
/* make the toast relation visible, else index creation will fail */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.181 2009/01/16 13:27:23 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.182 2009/02/02 19:31:38 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
TupleDesc OldHeapDesc,
tupdesc;
Oid OIDNewHeap;
+ Oid toastid;
Relation OldHeap;
HeapTuple tuple;
Datum reloptions;
* AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
* the TOAST table will be visible for insertion.
*/
- AlterTableCreateToastTable(OIDNewHeap);
+ toastid = OldHeap->rd_rel->reltoastrelid;
+ reloptions = (Datum) 0;
+ if (OidIsValid(toastid))
+ {
+ tuple = SearchSysCache(RELOID,
+ ObjectIdGetDatum(toastid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", toastid);
+ reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
+ &isNull);
+ if (isNull)
+ reloptions = (Datum) 0;
+ }
+ AlterTableCreateToastTable(OIDNewHeap, reloptions);
+
+ if (OidIsValid(toastid))
+ ReleaseSysCache(tuple);
heap_close(OldHeap, NoLock);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.102 2009/01/01 17:23:37 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.103 2009/02/02 19:31:38 alvherre Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
}
-/*
- * Extract a string value (otherwise uninterpreted) from a DefElem.
- */
-char *
-defGetString(DefElem *def)
+static char *
+nodeGetString(Node *value, char *name)
{
- if (def->arg == NULL)
+ if (value == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("%s requires a parameter",
- def->defname)));
- switch (nodeTag(def->arg))
+ errmsg("%s requires a parameter", name)));
+ switch (nodeTag(value))
{
case T_Integer:
{
char *str = palloc(32);
- snprintf(str, 32, "%ld", (long) intVal(def->arg));
+ snprintf(str, 32, "%ld", (long) intVal(value));
return str;
}
case T_Float:
* T_Float values are kept in string form, so this type cheat
* works (and doesn't risk losing precision)
*/
- return strVal(def->arg);
+ return strVal(value);
case T_String:
- return strVal(def->arg);
+ return strVal(value);
case T_TypeName:
- return TypeNameToString((TypeName *) def->arg);
+ return TypeNameToString((TypeName *) value);
case T_List:
- return NameListToString((List *) def->arg);
+ return NameListToString((List *) value);
default:
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
+ elog(ERROR, "unrecognized node type: %d", (int) nodeTag(value));
}
return NULL; /* keep compiler quiet */
}
+/*
+ * Extract a string value (otherwise uninterpreted) from a DefElem.
+ */
+char *
+defGetString(DefElem *def)
+{
+ return nodeGetString(def->arg, def->defname);
+}
+
/*
* Extract a numeric value (actually double) from a DefElem.
*/
return 0; /* keep compiler quiet */
}
-/*
- * Extract a boolean value from a DefElem.
- */
-bool
-defGetBoolean(DefElem *def)
+static bool
+nodeGetBoolean(Node *value, char *name)
{
/*
* If no parameter given, assume "true" is meant.
*/
- if (def->arg == NULL)
+ if (value == NULL)
return true;
/*
* Allow 0, 1, "true", "false"
*/
- switch (nodeTag(def->arg))
+ switch (nodeTag(value))
{
case T_Integer:
- switch (intVal(def->arg))
+ switch (intVal(value))
{
case 0:
return false;
break;
default:
{
- char *sval = defGetString(def);
+ char *sval = nodeGetString(value, name);
if (pg_strcasecmp(sval, "true") == 0)
return true;
}
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("%s requires a Boolean value",
- def->defname)));
+ errmsg("%s requires a Boolean value", name)));
return false; /* keep compiler quiet */
}
+/*
+ * Extract a boolean value from a DefElem.
+ */
+bool
+defGetBoolean(DefElem *def)
+{
+ return nodeGetBoolean(def->arg, def->defname);
+}
+
/*
* Extract an int64 value from a DefElem.
*/
return 0; /* keep compiler quiet */
}
+
+/*
+ * Extract a string value (otherwise uninterpreted) from a ReloptElem.
+ */
+char *
+reloptGetString(ReloptElem *relopt)
+{
+ return nodeGetString(relopt->arg, relopt->optname);
+}
+
+/*
+ * Extract a boolean value from a ReloptElem.
+ */
+bool
+reloptGetBoolean(ReloptElem *relopt)
+{
+ return nodeGetBoolean(relopt->arg, relopt->optname);
+}
+
/*
- * Create a DefElem setting "oids" to the specified value.
+ * Create a ReloptElem setting "oids" to the specified value.
*/
-DefElem *
-defWithOids(bool value)
+ReloptElem *
+reloptWithOids(bool value)
{
- DefElem *f = makeNode(DefElem);
+ ReloptElem *f = makeNode(ReloptElem);
- f->defname = "oids";
+ f->optname = "oids";
+ f->nmspc = NULL;
f->arg = (Node *) makeInteger(value);
return f;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.181 2009/01/01 17:23:38 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.182 2009/02/02 19:31:38 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Parse AM-specific options, convert to text array form, validate.
*/
- reloptions = transformRelOptions((Datum) 0, options, false, false);
+ reloptions = transformRelOptions((Datum) 0, options, NULL, NULL, false, false);
(void) index_reloptions(amoptions, reloptions, true);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.157 2009/01/20 18:59:37 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.158 2009/02/02 19:31:38 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
stmt->relation = seq->sequence;
stmt->inhRelations = NIL;
stmt->constraints = NIL;
- stmt->options = list_make1(defWithOids(false));
+ stmt->options = list_make1(reloptWithOids(false));
stmt->oncommit = ONCOMMIT_NOOP;
stmt->tablespacename = NULL;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.278 2009/01/22 20:16:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.279 2009/02/02 19:31:38 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
Datum reloptions;
ListCell *listptr;
AttrNumber attnum;
+ static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
/*
* Truncate relname to appropriate length (probably a waste of time, as
/*
* Parse and validate reloptions, if any.
*/
- reloptions = transformRelOptions((Datum) 0, stmt->options, true, false);
+ reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
+ true, false);
(void) heap_reloptions(relkind, reloptions, true);
(tab->subcmds[AT_PASS_ADD_COL] ||
tab->subcmds[AT_PASS_ALTER_TYPE] ||
tab->subcmds[AT_PASS_COL_ATTRS]))
- AlterTableCreateToastTable(tab->relid);
+ AlterTableCreateToastTable(tab->relid, (Datum) 0);
}
}
Datum repl_val[Natts_pg_class];
bool repl_null[Natts_pg_class];
bool repl_repl[Natts_pg_class];
+ static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
if (defList == NIL)
return; /* nothing to do */
/* Generate new proposed reloptions (text array) */
newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
- defList, false, isReset);
+ defList, NULL, validnsps, false, isReset);
/* Validate */
switch (rel->rd_rel->relkind)
ReleaseSysCache(tuple);
+ /* repeat the whole exercise for the toast table, if there's one */
+ if (OidIsValid(rel->rd_rel->reltoastrelid))
+ {
+ Relation toastrel;
+ Oid toastid = rel->rd_rel->reltoastrelid;
+
+ toastrel = heap_open(toastid, AccessExclusiveLock);
+
+ /* Get the old reloptions */
+ tuple = SearchSysCache(RELOID,
+ ObjectIdGetDatum(toastid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", toastid);
+
+ datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull);
+
+ newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
+ defList, "toast", validnsps, false, isReset);
+
+ (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
+
+ memset(repl_val, 0, sizeof(repl_val));
+ memset(repl_null, false, sizeof(repl_null));
+ memset(repl_repl, false, sizeof(repl_repl));
+
+ if (newOptions != (Datum) 0)
+ repl_val[Anum_pg_class_reloptions - 1] = newOptions;
+ else
+ repl_null[Anum_pg_class_reloptions - 1] = true;
+
+ repl_repl[Anum_pg_class_reloptions - 1] = true;
+
+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
+ repl_val, repl_null, repl_repl);
+
+ simple_heap_update(pgclass, &newtuple->t_self, newtuple);
+
+ CatalogUpdateIndexes(pgclass, newtuple);
+
+ heap_freetuple(newtuple);
+
+ ReleaseSysCache(tuple);
+
+ heap_close(toastrel, NoLock);
+ }
+
heap_close(pgclass, RowExclusiveLock);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.130 2009/01/09 15:46:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.131 2009/02/02 19:31:39 alvherre Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
createStmt->tableElts = coldeflist;
createStmt->inhRelations = NIL;
createStmt->constraints = NIL;
- createStmt->options = list_make1(defWithOids(false));
+ createStmt->options = list_make1(reloptWithOids(false));
createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.113 2009/01/27 12:40:15 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.114 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
createStmt->tableElts = attrList;
createStmt->inhRelations = NIL;
createStmt->constraints = NIL;
- createStmt->options = list_make1(defWithOids(false));
+ createStmt->options = list_make1(reloptWithOids(false));
createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.321 2009/01/22 20:16:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.322 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
Oid intoRelationId;
TupleDesc tupdesc;
DR_intorel *myState;
+ static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
Assert(into);
/* Parse and validate any reloptions */
reloptions = transformRelOptions((Datum) 0,
into->options,
+ NULL,
+ validnsps,
true,
false);
(void) heap_reloptions(RELKIND_RELATION, reloptions, true);
* AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
* the TOAST table will be visible for insertion.
*/
- AlterTableCreateToastTable(intoRelationId);
+ reloptions = transformRelOptions((Datum) 0,
+ into->options,
+ "toast",
+ validnsps,
+ true,
+ false);
+
+ (void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true);
+
+ AlterTableCreateToastTable(intoRelationId, reloptions);
/*
* And open the constructed table for writing.
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.421 2009/01/22 20:16:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.422 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
return newnode;
}
+static ReloptElem *
+_copyReloptElem(ReloptElem *from)
+{
+ ReloptElem *newnode = makeNode(ReloptElem);
+
+ COPY_STRING_FIELD(optname);
+ COPY_STRING_FIELD(nmspc);
+ COPY_NODE_FIELD(arg);
+
+ return newnode;
+}
+
static LockingClause *
_copyLockingClause(LockingClause *from)
{
case T_OptionDefElem:
retval = _copyOptionDefElem(from);
break;
+ case T_ReloptElem:
+ retval = _copyReloptElem(from);
+ break;
case T_LockingClause:
retval = _copyLockingClause(from);
break;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.346 2009/01/22 20:16:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.347 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
return true;
}
+static bool
+_equalReloptElem(ReloptElem *a, ReloptElem *b)
+{
+ COMPARE_STRING_FIELD(nmspc);
+ COMPARE_STRING_FIELD(optname);
+ COMPARE_NODE_FIELD(arg);
+
+ return true;
+}
+
static bool
_equalLockingClause(LockingClause *a, LockingClause *b)
{
case T_OptionDefElem:
retval = _equalOptionDefElem(a, b);
break;
+ case T_ReloptElem:
+ retval = _equalReloptElem(a, b);
+ break;
case T_LockingClause:
retval = _equalLockingClause(a, b);
break;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.62 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.63 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
res->def = def;
return res;
}
+
+ReloptElem *
+makeReloptElem(char *name, char *nmspc, Node *arg)
+{
+ ReloptElem *res = makeNode(ReloptElem);
+
+ res->optname = name;
+ res->nmspc = nmspc;
+ res->arg = arg;
+ return res;
+}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.350 2009/01/22 20:16:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.351 2009/02/02 19:31:39 alvherre Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
WRITE_NODE_FIELD(arg);
}
+static void
+_outReloptElem(StringInfo str, ReloptElem *node)
+{
+ WRITE_NODE_TYPE("RELOPTELEM");
+
+ WRITE_STRING_FIELD(nmspc);
+ WRITE_STRING_FIELD(optname);
+ WRITE_NODE_FIELD(arg);
+}
+
static void
_outLockingClause(StringInfo str, LockingClause *node)
{
case T_DefElem:
_outDefElem(str, obj);
break;
+ case T_ReloptElem:
+ _outReloptElem(str, obj);
+ break;
case T_LockingClause:
_outLockingClause(str, obj);
break;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.656 2009/01/22 20:16:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.657 2009/02/02 19:31:39 alvherre Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
FuncWithArgs *funwithargs;
DefElem *defelt;
OptionDefElem *optdef;
+ ReloptElem *reloptel;
SortBy *sortby;
WindowDef *windef;
JoinExpr *jexpr;
%type <list> stmtblock stmtmulti
OptTableElementList TableElementList OptInherit definition
+ reloptions opt_reloptions
OptWith opt_distinct opt_definition func_args func_args_list
func_args_with_defaults func_args_with_defaults_list
func_as createfunc_opt_list alterfunc_opt_list
target_list insert_column_list set_target_list
set_clause_list set_clause multiple_set_clause
ctext_expr_list ctext_row def_list indirection opt_indirection
- group_clause TriggerFuncArgs select_limit
+ reloption_list group_clause TriggerFuncArgs select_limit
opt_select_limit opclass_item_list opclass_drop_list
opt_opfamily transaction_mode_list_or_empty
TableFuncElementList opt_type_modifiers
%type <node> TableElement ConstraintElem TableFuncElement
%type <node> columnDef
%type <defelt> def_elem old_aggr_elem
+%type <reloptel> reloption_elem
%type <node> def_arg columnElem where_clause where_or_current_clause
a_expr b_expr c_expr func_expr AexprConst indirection_el
columnref in_expr having_clause func_table array_expr
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET (...) */
- | SET definition
+ | SET reloptions
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_SetRelOptions;
$$ = (Node *)n;
}
/* ALTER TABLE <name> RESET (...) */
- | RESET definition
+ | RESET reloptions
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ResetRelOptions;
| /* EMPTY */ { $$ = NULL; }
;
+reloptions:
+ '(' reloption_list ')' { $$ = $2; }
+ ;
+
+opt_reloptions: WITH reloptions { $$ = $2; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+reloption_list:
+ reloption_elem { $$ = list_make1($1); }
+ | reloption_list ',' reloption_elem { $$ = lappend($1, $3); }
+ ;
+
+reloption_elem:
+ ColLabel '=' def_arg
+ {
+ $$ = makeReloptElem($1, NULL, (Node *) $3);
+ }
+ | ColLabel
+ {
+ $$ = makeReloptElem($1, NULL, NULL);
+ }
+ | ColLabel '.' ColLabel '=' def_arg
+ {
+ $$ = makeReloptElem($3, $1, (Node *) $5);
+ }
+ | ColLabel '.' ColLabel
+ {
+ $$ = makeReloptElem($3, $1, NULL);
+ }
+ ;
/*****************************************************************************
/* WITH (options) is preferred, WITH OIDS and WITHOUT OIDS are legacy forms */
OptWith:
- WITH definition { $$ = $2; }
- | WITH OIDS { $$ = list_make1(defWithOids(true)); }
- | WITHOUT OIDS { $$ = list_make1(defWithOids(false)); }
+ WITH reloptions { $$ = $2; }
+ | WITH OIDS { $$ = list_make1(reloptWithOids(true)); }
+ | WITHOUT OIDS { $$ = list_make1(reloptWithOids(false)); }
| /*EMPTY*/ { $$ = NIL; }
;
IndexStmt: CREATE index_opt_unique INDEX index_name
ON qualified_name access_method_clause '(' index_params ')'
- opt_definition OptTableSpace where_clause
+ opt_reloptions OptTableSpace where_clause
{
IndexStmt *n = makeNode(IndexStmt);
n->unique = $2;
}
| CREATE index_opt_unique INDEX CONCURRENTLY index_name
ON qualified_name access_method_clause '(' index_params ')'
- opt_definition OptTableSpace where_clause
+ opt_reloptions OptTableSpace where_clause
{
IndexStmt *n = makeNode(IndexStmt);
n->unique = $2;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.186 2009/01/22 20:16:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.187 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
}
/*
- * Given a relation-options list (of DefElems), return true iff the specified
+ * Given a relation-options list (of ReloptElems), 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.
/* Scan list to see if OIDS was included */
foreach(cell, defList)
{
- DefElem *def = (DefElem *) lfirst(cell);
+ ReloptElem *def = (ReloptElem *) lfirst(cell);
- if (pg_strcasecmp(def->defname, "oids") == 0)
- return defGetBoolean(def);
+ if (pg_strcasecmp(def->optname, "oids") == 0)
+ return reloptGetBoolean(def);
}
/* OIDS option was not specified, so use default. */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.305 2009/01/22 20:16:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.306 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include "access/reloptions.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "catalog/catalog.h"
if (IsA(stmt, CreateStmt))
{
+ Datum toast_options;
+ static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
+
/* Create the table itself */
relOid = DefineRelation((CreateStmt *) stmt,
RELKIND_RELATION);
* needs a secondary relation too.
*/
CommandCounterIncrement();
- AlterTableCreateToastTable(relOid);
+
+ /* parse and validate reloptions for the toast table */
+ toast_options = transformRelOptions((Datum) 0,
+ ((CreateStmt *)stmt)->options,
+ "toast",
+ validnsps,
+ true, false);
+ (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options,
+ true);
+
+ AlterTableCreateToastTable(relOid, toast_options);
}
else
{
* by PostgreSQL
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.517 2009/01/27 12:40:15 petere Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.518 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
int i_owning_col;
int i_reltablespace;
int i_reloptions;
+ int i_toastreloptions;
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
* owning column, if any (note this dependency is AUTO as of 8.2)
*/
appendPQExpBuffer(query,
- "SELECT c.tableoid, c.oid, relname, "
- "relacl, relkind, relnamespace, "
- "(%s relowner) as rolname, "
- "relchecks, relhastriggers, "
- "relhasindex, relhasrules, relhasoids, "
+ "SELECT c.tableoid, c.oid, c.relname, "
+ "c.relacl, c.relkind, c.relnamespace, "
+ "(%s c.relowner) as rolname, "
+ "c.relchecks, c.relhastriggers, "
+ "c.relhasindex, c.relhasrules, c.relhasoids, "
"d.refobjid as owning_tab, "
"d.refobjsubid as owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
- "array_to_string(c.reloptions, ', ') as reloptions "
+ "array_to_string(c.reloptions, ', ') as reloptions, "
+ "array_to_string(array(select 'toast.' || x from unnest(tc.reloptions) x), ', ') as toast_reloptions "
"from pg_class c "
"left join pg_depend d on "
"(c.relkind = '%c' and "
"d.classid = c.tableoid and d.objid = c.oid and "
"d.objsubid = 0 and "
"d.refclassid = c.tableoid and d.deptype = 'a') "
- "where relkind in ('%c', '%c', '%c', '%c') "
+ "left join pg_class tc on (c.reltoastrelid = tc.oid) "
+ "where c.relkind in ('%c', '%c', '%c', '%c') "
"order by c.oid",
username_subquery,
RELKIND_SEQUENCE,
"d.refobjid as owning_tab, "
"d.refobjsubid as owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
- "array_to_string(c.reloptions, ', ') as reloptions "
+ "array_to_string(c.reloptions, ', ') as reloptions, "
+ "NULL as toast_reloptions "
"from pg_class c "
"left join pg_depend d on "
"(c.relkind = '%c' and "
"d.refobjid as owning_tab, "
"d.refobjsubid as owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
- "NULL as reloptions "
+ "NULL as reloptions, "
+ "NULL as toast_reloptions "
"from pg_class c "
"left join pg_depend d on "
"(c.relkind = '%c' and "
"d.refobjid as owning_tab, "
"d.refobjsubid as owning_col, "
"NULL as reltablespace, "
- "NULL as reloptions "
+ "NULL as reloptions, "
+ "NULL as toast_reloptions "
"from pg_class c "
"left join pg_depend d on "
"(c.relkind = '%c' and "
"NULL::oid as owning_tab, "
"NULL::int4 as owning_col, "
"NULL as reltablespace, "
- "NULL as reloptions "
+ "NULL as reloptions, "
+ "NULL as toast_reloptions "
"from pg_class "
"where relkind in ('%c', '%c', '%c') "
"order by oid",
"NULL::oid as owning_tab, "
"NULL::int4 as owning_col, "
"NULL as reltablespace, "
- "NULL as reloptions "
+ "NULL as reloptions, "
+ "NULL as toast_reloptions "
"from pg_class "
"where relkind in ('%c', '%c', '%c') "
"order by oid",
"NULL::oid as owning_tab, "
"NULL::int4 as owning_col, "
"NULL as reltablespace, "
- "NULL as reloptions "
+ "NULL as reloptions, "
+ "NULL as toast_reloptions "
"from pg_class c "
"where relkind in ('%c', '%c') "
"order by oid",
i_owning_col = PQfnumber(res, "owning_col");
i_reltablespace = PQfnumber(res, "reltablespace");
i_reloptions = PQfnumber(res, "reloptions");
+ i_toastreloptions = PQfnumber(res, "toast_reloptions");
if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
{
}
tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
+ tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions));
/* other fields were zeroed above */
appendPQExpBuffer(q, ")");
}
- if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
- appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions);
+ if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
+ (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
+ {
+ bool addcomma = false;
+
+ appendPQExpBuffer(q, "\nWITH (");
+ if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
+ {
+ addcomma = true;
+ appendPQExpBuffer(q, "%s", tbinfo->reloptions);
+ }
+ if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
+ {
+ appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
+ tbinfo->toast_reloptions);
+ }
+ appendPQExpBuffer(q, ")");
+ }
appendPQExpBuffer(q, ";\n");
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.149 2009/01/27 12:40:15 petere Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.150 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
char relkind;
char *reltablespace; /* relation tablespace */
char *reloptions; /* options specified by WITH (...) */
+ char *toast_reloptions; /* ditto, for the TOAST table */
bool hasindex; /* does it have any indexes? */
bool hasrules; /* does it have any rules? */
bool hastriggers; /* does it have any triggers? */
* 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.11 2009/01/26 19:41:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.12 2009/02/02 19:31:39 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
RELOPT_KIND_MAX = 255
} relopt_kind;
+/* reloption namespaces allowed for heaps -- currently only TOAST */
+#define HEAP_RELOPT_NAMESPACES { "toast", NULL }
+
/* generic struct to hold shared data */
typedef struct relopt_gen
{
char *default_val, validate_string_relopt validator);
extern Datum transformRelOptions(Datum oldOptions, List *defList,
+ char *namspace, char *validnsps[],
bool ignoreOids, bool isReset);
extern List *untransformRelOptions(Datum options);
extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/toasting.h,v 1.5 2009/01/01 17:23:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/toasting.h,v 1.6 2009/02/02 19:31:40 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
/*
* toasting.c prototypes
*/
-extern void AlterTableCreateToastTable(Oid relOid);
+extern void AlterTableCreateToastTable(Oid relOid, Datum reloptions);
extern void BootstrapToastTable(char *relName,
Oid toastOid, Oid toastIndexOid);
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.92 2009/01/01 17:23:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.93 2009/02/02 19:31:40 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
extern List *defGetQualifiedName(DefElem *def);
extern TypeName *defGetTypeName(DefElem *def);
extern int defGetTypeLength(DefElem *def);
-extern DefElem *defWithOids(bool value);
+extern char *reloptGetString(ReloptElem *relopt);
+extern bool reloptGetBoolean(ReloptElem *relopt);
+extern ReloptElem *reloptWithOids(bool value);
#endif /* DEFREM_H */
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.65 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.66 2009/02/02 19:31:40 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
extern OptionDefElem *makeOptionDefElem(int op, DefElem *def);
+extern ReloptElem *makeReloptElem(char *name, char *namspc, Node *arg);
+
#endif /* MAKEFUNC_H */
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.219 2009/01/22 20:16:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.220 2009/02/02 19:31:40 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
T_Constraint,
T_DefElem,
T_OptionDefElem,
+ T_ReloptElem,
T_RangeTblEntry,
T_SortGroupClause,
T_WindowClause,
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.389 2009/01/22 20:16:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.390 2009/02/02 19:31:40 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
DefElem *def; /* The actual definition */
} OptionDefElem;
+/*
+ * Reloption definition. As DefElem, with optional option namespace.
+ */
+typedef struct ReloptElem
+{
+ NodeTag type;
+ char *nmspc;
+ char *optname;
+ Node *arg;
+} ReloptElem;
+
/*
* LockingClause - raw representation of FOR UPDATE/SHARE options
*