Tom Lane wrote: > This is not only really ugly, but 100% toast-specific. The > qualified-name approach ("toast.autovacuum_enabled") has at least > a chance of being good for something else. Or just make it > toast_autovacuum_enabled and do the translation magic at some low > level in the statement execution code.
Does this look better? This is still WIP, as some cases are not handled correctly; but with this patch it's possible to set a toast table fillfactor (not that that's useful for anything AFAICS). -- 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.16 diff -c -p -r1.16 reloptions.c *** src/backend/access/common/reloptions.c 6 Jan 2009 14:47:37 -0000 1.16 --- src/backend/access/common/reloptions.c 7 Jan 2009 23:07:22 -0000 *************** add_string_reloption(int kind, char *nam *** 378,385 **** } /* ! * 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 --- 378,387 ---- } /* ! * 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 *** 396,402 **** * 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; --- 398,404 ---- * 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 *** 432,442 **** /* 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) --- 434,444 ---- /* Search for a match in defList */ foreach(cell, defList) { ! ReloptElem *def = lfirst(cell); ! int 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 *** 456,462 **** */ foreach(cell, defList) { ! DefElem *def = lfirst(cell); if (isReset) { --- 458,464 ---- */ foreach(cell, defList) { ! ReloptElem *def = lfirst(cell); if (isReset) { *************** transformRelOptions(Datum oldOptions, Li *** 471,492 **** 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, --- 473,506 ---- 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 *** 784,790 **** } /* ! * Parse options for heaps (and perhaps someday toast tables). */ bytea * heap_reloptions(char relkind, Datum reloptions, bool validate) --- 798,804 ---- } /* ! * 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 7 Jan 2009 22:10:48 -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,748 ---- * 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); ! 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 7 Jan 2009 23:43:05 -0000 *************** defGetTypeLength(DefElem *def) *** 306,319 **** } /* ! * 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; } --- 306,407 ---- } /* ! * Extract a string value (otherwise uninterpreted) from a ReloptElem. */ ! char * ! reloptGetString(ReloptElem *def) { ! if (def->arg == NULL) ! ereport(ERROR, ! (errcode(ERRCODE_SYNTAX_ERROR), ! errmsg("%s requires a parameter", ! def->optname))); ! switch (nodeTag(def->arg)) ! { ! case T_Integer: ! { ! char *str = palloc(32); ! snprintf(str, 32, "%ld", (long) intVal(def->arg)); ! 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); ! 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 boolean value from a ReloptElem. ! */ ! bool ! reloptGetBoolean(ReloptElem *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; ! case 1: ! return true; ! default: ! /* otherwise, error out below */ ! break; ! } ! break; ! default: ! { ! char *sval = reloptGetString(def); ! ! if (pg_strcasecmp(sval, "true") == 0) ! return true; ! if (pg_strcasecmp(sval, "false") == 0) ! return false; ! ! } ! break; ! } ! ereport(ERROR, ! (errcode(ERRCODE_SYNTAX_ERROR), ! errmsg("%s requires a Boolean value", ! def->optname))); ! return false; /* keep compiler quiet */ ! } ! ! /* ! * 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.276 diff -c -p -r1.276 tablecmds.c *** src/backend/commands/tablecmds.c 1 Jan 2009 17:23:39 -0000 1.276 --- src/backend/commands/tablecmds.c 7 Jan 2009 22:10:48 -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) *** 2547,2553 **** (tab->subcmds[AT_PASS_ADD_COL] || tab->subcmds[AT_PASS_ALTER_TYPE] || tab->subcmds[AT_PASS_COL_ATTRS])) ! AlterTableCreateToastTable(tab->relid); } } --- 2547,2553 ---- (tab->subcmds[AT_PASS_ADD_COL] || tab->subcmds[AT_PASS_ALTER_TYPE] || tab->subcmds[AT_PASS_COL_ATTRS])) ! AlterTableCreateToastTable(tab->relid, (Datum) 0); /* FIXME must preserve */ } } *************** ATExecSetRelOptions(Relation rel, List * *** 6435,6441 **** /* Generate new proposed reloptions (text array) */ newOptions = transformRelOptions(isnull ? (Datum) 0 : datum, ! defList, false, isReset); /* Validate */ switch (rel->rd_rel->relkind) --- 6435,6441 ---- /* Generate new proposed reloptions (text array) */ newOptions = transformRelOptions(isnull ? (Datum) 0 : datum, ! defList, NULL, false, isReset); /* Validate */ switch (rel->rd_rel->relkind) Index: src/backend/commands/typecmds.c =================================================================== RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/typecmds.c,v retrieving revision 1.129 diff -c -p -r1.129 typecmds.c *** src/backend/commands/typecmds.c 1 Jan 2009 17:23:40 -0000 1.129 --- src/backend/commands/typecmds.c 7 Jan 2009 23:43:37 -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/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/parser/gram.y =================================================================== RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/parser/gram.y,v retrieving revision 2.651 diff -c -p -r2.651 gram.y *** src/backend/parser/gram.y 1 Jan 2009 17:23:45 -0000 2.651 --- src/backend/parser/gram.y 7 Jan 2009 23:43:59 -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 *** 333,338 **** --- 335,341 ---- %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: *** 1772,1778 **** $$ = (Node *)n; } /* ALTER TABLE <name> SET (...) */ ! | SET definition { AlterTableCmd *n = makeNode(AlterTableCmd); n->subtype = AT_SetRelOptions; --- 1775,1781 ---- $$ = (Node *)n; } /* ALTER TABLE <name> SET (...) */ ! | SET reloptions { AlterTableCmd *n = makeNode(AlterTableCmd); n->subtype = AT_SetRelOptions; *************** alter_table_cmd: *** 1780,1786 **** $$ = (Node *)n; } /* ALTER TABLE <name> RESET (...) */ ! | RESET definition { AlterTableCmd *n = makeNode(AlterTableCmd); n->subtype = AT_ResetRelOptions; --- 1783,1789 ---- $$ = (Node *)n; } /* ALTER TABLE <name> RESET (...) */ ! | RESET reloptions { AlterTableCmd *n = makeNode(AlterTableCmd); n->subtype = AT_ResetRelOptions; *************** alter_using: *** 1805,1811 **** --- 1808,1840 ---- | /* 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_ *** 2431,2439 **** /* 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; } ; --- 2460,2468 ---- /* 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.8 diff -c -p -r1.8 reloptions.h *** src/include/access/reloptions.h 6 Jan 2009 14:47:37 -0000 1.8 --- src/include/access/reloptions.h 7 Jan 2009 22:10:48 -0000 *************** extern void add_string_reloption(int kin *** 201,207 **** char *default_val); 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); --- 201,207 ---- char *default_val); 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 7 Jan 2009 23:43:21 -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 *def); ! extern bool reloptGetBoolean(ReloptElem *def); ! 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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers