Euler Taveira de Oliveira wrote:
> Alvaro Herrera escreveu:
> > I wasn't sure of the best place to add a check. I have added it to
> > transformRelOptions; I am not entirely comfortable with it, because it
> > works, but it still allows this:
> >
> IMHO it's the appropriate place.
I think the best place would be parseRelOptions. The problem is that
transformRelOptions does not apply any semantics to the values it's
parsing; it doesn't know about the relopt_kind for example. That stuff
is only known by parseRelOptions, but when the options reach that point,
they have already lost the namespace (due to transformRelOptions).
> > alvherre=# alter index f set (toast.fillfactor = 20);
> > ALTER INDEX
> >
> Maybe you need to add relopt_kind test in your validation code.
No clean way to do that :-(
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Index: src/backend/access/common/reloptions.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/access/common/reloptions.c,v
retrieving revision 1.18
diff -c -p -r1.18 reloptions.c
*** src/backend/access/common/reloptions.c 12 Jan 2009 21:02:14 -0000 1.18
--- src/backend/access/common/reloptions.c 14 Jan 2009 14:32:26 -0000
*************** add_string_reloption(int kind, char *nam
*** 390,397 ****
}
/*
! * 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
--- 390,399 ----
}
/*
! * 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
*************** add_string_reloption(int kind, char *nam
*** 402,414 ****
* 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;
--- 404,416 ----
* 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, but it does check that the namespaces given are known.
*
* 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, char *namspace,
bool ignoreOids, bool isReset)
{
Datum result;
*************** transformRelOptions(Datum oldOptions, Li
*** 444,454 ****
/* 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)
--- 446,468 ----
/* Search for a match in defList */
foreach(cell, defList)
{
! 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->optname, kw_len) == 0)
break;
}
if (!cell)
*************** transformRelOptions(Datum oldOptions, Li
*** 468,474 ****
*/
foreach(cell, defList)
{
! DefElem *def = lfirst(cell);
if (isReset)
{
--- 482,493 ----
*/
foreach(cell, defList)
{
! ReloptElem *def = lfirst(cell);
!
! if (def->nmspc && pg_strcasecmp(def->nmspc, "toast") != 0)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! errmsg("unrecognized parameter namespace \"%s\"", def->nmspc)));
if (isReset)
{
*************** transformRelOptions(Datum oldOptions, Li
*** 483,504 ****
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);
SET_VARSIZE(t, len);
! sprintf(VARDATA(t), "%s=%s", def->defname, value);
astate = accumArrayResult(astate, PointerGetDatum(t),
false, TEXTOID,
--- 502,535 ----
const char *value;
Size len;
! 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 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 = reloptGetString(def);
else
value = "true";
! 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->optname, value);
astate = accumArrayResult(astate, PointerGetDatum(t),
false, TEXTOID,
*************** default_reloptions(Datum reloptions, boo
*** 897,903 ****
}
/*
! * Parse options for heaps (and perhaps someday toast tables).
*/
bytea *
heap_reloptions(char relkind, Datum reloptions, bool validate)
--- 928,934 ----
}
/*
! * Parse options for heaps and toast tables.
*/
bytea *
heap_reloptions(char relkind, Datum reloptions, bool validate)
Index: src/backend/catalog/toasting.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/catalog/toasting.c,v
retrieving revision 1.12
diff -c -p -r1.12 toasting.c
*** src/backend/catalog/toasting.c 1 Jan 2009 17:23:37 -0000 1.12
--- src/backend/catalog/toasting.c 7 Jan 2009 22:10:48 -0000
***************
*** 32,38 ****
#include "utils/syscache.h"
! static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid);
static bool needs_toast_table(Relation rel);
--- 32,39 ----
#include "utils/syscache.h"
! static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
! Datum reloptions);
static bool needs_toast_table(Relation rel);
*************** static bool needs_toast_table(Relation r
*** 46,52 ****
* to end with CommandCounterIncrement if it makes any changes.
*/
void
! AlterTableCreateToastTable(Oid relOid)
{
Relation rel;
--- 47,53 ----
* to end with CommandCounterIncrement if it makes any changes.
*/
void
! AlterTableCreateToastTable(Oid relOid, Datum reloptions)
{
Relation rel;
*************** AlterTableCreateToastTable(Oid relOid)
*** 58,64 ****
rel = heap_open(relOid, AccessExclusiveLock);
/* create_toast_table does all the work */
! (void) create_toast_table(rel, InvalidOid, InvalidOid);
heap_close(rel, NoLock);
}
--- 59,65 ----
rel = heap_open(relOid, AccessExclusiveLock);
/* create_toast_table does all the work */
! (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions);
heap_close(rel, NoLock);
}
*************** BootstrapToastTable(char *relName, Oid t
*** 84,90 ****
relName)));
/* create_toast_table does all the work */
! if (!create_toast_table(rel, toastOid, toastIndexOid))
elog(ERROR, "\"%s\" does not require a toast table",
relName);
--- 85,91 ----
relName)));
/* create_toast_table does all the work */
! if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0))
elog(ERROR, "\"%s\" does not require a toast table",
relName);
*************** BootstrapToastTable(char *relName, Oid t
*** 100,106 ****
* bootstrap they can be nonzero to specify hand-assigned OIDs
*/
static bool
! create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid)
{
Oid relOid = RelationGetRelid(rel);
HeapTuple reltup;
--- 101,107 ----
* bootstrap they can be nonzero to specify hand-assigned OIDs
*/
static bool
! create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptions)
{
Oid relOid = RelationGetRelid(rel);
HeapTuple reltup;
*************** create_toast_table(Relation rel, Oid toa
*** 183,192 ****
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,
--- 184,189 ----
*************** create_toast_table(Relation rel, Oid toa
*** 199,205 ****
true,
0,
ONCOMMIT_NOOP,
! (Datum) 0,
true);
/* make the toast relation visible, else index creation will fail */
--- 196,202 ----
true,
0,
ONCOMMIT_NOOP,
! reloptions,
true);
/* make the toast relation visible, else index creation will fail */
Index: src/backend/commands/cluster.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/cluster.c,v
retrieving revision 1.180
diff -c -p -r1.180 cluster.c
*** src/backend/commands/cluster.c 1 Jan 2009 17:23:37 -0000 1.180
--- src/backend/commands/cluster.c 13 Jan 2009 00:55:25 -0000
*************** make_new_heap(Oid OIDOldHeap, const char
*** 668,673 ****
--- 668,674 ----
TupleDesc OldHeapDesc,
tupdesc;
Oid OIDNewHeap;
+ Oid toastid;
Relation OldHeap;
HeapTuple tuple;
Datum reloptions;
*************** make_new_heap(Oid OIDOldHeap, const char
*** 726,732 ****
* AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
* the TOAST table will be visible for insertion.
*/
! AlterTableCreateToastTable(OIDNewHeap);
heap_close(OldHeap, NoLock);
--- 727,750 ----
* AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
* the TOAST table will be visible for insertion.
*/
! 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);
Index: src/backend/commands/define.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/define.c,v
retrieving revision 1.102
diff -c -p -r1.102 define.c
*** src/backend/commands/define.c 1 Jan 2009 17:23:37 -0000 1.102
--- src/backend/commands/define.c 13 Jan 2009 00:31:44 -0000
*************** case_translate_language_name(const char
*** 55,78 ****
}
! /*
! * Extract a string value (otherwise uninterpreted) from a DefElem.
! */
! char *
! defGetString(DefElem *def)
{
! if (def->arg == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
! errmsg("%s requires a parameter",
! def->defname)));
! switch (nodeTag(def->arg))
{
case T_Integer:
{
char *str = palloc(32);
! snprintf(str, 32, "%ld", (long) intVal(def->arg));
return str;
}
case T_Float:
--- 55,74 ----
}
! static char *
! nodeGetString(Node *value, char *name)
{
! if (value == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
! errmsg("%s requires a parameter", name)));
! switch (nodeTag(value))
{
case T_Integer:
{
char *str = palloc(32);
! snprintf(str, 32, "%ld", (long) intVal(value));
return str;
}
case T_Float:
*************** defGetString(DefElem *def)
*** 81,100 ****
* T_Float values are kept in string form, so this type cheat
* works (and doesn't risk losing precision)
*/
! return strVal(def->arg);
case T_String:
! return strVal(def->arg);
case T_TypeName:
! return TypeNameToString((TypeName *) def->arg);
case T_List:
! return NameListToString((List *) def->arg);
default:
! elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
}
return NULL; /* keep compiler quiet */
}
/*
* Extract a numeric value (actually double) from a DefElem.
*/
double
--- 77,105 ----
* T_Float values are kept in string form, so this type cheat
* works (and doesn't risk losing precision)
*/
! return strVal(value);
case T_String:
! return strVal(value);
case T_TypeName:
! return TypeNameToString((TypeName *) value);
case T_List:
! return NameListToString((List *) value);
default:
! 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.
*/
double
*************** defGetNumeric(DefElem *def)
*** 120,144 ****
return 0; /* keep compiler quiet */
}
! /*
! * Extract a boolean value from a DefElem.
! */
! bool
! defGetBoolean(DefElem *def)
{
/*
* 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;
--- 125,146 ----
return 0; /* keep compiler quiet */
}
! static bool
! nodeGetBoolean(Node *value, char *name)
{
/*
* If no parameter given, assume "true" is meant.
*/
! if (value == NULL)
return true;
/*
* Allow 0, 1, "true", "false"
*/
! switch (nodeTag(value))
{
case T_Integer:
! switch (intVal(value))
{
case 0:
return false;
*************** defGetBoolean(DefElem *def)
*** 151,157 ****
break;
default:
{
! char *sval = defGetString(def);
if (pg_strcasecmp(sval, "true") == 0)
return true;
--- 153,159 ----
break;
default:
{
! char *sval = nodeGetString(value, name);
if (pg_strcasecmp(sval, "true") == 0)
return true;
*************** defGetBoolean(DefElem *def)
*** 163,174 ****
}
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
! errmsg("%s requires a Boolean value",
! def->defname)));
return false; /* keep compiler quiet */
}
/*
* Extract an int64 value from a DefElem.
*/
int64
--- 165,184 ----
}
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
! 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.
*/
int64
*************** defGetTypeLength(DefElem *def)
*** 305,319 ****
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;
}
--- 315,349 ----
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 ReloptElem setting "oids" to the specified value.
*/
! ReloptElem *
! reloptWithOids(bool value)
{
! ReloptElem *f = makeNode(ReloptElem);
! f->optname = "oids";
! f->nmspc = NULL;
f->arg = (Node *) makeInteger(value);
return f;
}
Index: src/backend/commands/indexcmds.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/indexcmds.c,v
retrieving revision 1.181
diff -c -p -r1.181 indexcmds.c
*** src/backend/commands/indexcmds.c 1 Jan 2009 17:23:38 -0000 1.181
--- src/backend/commands/indexcmds.c 7 Jan 2009 22:17:00 -0000
*************** DefineIndex(RangeVar *heapRelation,
*** 398,404 ****
/*
* Parse AM-specific options, convert to text array form, validate.
*/
! reloptions = transformRelOptions((Datum) 0, options, false, false);
(void) index_reloptions(amoptions, reloptions, true);
--- 398,404 ----
/*
* Parse AM-specific options, convert to text array form, validate.
*/
! reloptions = transformRelOptions((Datum) 0, options, NULL, false, false);
(void) index_reloptions(amoptions, reloptions, true);
Index: src/backend/commands/sequence.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/sequence.c,v
retrieving revision 1.156
diff -c -p -r1.156 sequence.c
*** src/backend/commands/sequence.c 1 Jan 2009 17:23:39 -0000 1.156
--- src/backend/commands/sequence.c 7 Jan 2009 23:43:29 -0000
*************** DefineSequence(CreateSeqStmt *seq)
*** 198,204 ****
stmt->relation = seq->sequence;
stmt->inhRelations = NIL;
stmt->constraints = NIL;
! stmt->options = list_make1(defWithOids(false));
stmt->oncommit = ONCOMMIT_NOOP;
stmt->tablespacename = NULL;
--- 198,204 ----
stmt->relation = seq->sequence;
stmt->inhRelations = NIL;
stmt->constraints = NIL;
! stmt->options = list_make1(reloptWithOids(false));
stmt->oncommit = ONCOMMIT_NOOP;
stmt->tablespacename = NULL;
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.277
diff -c -p -r1.277 tablecmds.c
*** src/backend/commands/tablecmds.c 12 Jan 2009 08:54:26 -0000 1.277
--- src/backend/commands/tablecmds.c 13 Jan 2009 21:34:09 -0000
*************** DefineRelation(CreateStmt *stmt, char re
*** 417,423 ****
/*
* Parse and validate reloptions, if any.
*/
! reloptions = transformRelOptions((Datum) 0, stmt->options, true, false);
(void) heap_reloptions(relkind, reloptions, true);
--- 417,423 ----
/*
* Parse and validate reloptions, if any.
*/
! reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, true, false);
(void) heap_reloptions(relkind, reloptions, true);
*************** ATRewriteCatalogs(List **wqueue)
*** 2571,2577 ****
(tab->subcmds[AT_PASS_ADD_COL] ||
tab->subcmds[AT_PASS_ALTER_TYPE] ||
tab->subcmds[AT_PASS_COL_ATTRS]))
! AlterTableCreateToastTable(tab->relid);
}
}
--- 2571,2577 ----
(tab->subcmds[AT_PASS_ADD_COL] ||
tab->subcmds[AT_PASS_ALTER_TYPE] ||
tab->subcmds[AT_PASS_COL_ATTRS]))
! AlterTableCreateToastTable(tab->relid, (Datum) 0);
}
}
*************** ATExecSetRelOptions(Relation rel, List *
*** 6459,6465 ****
/* Generate new proposed reloptions (text array) */
newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
! defList, false, isReset);
/* Validate */
switch (rel->rd_rel->relkind)
--- 6459,6465 ----
/* Generate new proposed reloptions (text array) */
newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
! defList, NULL, false, isReset);
/* Validate */
switch (rel->rd_rel->relkind)
*************** ATExecSetRelOptions(Relation rel, List *
*** 6505,6510 ****
--- 6505,6557 ----
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", 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);
}
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.130
diff -c -p -r1.130 typecmds.c
*** src/backend/commands/typecmds.c 9 Jan 2009 15:46:10 -0000 1.130
--- src/backend/commands/typecmds.c 12 Jan 2009 21:35:28 -0000
*************** DefineCompositeType(const RangeVar *type
*** 1491,1497 ****
createStmt->tableElts = coldeflist;
createStmt->inhRelations = NIL;
createStmt->constraints = NIL;
! createStmt->options = list_make1(defWithOids(false));
createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
--- 1491,1497 ----
createStmt->tableElts = coldeflist;
createStmt->inhRelations = NIL;
createStmt->constraints = NIL;
! createStmt->options = list_make1(reloptWithOids(false));
createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
Index: src/backend/commands/view.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/view.c,v
retrieving revision 1.111
diff -c -p -r1.111 view.c
*** src/backend/commands/view.c 1 Jan 2009 17:23:40 -0000 1.111
--- src/backend/commands/view.c 7 Jan 2009 23:43:43 -0000
*************** DefineVirtualRelation(const RangeVar *re
*** 229,235 ****
createStmt->tableElts = attrList;
createStmt->inhRelations = NIL;
createStmt->constraints = NIL;
! createStmt->options = list_make1(defWithOids(false));
createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
--- 229,235 ----
createStmt->tableElts = attrList;
createStmt->inhRelations = NIL;
createStmt->constraints = NIL;
! createStmt->options = list_make1(reloptWithOids(false));
createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/executor/execMain.c,v
retrieving revision 1.320
diff -c -p -r1.320 execMain.c
*** src/backend/executor/execMain.c 1 Jan 2009 17:23:41 -0000 1.320
--- src/backend/executor/execMain.c 7 Jan 2009 22:10:48 -0000
*************** OpenIntoRel(QueryDesc *queryDesc)
*** 2787,2792 ****
--- 2787,2793 ----
/* Parse and validate any reloptions */
reloptions = transformRelOptions((Datum) 0,
into->options,
+ NULL,
true,
false);
(void) heap_reloptions(RELKIND_RELATION, reloptions, true);
*************** OpenIntoRel(QueryDesc *queryDesc)
*** 2823,2829 ****
* AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
* the TOAST table will be visible for insertion.
*/
! AlterTableCreateToastTable(intoRelationId);
/*
* And open the constructed table for writing.
--- 2824,2838 ----
* AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
* the TOAST table will be visible for insertion.
*/
! reloptions = transformRelOptions((Datum) 0,
! into->options,
! "toast",
! true,
! false);
!
! (void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true);
!
! AlterTableCreateToastTable(intoRelationId, reloptions);
/*
* And open the constructed table for writing.
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.419
diff -c -p -r1.419 copyfuncs.c
*** src/backend/nodes/copyfuncs.c 1 Jan 2009 17:23:43 -0000 1.419
--- src/backend/nodes/copyfuncs.c 7 Jan 2009 22:21:31 -0000
*************** _copyOptionDefElem(OptionDefElem *from)
*** 2123,2128 ****
--- 2123,2140 ----
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)
{
*************** copyObject(void *from)
*** 4066,4071 ****
--- 4078,4086 ----
case T_OptionDefElem:
retval = _copyOptionDefElem(from);
break;
+ case T_ReloptElem:
+ retval = _copyReloptElem(from);
+ break;
case T_LockingClause:
retval = _copyLockingClause(from);
break;
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.344
diff -c -p -r1.344 equalfuncs.c
*** src/backend/nodes/equalfuncs.c 1 Jan 2009 17:23:43 -0000 1.344
--- src/backend/nodes/equalfuncs.c 14 Jan 2009 14:11:16 -0000
*************** _equalOptionDefElem(OptionDefElem *a, Op
*** 2090,2095 ****
--- 2090,2105 ----
}
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)
{
COMPARE_NODE_FIELD(lockedRels);
*************** equal(void *a, void *b)
*** 2844,2849 ****
--- 2854,2862 ----
case T_OptionDefElem:
retval = _equalOptionDefElem(a, b);
break;
+ case T_ReloptElem:
+ retval = _equalReloptElem(a, b);
+ break;
case T_LockingClause:
retval = _equalLockingClause(a, b);
break;
Index: src/backend/nodes/makefuncs.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/nodes/makefuncs.c,v
retrieving revision 1.62
diff -c -p -r1.62 makefuncs.c
*** src/backend/nodes/makefuncs.c 1 Jan 2009 17:23:43 -0000 1.62
--- src/backend/nodes/makefuncs.c 7 Jan 2009 22:10:48 -0000
*************** makeOptionDefElem(int op, DefElem *def)
*** 374,376 ****
--- 374,387 ----
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;
+ }
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/nodes/outfuncs.c,v
retrieving revision 1.349
diff -c -p -r1.349 outfuncs.c
*** src/backend/nodes/outfuncs.c 1 Jan 2009 17:23:43 -0000 1.349
--- src/backend/nodes/outfuncs.c 14 Jan 2009 14:12:38 -0000
*************** _outDefElem(StringInfo str, DefElem *nod
*** 1807,1812 ****
--- 1807,1822 ----
}
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)
{
WRITE_NODE_TYPE("LOCKINGCLAUSE");
*************** _outNode(StringInfo str, void *obj)
*** 2770,2775 ****
--- 2780,2788 ----
case T_DefElem:
_outDefElem(str, obj);
break;
+ case T_ReloptElem:
+ _outReloptElem(str, obj);
+ break;
case T_LockingClause:
_outLockingClause(str, obj);
break;
Index: src/backend/parser/gram.y
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.654
diff -c -p -r2.654 gram.y
*** src/backend/parser/gram.y 12 Jan 2009 09:38:30 -0000 2.654
--- src/backend/parser/gram.y 12 Jan 2009 21:35:29 -0000
*************** static TypeName *TableFuncTypeName(List
*** 157,162 ****
--- 157,163 ----
FuncWithArgs *funwithargs;
DefElem *defelt;
OptionDefElem *optdef;
+ ReloptElem *reloptel;
SortBy *sortby;
WindowDef *windef;
JoinExpr *jexpr;
*************** static TypeName *TableFuncTypeName(List
*** 263,268 ****
--- 264,270 ----
%type <list> stmtblock stmtmulti
OptTableElementList TableElementList OptInherit definition
+ 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
*************** static TypeName *TableFuncTypeName(List
*** 276,282 ****
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
opt_select_limit opclass_item_list opclass_drop_list
opt_opfamily transaction_mode_list_or_empty
TableFuncElementList opt_type_modifiers
--- 278,284 ----
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
! 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
*************** static TypeName *TableFuncTypeName(List
*** 334,339 ****
--- 336,342 ----
%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
*************** alter_table_cmd:
*** 1773,1779 ****
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET (...) */
! | SET definition
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_SetRelOptions;
--- 1776,1782 ----
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET (...) */
! | SET reloptions
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_SetRelOptions;
*************** alter_table_cmd:
*** 1781,1787 ****
$$ = (Node *)n;
}
/* ALTER TABLE <name> RESET (...) */
! | RESET definition
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ResetRelOptions;
--- 1784,1790 ----
$$ = (Node *)n;
}
/* ALTER TABLE <name> RESET (...) */
! | RESET reloptions
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ResetRelOptions;
*************** alter_using:
*** 1806,1812 ****
--- 1809,1841 ----
| /* EMPTY */ { $$ = NULL; }
;
+ reloptions:
+ '(' reloption_list ')' { $$ = $2; }
+ ;
+
+ 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);
+ }
+ ;
/*****************************************************************************
*
*************** OptInherit: INHERITS '(' qualified_name_
*** 2432,2440 ****
/* 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)); }
| /*EMPTY*/ { $$ = NIL; }
;
--- 2461,2469 ----
/* WITH (options) is preferred, WITH OIDS and WITHOUT OIDS are legacy forms */
OptWith:
! WITH reloptions { $$ = $2; }
! | WITH OIDS { $$ = list_make1(reloptWithOids(true)); }
! | WITHOUT OIDS { $$ = list_make1(reloptWithOids(false)); }
| /*EMPTY*/ { $$ = NIL; }
;
Index: src/backend/parser/parse_clause.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/parser/parse_clause.c,v
retrieving revision 1.185
diff -c -p -r1.185 parse_clause.c
*** src/backend/parser/parse_clause.c 1 Jan 2009 17:23:45 -0000 1.185
--- src/backend/parser/parse_clause.c 7 Jan 2009 23:04:33 -0000
*************** interpretInhOption(InhOption inhOpt)
*** 233,239 ****
}
/*
! * 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.
--- 233,239 ----
}
/*
! * 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.
*************** interpretOidsOption(List *defList)
*** 246,255 ****
/* Scan list to see if OIDS was included */
foreach(cell, defList)
{
! DefElem *def = (DefElem *) lfirst(cell);
! if (pg_strcasecmp(def->defname, "oids") == 0)
! return defGetBoolean(def);
}
/* OIDS option was not specified, so use default. */
--- 246,255 ----
/* Scan list to see if OIDS was included */
foreach(cell, defList)
{
! ReloptElem *def = (ReloptElem *) lfirst(cell);
! if (pg_strcasecmp(def->optname, "oids") == 0)
! return reloptGetBoolean(def);
}
/* OIDS option was not specified, so use default. */
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.304
diff -c -p -r1.304 utility.c
*** src/backend/tcop/utility.c 1 Jan 2009 17:23:48 -0000 1.304
--- src/backend/tcop/utility.c 7 Jan 2009 22:10:48 -0000
***************
*** 16,21 ****
--- 16,22 ----
*/
#include "postgres.h"
+ #include "access/reloptions.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "catalog/catalog.h"
*************** ProcessUtility(Node *parsetree,
*** 422,427 ****
--- 423,430 ----
if (IsA(stmt, CreateStmt))
{
+ Datum toast_options;
+
/* Create the table itself */
relOid = DefineRelation((CreateStmt *) stmt,
RELKIND_RELATION);
*************** ProcessUtility(Node *parsetree,
*** 431,437 ****
* needs a secondary relation too.
*/
CommandCounterIncrement();
! AlterTableCreateToastTable(relOid);
}
else
{
--- 434,449 ----
* needs a secondary relation too.
*/
CommandCounterIncrement();
!
! /* parse and validate reloptions for the toast table */
! toast_options = transformRelOptions((Datum) 0,
! ((CreateStmt *)stmt)->options,
! "toast",
! true, false);
! (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options,
! true);
!
! AlterTableCreateToastTable(relOid, toast_options);
}
else
{
Index: src/include/access/reloptions.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/access/reloptions.h,v
retrieving revision 1.10
diff -c -p -r1.10 reloptions.h
*** src/include/access/reloptions.h 12 Jan 2009 21:02:15 -0000 1.10
--- src/include/access/reloptions.h 12 Jan 2009 23:38:37 -0000
*************** extern void add_string_reloption(int kin
*** 239,245 ****
char *default_val, validate_string_relopt validator);
extern Datum transformRelOptions(Datum oldOptions, List *defList,
! bool ignoreOids, bool isReset);
extern List *untransformRelOptions(Datum options);
extern relopt_value *parseRelOptions(Datum options, bool validate,
relopt_kind kind, int *numrelopts);
--- 239,245 ----
char *default_val, validate_string_relopt validator);
extern Datum transformRelOptions(Datum oldOptions, List *defList,
! char *namspace, bool ignoreOids, bool isReset);
extern List *untransformRelOptions(Datum options);
extern relopt_value *parseRelOptions(Datum options, bool validate,
relopt_kind kind, int *numrelopts);
Index: src/include/catalog/toasting.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/catalog/toasting.h,v
retrieving revision 1.5
diff -c -p -r1.5 toasting.h
*** src/include/catalog/toasting.h 1 Jan 2009 17:23:58 -0000 1.5
--- src/include/catalog/toasting.h 7 Jan 2009 22:10:48 -0000
***************
*** 17,23 ****
/*
* toasting.c prototypes
*/
! extern void AlterTableCreateToastTable(Oid relOid);
extern void BootstrapToastTable(char *relName,
Oid toastOid, Oid toastIndexOid);
--- 17,23 ----
/*
* toasting.c prototypes
*/
! extern void AlterTableCreateToastTable(Oid relOid, Datum reloptions);
extern void BootstrapToastTable(char *relName,
Oid toastOid, Oid toastIndexOid);
Index: src/include/commands/defrem.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/commands/defrem.h,v
retrieving revision 1.92
diff -c -p -r1.92 defrem.h
*** src/include/commands/defrem.h 1 Jan 2009 17:23:58 -0000 1.92
--- src/include/commands/defrem.h 13 Jan 2009 00:06:05 -0000
*************** extern int64 defGetInt64(DefElem *def);
*** 145,150 ****
extern List *defGetQualifiedName(DefElem *def);
extern TypeName *defGetTypeName(DefElem *def);
extern int defGetTypeLength(DefElem *def);
! extern DefElem *defWithOids(bool value);
#endif /* DEFREM_H */
--- 145,152 ----
extern List *defGetQualifiedName(DefElem *def);
extern TypeName *defGetTypeName(DefElem *def);
extern int defGetTypeLength(DefElem *def);
! extern char *reloptGetString(ReloptElem *relopt);
! extern bool reloptGetBoolean(ReloptElem *relopt);
! extern ReloptElem *reloptWithOids(bool value);
#endif /* DEFREM_H */
Index: src/include/nodes/makefuncs.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/nodes/makefuncs.h,v
retrieving revision 1.65
diff -c -p -r1.65 makefuncs.h
*** src/include/nodes/makefuncs.h 1 Jan 2009 17:24:00 -0000 1.65
--- src/include/nodes/makefuncs.h 7 Jan 2009 22:10:48 -0000
*************** extern DefElem *makeDefElem(char *name,
*** 69,72 ****
--- 69,74 ----
extern OptionDefElem *makeOptionDefElem(int op, DefElem *def);
+ extern ReloptElem *makeReloptElem(char *name, char *namspc, Node *arg);
+
#endif /* MAKEFUNC_H */
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.218
diff -c -p -r1.218 nodes.h
*** src/include/nodes/nodes.h 1 Jan 2009 17:24:00 -0000 1.218
--- src/include/nodes/nodes.h 7 Jan 2009 22:10:48 -0000
*************** typedef enum NodeTag
*** 363,368 ****
--- 363,369 ----
T_Constraint,
T_DefElem,
T_OptionDefElem,
+ T_ReloptElem,
T_RangeTblEntry,
T_SortGroupClause,
T_WindowClause,
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.387
diff -c -p -r1.387 parsenodes.h
*** src/include/nodes/parsenodes.h 1 Jan 2009 17:24:00 -0000 1.387
--- src/include/nodes/parsenodes.h 7 Jan 2009 22:10:48 -0000
*************** typedef struct OptionDefElem
*** 532,537 ****
--- 532,548 ----
} 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
*
* Note: lockedRels == NIL means "all relations in query". Otherwise it
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers