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

Reply via email to