From 3a5b77371522b64feda006a7aed2a0e57bfb2b22 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Mon, 2 Feb 2009 19:31:40 +0000
Subject: [PATCH] Allow reloption names to have qualifiers, initially
 supporting a TOAST qualifier, and add support for this in pg_dump.

This allows TOAST tables to have user-defined fillfactor, and will also
enable us to move the autovacuum parameters to reloptions without taking
away the possibility of setting values for TOAST tables.
---
 doc/src/sgml/ref/create_index.sgml     |  8 ++-
 doc/src/sgml/ref/create_table.sgml     | 16 ++++-
 src/backend/access/common/reloptions.c | 92 ++++++++++++++++++++-----
 src/backend/catalog/toasting.c         | 19 +++---
 src/backend/commands/cluster.c         | 22 +++++-
 src/backend/commands/define.c          | 94 +++++++++++++++++---------
 src/backend/commands/indexcmds.c       |  4 +-
 src/backend/commands/sequence.c        |  4 +-
 src/backend/commands/tablecmds.c       | 58 ++++++++++++++--
 src/backend/commands/typecmds.c        |  4 +-
 src/backend/commands/view.c            |  4 +-
 src/backend/executor/execMain.c        | 16 ++++-
 src/backend/nodes/copyfuncs.c          | 17 ++++-
 src/backend/nodes/equalfuncs.c         | 15 +++-
 src/backend/nodes/makefuncs.c          | 13 +++-
 src/backend/nodes/outfuncs.c           | 15 +++-
 src/backend/parser/gram.y              | 52 +++++++++++---
 src/backend/parser/parse_clause.c      | 10 +--
 src/backend/tcop/utility.c             | 18 ++++-
 src/bin/pg_dump/pg_dump.c              | 59 +++++++++++-----
 src/bin/pg_dump/pg_dump.h              |  3 +-
 src/include/access/reloptions.h        |  6 +-
 src/include/catalog/toasting.h         |  4 +-
 src/include/commands/defrem.h          |  6 +-
 src/include/nodes/makefuncs.h          |  4 +-
 src/include/nodes/nodes.h              |  3 +-
 src/include/nodes/parsenodes.h         | 13 +++-
 27 files changed, 452 insertions(+), 127 deletions(-)

diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml
index b387da49f0c..3596b5df288 100644
--- a/doc/src/sgml/ref/create_index.sgml
+++ b/doc/src/sgml/ref/create_index.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.69 2008/11/14 10:22:46 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.70 2009/02/02 19:31:38 alvherre Exp $
 PostgreSQL documentation
 -->
 
@@ -231,7 +231,8 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] <replaceable class="parameter">name</re
       <listitem>
        <para>
         The name of an index-method-specific storage parameter.  See
-        below for details.
+        <xref linkend="sql-createindex-storage-parameters" endterm="sql-createindex-storage-parameters-title">
+        for details.
        </para>
       </listitem>
      </varlistentry>
@@ -265,7 +266,8 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] <replaceable class="parameter">name</re
    <para>
     The <literal>WITH</> clause can specify <firstterm>storage parameters</>
     for indexes.  Each index method can have its own set of allowed storage
-    parameters.  The built-in index methods all accept a single parameter:
+    parameters.  The <literal>B-tree</literal>, <literal>hash</literal> and
+    <literal>GiST</literal> built-in index methods all accept a single parameter:
    </para>
 
    <variablelist>
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index e7d14a53ce1..285ed5bd2e9 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.111 2008/11/14 10:22:46 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.112 2009/02/02 19:31:38 alvherre Exp $
 PostgreSQL documentation
 -->
 
@@ -690,8 +690,8 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
     for tables, and for indexes associated with a <literal>UNIQUE</literal> or
     <literal>PRIMARY KEY</literal> constraint.  Storage parameters for
     indexes are documented in <xref linkend="SQL-CREATEINDEX"
-    endterm="sql-createindex-title">.  The only storage parameter currently
-    available for tables is:
+    endterm="sql-createindex-title">.  The storage parameters currently
+    available for tables are:
    </para>
 
    <variablelist>
@@ -714,6 +714,16 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><literal>TOAST.FILLFACTOR</literal></term>
+    <listitem>
+     <para>
+      Same as above, for the supplementary storage table, if any; see
+      <xref linkend="storage-toast">.
+     </para>
+    </listitem>
+   </varlistentry>
+
    </variablelist>
 
   </refsect2>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 105514be9dd..e566a136442 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.19 2009/01/26 19:41:06 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.20 2009/02/02 19:31:38 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -390,8 +390,10 @@ add_string_reloption(int kind, char *name, char *desc, char *default_val,
 }
 
 /*
- * Transform a relation options list (list of DefElem) into the text array
- * format that is kept in pg_class.reloptions.
+ * Transform a relation options list (list of ReloptElem) into the text array
+ * format that is kept in pg_class.reloptions, including only those options
+ * that are in the passed namespace.  The output values do not include the
+ * namespace.
  *
  * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
  * ALTER TABLE RESET.  In the ALTER cases, oldOptions is the existing
@@ -402,14 +404,17 @@ add_string_reloption(int kind, char *name, char *desc, char *default_val,
  * in the list (it will be or has been handled by interpretOidsOption()).
  *
  * Note that this is not responsible for determining whether the options
- * are valid.
+ * are valid, but it does check that namespaces for all the options given are
+ * listed in validnsps.  The NULL namespace is always valid and needs not be
+ * explicitely listed.  Passing a NULL pointer means that only the NULL
+ * namespace is valid.
  *
  * Both oldOptions and the result are text arrays (or NULL for "default"),
  * but we declare them as Datums to avoid including array.h in reloptions.h.
  */
 Datum
-transformRelOptions(Datum oldOptions, List *defList,
-					bool ignoreOids, bool isReset)
+transformRelOptions(Datum oldOptions, List *defList, char *namspace,
+					char *validnsps[], bool ignoreOids, bool isReset)
 {
 	Datum		result;
 	ArrayBuildState *astate;
@@ -444,11 +449,23 @@ transformRelOptions(Datum oldOptions, List *defList,
 			/* Search for a match in defList */
 			foreach(cell, defList)
 			{
-				DefElem    *def = lfirst(cell);
-				int			kw_len = strlen(def->defname);
+				ReloptElem *def = lfirst(cell);
+				int			kw_len;
 
+				/* ignore if not in the same namespace */
+				if (namspace == NULL)
+				{
+					if (def->nmspc != NULL)
+						continue;
+				}
+				else if (def->nmspc == NULL)
+					continue;
+				else if (pg_strcasecmp(def->nmspc, namspace) != 0)
+					continue;
+
+				kw_len = strlen(def->optname);
 				if (text_len > kw_len && text_str[kw_len] == '=' &&
-					pg_strncasecmp(text_str, def->defname, kw_len) == 0)
+					pg_strncasecmp(text_str, def->optname, kw_len) == 0)
 					break;
 			}
 			if (!cell)
@@ -468,7 +485,8 @@ transformRelOptions(Datum oldOptions, List *defList,
 	 */
 	foreach(cell, defList)
 	{
-		DefElem    *def = lfirst(cell);
+		ReloptElem    *def = lfirst(cell);
+
 
 		if (isReset)
 		{
@@ -483,22 +501,62 @@ transformRelOptions(Datum oldOptions, List *defList,
 			const char *value;
 			Size		len;
 
-			if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
+			/*
+			 * Error out if the namespace is not valid.  A NULL namespace
+			 * is always valid.
+			 */
+			if (def->nmspc != NULL)
+			{
+				bool	valid = false;
+				int		i;
+
+				if (validnsps)
+				{
+					for (i = 0; validnsps[i]; i++)
+					{
+						if (pg_strcasecmp(def->nmspc, validnsps[i]) == 0)
+						{
+							valid = true;
+							break;
+						}
+					}
+				}
+
+				if (!valid)
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							 errmsg("unrecognized parameter namespace \"%s\"",
+									def->nmspc)));
+			}
+
+			if (ignoreOids && pg_strcasecmp(def->optname, "oids") == 0)
+				continue;
+
+			/* ignore if not in the same namespace */
+			if (namspace == NULL)
+			{
+				if (def->nmspc != NULL)
+					continue;
+			}
+			else if (def->nmspc == NULL)
+				continue;
+			else if (pg_strcasecmp(def->nmspc, namspace) != 0)
 				continue;
 
 			/*
-			 * Flatten the DefElem into a text string like "name=arg". If we
-			 * have just "name", assume "name=true" is meant.
+			 * Flatten the ReloptElem into a text string like "name=arg". If we
+			 * have just "name", assume "name=true" is meant.  Note: the
+			 * namespace is not output.
 			 */
 			if (def->arg != NULL)
-				value = defGetString(def);
+				value = reloptGetString(def);
 			else
 				value = "true";
-			len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
+			len = VARHDRSZ + strlen(def->optname) + 1 + strlen(value);
 			/* +1 leaves room for sprintf's trailing null */
 			t = (text *) palloc(len + 1);
 			SET_VARSIZE(t, len);
-			sprintf(VARDATA(t), "%s=%s", def->defname, value);
+			sprintf(VARDATA(t), "%s=%s", def->optname, value);
 
 			astate = accumArrayResult(astate, PointerGetDatum(t),
 									  false, TEXTOID,
@@ -944,7 +1002,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
 }
 
 /*
- * Parse options for heaps (and perhaps someday toast tables).
+ * Parse options for heaps and toast tables.
  */
 bytea *
 heap_reloptions(char relkind, Datum reloptions, bool validate)
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 3809c0f1b80..7510f96b47c 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.12 2009/01/01 17:23:37 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.13 2009/02/02 19:31:38 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,7 +32,8 @@
 #include "utils/syscache.h"
 
 
-static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid);
+static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
+				   Datum reloptions);
 static bool needs_toast_table(Relation rel);
 
 
@@ -46,7 +47,7 @@ static bool needs_toast_table(Relation rel);
  * to end with CommandCounterIncrement if it makes any changes.
  */
 void
-AlterTableCreateToastTable(Oid relOid)
+AlterTableCreateToastTable(Oid relOid, Datum reloptions)
 {
 	Relation	rel;
 
@@ -58,7 +59,7 @@ AlterTableCreateToastTable(Oid relOid)
 	rel = heap_open(relOid, AccessExclusiveLock);
 
 	/* create_toast_table does all the work */
-	(void) create_toast_table(rel, InvalidOid, InvalidOid);
+	(void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions);
 
 	heap_close(rel, NoLock);
 }
@@ -84,7 +85,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
 						relName)));
 
 	/* create_toast_table does all the work */
-	if (!create_toast_table(rel, toastOid, toastIndexOid))
+	if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0))
 		elog(ERROR, "\"%s\" does not require a toast table",
 			 relName);
 
@@ -100,7 +101,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
  * bootstrap they can be nonzero to specify hand-assigned OIDs
  */
 static bool
-create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid)
+create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptions)
 {
 	Oid			relOid = RelationGetRelid(rel);
 	HeapTuple	reltup;
@@ -183,10 +184,6 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid)
 	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,
@@ -199,7 +196,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid)
 										   true,
 										   0,
 										   ONCOMMIT_NOOP,
-										   (Datum) 0,
+										   reloptions,
 										   true);
 
 	/* make the toast relation visible, else index creation will fail */
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index e5bff5cb3ef..6f578440da8 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.181 2009/01/16 13:27:23 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.182 2009/02/02 19:31:38 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -668,6 +668,7 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
 	TupleDesc	OldHeapDesc,
 				tupdesc;
 	Oid			OIDNewHeap;
+	Oid			toastid;
 	Relation	OldHeap;
 	HeapTuple	tuple;
 	Datum		reloptions;
@@ -726,7 +727,24 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
 	 * AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
 	 * the TOAST table will be visible for insertion.
 	 */
-	AlterTableCreateToastTable(OIDNewHeap);
+	toastid = OldHeap->rd_rel->reltoastrelid;
+	reloptions = (Datum) 0;
+	if (OidIsValid(toastid))
+	{
+		tuple = SearchSysCache(RELOID,
+							   ObjectIdGetDatum(toastid),
+							   0, 0, 0);
+		if (!HeapTupleIsValid(tuple))
+			elog(ERROR, "cache lookup failed for relation %u", toastid);
+		reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
+									 &isNull);
+		if (isNull)
+			reloptions = (Datum) 0;
+	}
+	AlterTableCreateToastTable(OIDNewHeap, reloptions);
+
+	if (OidIsValid(toastid))
+		ReleaseSysCache(tuple);
 
 	heap_close(OldHeap, NoLock);
 
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 77f7d8bfdb9..c5e2a13d950 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.102 2009/01/01 17:23:37 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.103 2009/02/02 19:31:38 alvherre Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -55,24 +55,20 @@ case_translate_language_name(const char *input)
 }
 
 
-/*
- * Extract a string value (otherwise uninterpreted) from a DefElem.
- */
-char *
-defGetString(DefElem *def)
+static char *
+nodeGetString(Node *value, char *name)
 {
-	if (def->arg == NULL)
+	if (value == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
-				 errmsg("%s requires a parameter",
-						def->defname)));
-	switch (nodeTag(def->arg))
+				 errmsg("%s requires a parameter", name)));
+	switch (nodeTag(value))
 	{
 		case T_Integer:
 			{
 				char	   *str = palloc(32);
 
-				snprintf(str, 32, "%ld", (long) intVal(def->arg));
+				snprintf(str, 32, "%ld", (long) intVal(value));
 				return str;
 			}
 		case T_Float:
@@ -81,19 +77,28 @@ defGetString(DefElem *def)
 			 * T_Float values are kept in string form, so this type cheat
 			 * works (and doesn't risk losing precision)
 			 */
-			return strVal(def->arg);
+			return strVal(value);
 		case T_String:
-			return strVal(def->arg);
+			return strVal(value);
 		case T_TypeName:
-			return TypeNameToString((TypeName *) def->arg);
+			return TypeNameToString((TypeName *) value);
 		case T_List:
-			return NameListToString((List *) def->arg);
+			return NameListToString((List *) value);
 		default:
-			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
+			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(value));
 	}
 	return NULL;				/* keep compiler quiet */
 }
 
+/*
+ * Extract a string value (otherwise uninterpreted) from a DefElem.
+ */
+char *
+defGetString(DefElem *def)
+{
+	return nodeGetString(def->arg, def->defname);
+}
+
 /*
  * Extract a numeric value (actually double) from a DefElem.
  */
@@ -120,25 +125,22 @@ defGetNumeric(DefElem *def)
 	return 0;					/* keep compiler quiet */
 }
 
-/*
- * Extract a boolean value from a DefElem.
- */
-bool
-defGetBoolean(DefElem *def)
+static bool
+nodeGetBoolean(Node *value, char *name)
 {
 	/*
 	 * If no parameter given, assume "true" is meant.
 	 */
-	if (def->arg == NULL)
+	if (value == NULL)
 		return true;
 
 	/*
 	 * Allow 0, 1, "true", "false"
 	 */
-	switch (nodeTag(def->arg))
+	switch (nodeTag(value))
 	{
 		case T_Integer:
-			switch (intVal(def->arg))
+			switch (intVal(value))
 			{
 				case 0:
 					return false;
@@ -151,7 +153,7 @@ defGetBoolean(DefElem *def)
 			break;
 		default:
 			{
-				char	   *sval = defGetString(def);
+				char	   *sval = nodeGetString(value, name);
 
 				if (pg_strcasecmp(sval, "true") == 0)
 					return true;
@@ -163,11 +165,19 @@ defGetBoolean(DefElem *def)
 	}
 	ereport(ERROR,
 			(errcode(ERRCODE_SYNTAX_ERROR),
-			 errmsg("%s requires a Boolean value",
-					def->defname)));
+			 errmsg("%s requires a Boolean value", name)));
 	return false;				/* keep compiler quiet */
 }
 
+/*
+ * Extract a boolean value from a DefElem.
+ */
+bool
+defGetBoolean(DefElem *def)
+{
+	return nodeGetBoolean(def->arg, def->defname);
+}
+
 /*
  * Extract an int64 value from a DefElem.
  */
@@ -305,15 +315,35 @@ defGetTypeLength(DefElem *def)
 	return 0;					/* keep compiler quiet */
 }
 
+
+/*
+ * Extract a string value (otherwise uninterpreted) from a ReloptElem.
+ */
+char *
+reloptGetString(ReloptElem *relopt)
+{
+	return nodeGetString(relopt->arg, relopt->optname);
+}
+
+/*
+ * Extract a boolean value from a ReloptElem.
+ */
+bool
+reloptGetBoolean(ReloptElem *relopt)
+{
+	return nodeGetBoolean(relopt->arg, relopt->optname);
+}
+
 /*
- * Create a DefElem setting "oids" to the specified value.
+ * Create a ReloptElem setting "oids" to the specified value.
  */
-DefElem *
-defWithOids(bool value)
+ReloptElem *
+reloptWithOids(bool value)
 {
-	DefElem    *f = makeNode(DefElem);
+	ReloptElem    *f = makeNode(ReloptElem);
 
-	f->defname = "oids";
+	f->optname = "oids";
+	f->nmspc = NULL;
 	f->arg = (Node *) makeInteger(value);
 	return f;
 }
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 55422e8b313..b0cd2ef0d15 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.181 2009/01/01 17:23:38 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.182 2009/02/02 19:31:38 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -398,7 +398,7 @@ DefineIndex(RangeVar *heapRelation,
 	/*
 	 * Parse AM-specific options, convert to text array form, validate.
 	 */
-	reloptions = transformRelOptions((Datum) 0, options, false, false);
+	reloptions = transformRelOptions((Datum) 0, options, NULL, NULL, false, false);
 
 	(void) index_reloptions(amoptions, reloptions, true);
 
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index d68f525ba02..deeed230784 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.157 2009/01/20 18:59:37 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.158 2009/02/02 19:31:38 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -198,7 +198,7 @@ DefineSequence(CreateSeqStmt *seq)
 	stmt->relation = seq->sequence;
 	stmt->inhRelations = NIL;
 	stmt->constraints = NIL;
-	stmt->options = list_make1(defWithOids(false));
+	stmt->options = list_make1(reloptWithOids(false));
 	stmt->oncommit = ONCOMMIT_NOOP;
 	stmt->tablespacename = NULL;
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 397e010acaf..cda87e28b30 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.278 2009/01/22 20:16:02 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.279 2009/02/02 19:31:38 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -351,6 +351,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
 	Datum		reloptions;
 	ListCell   *listptr;
 	AttrNumber	attnum;
+	static char	   *validnsps[] = HEAP_RELOPT_NAMESPACES;
 
 	/*
 	 * Truncate relname to appropriate length (probably a waste of time, as
@@ -418,7 +419,8 @@ DefineRelation(CreateStmt *stmt, char relkind)
 	/*
 	 * Parse and validate reloptions, if any.
 	 */
-	reloptions = transformRelOptions((Datum) 0, stmt->options, true, false);
+	reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
+									 true, false);
 
 	(void) heap_reloptions(relkind, reloptions, true);
 
@@ -2572,7 +2574,7 @@ ATRewriteCatalogs(List **wqueue)
 			(tab->subcmds[AT_PASS_ADD_COL] ||
 			 tab->subcmds[AT_PASS_ALTER_TYPE] ||
 			 tab->subcmds[AT_PASS_COL_ATTRS]))
-			AlterTableCreateToastTable(tab->relid);
+			AlterTableCreateToastTable(tab->relid, (Datum) 0);
 	}
 }
 
@@ -6457,6 +6459,7 @@ ATExecSetRelOptions(Relation rel, List *defList, bool isReset)
 	Datum		repl_val[Natts_pg_class];
 	bool		repl_null[Natts_pg_class];
 	bool		repl_repl[Natts_pg_class];
+	static char	   *validnsps[] = HEAP_RELOPT_NAMESPACES;
 
 	if (defList == NIL)
 		return;					/* nothing to do */
@@ -6475,7 +6478,7 @@ ATExecSetRelOptions(Relation rel, List *defList, bool isReset)
 
 	/* Generate new proposed reloptions (text array) */
 	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
-									 defList, false, isReset);
+									 defList, NULL, validnsps, false, isReset);
 
 	/* Validate */
 	switch (rel->rd_rel->relkind)
@@ -6521,6 +6524,53 @@ ATExecSetRelOptions(Relation rel, List *defList, bool isReset)
 
 	ReleaseSysCache(tuple);
 
+	/* repeat the whole exercise for the toast table, if there's one */
+	if (OidIsValid(rel->rd_rel->reltoastrelid))
+	{
+		Relation	toastrel;
+		Oid			toastid = rel->rd_rel->reltoastrelid;
+
+		toastrel = heap_open(toastid, AccessExclusiveLock);
+
+		/* Get the old reloptions */
+		tuple = SearchSysCache(RELOID,
+							   ObjectIdGetDatum(toastid),
+							   0, 0, 0);
+		if (!HeapTupleIsValid(tuple))
+			elog(ERROR, "cache lookup failed for relation %u", toastid);
+
+		datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull);
+
+		newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
+										 defList, "toast", validnsps, false, isReset);
+
+		(void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
+
+		memset(repl_val, 0, sizeof(repl_val));
+		memset(repl_null, false, sizeof(repl_null));
+		memset(repl_repl, false, sizeof(repl_repl));
+
+		if (newOptions != (Datum) 0)
+			repl_val[Anum_pg_class_reloptions - 1] = newOptions;
+		else
+			repl_null[Anum_pg_class_reloptions - 1] = true;
+
+		repl_repl[Anum_pg_class_reloptions - 1] = true;
+
+		newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass),
+									 repl_val, repl_null, repl_repl);
+
+		simple_heap_update(pgclass, &newtuple->t_self, newtuple);
+
+		CatalogUpdateIndexes(pgclass, newtuple);
+
+		heap_freetuple(newtuple);
+
+		ReleaseSysCache(tuple);
+
+		heap_close(toastrel, NoLock);
+	}
+
 	heap_close(pgclass, RowExclusiveLock);
 }
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 1bd0ef2cd13..ca87b15068f 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.130 2009/01/09 15:46:10 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.131 2009/02/02 19:31:39 alvherre Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -1491,7 +1491,7 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
 	createStmt->tableElts = coldeflist;
 	createStmt->inhRelations = NIL;
 	createStmt->constraints = NIL;
-	createStmt->options = list_make1(defWithOids(false));
+	createStmt->options = list_make1(reloptWithOids(false));
 	createStmt->oncommit = ONCOMMIT_NOOP;
 	createStmt->tablespacename = NULL;
 
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 909c6a8865c..4d8717d2511 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.113 2009/01/27 12:40:15 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.114 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -229,7 +229,7 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
 		createStmt->tableElts = attrList;
 		createStmt->inhRelations = NIL;
 		createStmt->constraints = NIL;
-		createStmt->options = list_make1(defWithOids(false));
+		createStmt->options = list_make1(reloptWithOids(false));
 		createStmt->oncommit = ONCOMMIT_NOOP;
 		createStmt->tablespacename = NULL;
 
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 0352d9a5e43..41b6737049b 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.321 2009/01/22 20:16:03 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.322 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2832,6 +2832,7 @@ OpenIntoRel(QueryDesc *queryDesc)
 	Oid			intoRelationId;
 	TupleDesc	tupdesc;
 	DR_intorel *myState;
+	static char	   *validnsps[] = HEAP_RELOPT_NAMESPACES;
 
 	Assert(into);
 
@@ -2890,6 +2891,8 @@ OpenIntoRel(QueryDesc *queryDesc)
 	/* Parse and validate any reloptions */
 	reloptions = transformRelOptions((Datum) 0,
 									 into->options,
+									 NULL,
+									 validnsps,
 									 true,
 									 false);
 	(void) heap_reloptions(RELKIND_RELATION, reloptions, true);
@@ -2926,7 +2929,16 @@ OpenIntoRel(QueryDesc *queryDesc)
 	 * AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
 	 * the TOAST table will be visible for insertion.
 	 */
-	AlterTableCreateToastTable(intoRelationId);
+	reloptions = transformRelOptions((Datum) 0,
+									 into->options,
+									 "toast",
+									 validnsps,
+									 true,
+									 false);
+
+	(void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true);
+
+	AlterTableCreateToastTable(intoRelationId, reloptions);
 
 	/*
 	 * And open the constructed table for writing.
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 06f89b16a30..de57c874e93 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.421 2009/01/22 20:16:03 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.422 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2125,6 +2125,18 @@ _copyOptionDefElem(OptionDefElem *from)
 	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)
 {
@@ -4079,6 +4091,9 @@ copyObject(void *from)
 		case T_OptionDefElem:
 			retval = _copyOptionDefElem(from);
 			break;
+		case T_ReloptElem:
+			retval = _copyReloptElem(from);
+			break;
 		case T_LockingClause:
 			retval = _copyLockingClause(from);
 			break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 4e101dd23b8..2b8b542e749 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.346 2009/01/22 20:16:03 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.347 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2098,6 +2098,16 @@ _equalOptionDefElem(OptionDefElem *a, OptionDefElem *b)
 	return true;
 }
 
+static bool
+_equalReloptElem(ReloptElem *a, ReloptElem *b)
+{
+	COMPARE_STRING_FIELD(nmspc);
+	COMPARE_STRING_FIELD(optname);
+	COMPARE_NODE_FIELD(arg);
+
+	return true;
+}
+
 static bool
 _equalLockingClause(LockingClause *a, LockingClause *b)
 {
@@ -2855,6 +2865,9 @@ equal(void *a, void *b)
 		case T_OptionDefElem:
 			retval = _equalOptionDefElem(a, b);
 			break;
+		case T_ReloptElem:
+			retval = _equalReloptElem(a, b);
+			break;
 		case T_LockingClause:
 			retval = _equalLockingClause(a, b);
 			break;
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 3bbb2a38a8c..39d7e20f83e 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.62 2009/01/01 17:23:43 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.63 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -374,3 +374,14 @@ makeOptionDefElem(int op, DefElem *def)
 	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;
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 0efd84dae8d..74df2f30616 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.350 2009/01/22 20:16:04 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.351 2009/02/02 19:31:39 alvherre Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -1804,6 +1804,16 @@ _outDefElem(StringInfo str, DefElem *node)
 	WRITE_NODE_FIELD(arg);
 }
 
+static void
+_outReloptElem(StringInfo str, ReloptElem *node)
+{
+	WRITE_NODE_TYPE("RELOPTELEM");
+
+	WRITE_STRING_FIELD(nmspc);
+	WRITE_STRING_FIELD(optname);
+	WRITE_NODE_FIELD(arg);
+}
+
 static void
 _outLockingClause(StringInfo str, LockingClause *node)
 {
@@ -2770,6 +2780,9 @@ _outNode(StringInfo str, void *obj)
 			case T_DefElem:
 				_outDefElem(str, obj);
 				break;
+			case T_ReloptElem:
+				_outReloptElem(str, obj);
+				break;
 			case T_LockingClause:
 				_outLockingClause(str, obj);
 				break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7f9e5e5b983..1bf99765f8c 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.656 2009/01/22 20:16:05 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.657 2009/02/02 19:31:39 alvherre Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -164,6 +164,7 @@ static TypeName *TableFuncTypeName(List *columns);
 	FuncWithArgs		*funwithargs;
 	DefElem				*defelt;
 	OptionDefElem		*optdef;
+	ReloptElem			*reloptel;
 	SortBy				*sortby;
 	WindowDef			*windef;
 	JoinExpr			*jexpr;
@@ -271,6 +272,7 @@ static TypeName *TableFuncTypeName(List *columns);
 
 %type <list>	stmtblock stmtmulti
 				OptTableElementList TableElementList OptInherit definition
+				reloptions opt_reloptions
 				OptWith opt_distinct opt_definition func_args func_args_list
 				func_args_with_defaults func_args_with_defaults_list
 				func_as createfunc_opt_list alterfunc_opt_list
@@ -284,7 +286,7 @@ static TypeName *TableFuncTypeName(List *columns);
 				target_list insert_column_list set_target_list
 				set_clause_list set_clause multiple_set_clause
 				ctext_expr_list ctext_row def_list indirection opt_indirection
-				group_clause TriggerFuncArgs select_limit
+				reloption_list group_clause TriggerFuncArgs select_limit
 				opt_select_limit opclass_item_list opclass_drop_list
 				opt_opfamily transaction_mode_list_or_empty
 				TableFuncElementList opt_type_modifiers
@@ -342,6 +344,7 @@ static TypeName *TableFuncTypeName(List *columns);
 %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
@@ -1781,7 +1784,7 @@ alter_table_cmd:
 					$$ = (Node *)n;
 				}
 			/* ALTER TABLE <name> SET (...) */
-			| SET definition
+			| SET reloptions
 				{
 					AlterTableCmd *n = makeNode(AlterTableCmd);
 					n->subtype = AT_SetRelOptions;
@@ -1789,7 +1792,7 @@ alter_table_cmd:
 					$$ = (Node *)n;
 				}
 			/* ALTER TABLE <name> RESET (...) */
-			| RESET definition
+			| RESET reloptions
 				{
 					AlterTableCmd *n = makeNode(AlterTableCmd);
 					n->subtype = AT_ResetRelOptions;
@@ -1814,6 +1817,37 @@ alter_using:
 			| /* EMPTY */				{ $$ = NULL; }
 		;
 
+reloptions:
+		  	'(' reloption_list ')'					{ $$ = $2; }
+		;
+
+opt_reloptions:		WITH reloptions					{ $$ = $2; }
+			 |		/* EMPTY */						{ $$ = NIL; }
+		;
+
+reloption_list:
+			reloption_elem							{ $$ = list_make1($1); }
+			| reloption_list ',' reloption_elem		{ $$ = lappend($1, $3); }
+		;
+
+reloption_elem:	
+			ColLabel '=' def_arg
+				{
+					$$ = makeReloptElem($1, NULL, (Node *) $3);
+				}
+			| ColLabel
+				{
+					$$ = makeReloptElem($1, NULL, NULL);
+				}
+			| ColLabel '.' ColLabel '=' def_arg
+				{
+					$$ = makeReloptElem($3, $1, (Node *) $5);
+				}
+			| ColLabel '.' ColLabel
+				{
+					$$ = makeReloptElem($3, $1, NULL);
+				}
+		;
 
 
 /*****************************************************************************
@@ -2440,9 +2474,9 @@ OptInherit: INHERITS '(' qualified_name_list ')'	{ $$ = $3; }
 
 /* WITH (options) is preferred, WITH OIDS and WITHOUT OIDS are legacy forms */
 OptWith:
-			WITH definition				{ $$ = $2; }
-			| WITH OIDS					{ $$ = list_make1(defWithOids(true)); }
-			| WITHOUT OIDS				{ $$ = list_make1(defWithOids(false)); }
+			WITH reloptions				{ $$ = $2; }
+			| WITH OIDS					{ $$ = list_make1(reloptWithOids(true)); }
+			| WITHOUT OIDS				{ $$ = list_make1(reloptWithOids(false)); }
 			| /*EMPTY*/					{ $$ = NIL; }
 		;
 
@@ -4473,7 +4507,7 @@ opt_granted_by: GRANTED BY RoleId						{ $$ = $3; }
 
 IndexStmt:	CREATE index_opt_unique INDEX index_name
 			ON qualified_name access_method_clause '(' index_params ')'
-			opt_definition OptTableSpace where_clause
+			opt_reloptions OptTableSpace where_clause
 				{
 					IndexStmt *n = makeNode(IndexStmt);
 					n->unique = $2;
@@ -4489,7 +4523,7 @@ IndexStmt:	CREATE index_opt_unique INDEX index_name
 				}
 			| CREATE index_opt_unique INDEX CONCURRENTLY index_name
 			ON qualified_name access_method_clause '(' index_params ')'
-			opt_definition OptTableSpace where_clause
+			opt_reloptions OptTableSpace where_clause
 				{
 					IndexStmt *n = makeNode(IndexStmt);
 					n->unique = $2;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 7e9fb9c071a..24b9ee22c75 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.186 2009/01/22 20:16:05 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.187 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -233,7 +233,7 @@ interpretInhOption(InhOption inhOpt)
 }
 
 /*
- * Given a relation-options list (of DefElems), return true iff the specified
+ * Given a relation-options list (of ReloptElems), return true iff the specified
  * table/result set should be created with OIDs. This needs to be done after
  * parsing the query string because the return value can depend upon the
  * default_with_oids GUC var.
@@ -246,10 +246,10 @@ interpretOidsOption(List *defList)
 	/* Scan list to see if OIDS was included */
 	foreach(cell, defList)
 	{
-		DefElem    *def = (DefElem *) lfirst(cell);
+		ReloptElem    *def = (ReloptElem *) lfirst(cell);
 
-		if (pg_strcasecmp(def->defname, "oids") == 0)
-			return defGetBoolean(def);
+		if (pg_strcasecmp(def->optname, "oids") == 0)
+			return reloptGetBoolean(def);
 	}
 
 	/* OIDS option was not specified, so use default. */
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 7e7d07e4f03..6c6b13e17ef 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,12 +10,13 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.305 2009/01/22 20:16:06 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.306 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "access/reloptions.h"
 #include "access/twophase.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
@@ -422,6 +423,9 @@ ProcessUtility(Node *parsetree,
 
 					if (IsA(stmt, CreateStmt))
 					{
+						Datum	toast_options;
+						static char   *validnsps[] = HEAP_RELOPT_NAMESPACES;
+
 						/* Create the table itself */
 						relOid = DefineRelation((CreateStmt *) stmt,
 												RELKIND_RELATION);
@@ -431,7 +435,17 @@ ProcessUtility(Node *parsetree,
 						 * needs a secondary relation too.
 						 */
 						CommandCounterIncrement();
-						AlterTableCreateToastTable(relOid);
+
+						/* parse and validate reloptions for the toast table */
+						toast_options = transformRelOptions((Datum) 0,
+															((CreateStmt *)stmt)->options,
+															"toast",
+															validnsps,
+															true, false);
+						(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options,
+											   true);
+
+						AlterTableCreateToastTable(relOid, toast_options);
 					}
 					else
 					{
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index cb6ae92a38d..6f057f2a33e 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
  *	by PostgreSQL
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.517 2009/01/27 12:40:15 petere Exp $
+ *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.518 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3100,6 +3100,7 @@ getTables(int *numTables)
 	int			i_owning_col;
 	int			i_reltablespace;
 	int			i_reloptions;
+	int			i_toastreloptions;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema("pg_catalog");
@@ -3131,22 +3132,24 @@ getTables(int *numTables)
 		 * owning column, if any (note this dependency is AUTO as of 8.2)
 		 */
 		appendPQExpBuffer(query,
-						  "SELECT c.tableoid, c.oid, relname, "
-						  "relacl, relkind, relnamespace, "
-						  "(%s relowner) as rolname, "
-						  "relchecks, relhastriggers, "
-						  "relhasindex, relhasrules, relhasoids, "
+						  "SELECT c.tableoid, c.oid, c.relname, "
+						  "c.relacl, c.relkind, c.relnamespace, "
+						  "(%s c.relowner) as rolname, "
+						  "c.relchecks, c.relhastriggers, "
+						  "c.relhasindex, c.relhasrules, c.relhasoids, "
 						  "d.refobjid as owning_tab, "
 						  "d.refobjsubid as owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
-						  "array_to_string(c.reloptions, ', ') as reloptions "
+						  "array_to_string(c.reloptions, ', ') as reloptions, "
+						  "array_to_string(array(select 'toast.' || x from unnest(tc.reloptions) x), ', ') as toast_reloptions "
 						  "from pg_class c "
 						  "left join pg_depend d on "
 						  "(c.relkind = '%c' and "
 						  "d.classid = c.tableoid and d.objid = c.oid and "
 						  "d.objsubid = 0 and "
 						  "d.refclassid = c.tableoid and d.deptype = 'a') "
-						  "where relkind in ('%c', '%c', '%c', '%c') "
+						  "left join pg_class tc on (c.reltoastrelid = tc.oid) "
+						  "where c.relkind in ('%c', '%c', '%c', '%c') "
 						  "order by c.oid",
 						  username_subquery,
 						  RELKIND_SEQUENCE,
@@ -3168,7 +3171,8 @@ getTables(int *numTables)
 						  "d.refobjid as owning_tab, "
 						  "d.refobjsubid as owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
-						  "array_to_string(c.reloptions, ', ') as reloptions "
+						  "array_to_string(c.reloptions, ', ') as reloptions, "
+						  "NULL as toast_reloptions "
 						  "from pg_class c "
 						  "left join pg_depend d on "
 						  "(c.relkind = '%c' and "
@@ -3197,7 +3201,8 @@ getTables(int *numTables)
 						  "d.refobjid as owning_tab, "
 						  "d.refobjsubid as owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
-						  "NULL as reloptions "
+						  "NULL as reloptions, "
+						  "NULL as toast_reloptions "
 						  "from pg_class c "
 						  "left join pg_depend d on "
 						  "(c.relkind = '%c' and "
@@ -3226,7 +3231,8 @@ getTables(int *numTables)
 						  "d.refobjid as owning_tab, "
 						  "d.refobjsubid as owning_col, "
 						  "NULL as reltablespace, "
-						  "NULL as reloptions "
+						  "NULL as reloptions, "
+						  "NULL as toast_reloptions "
 						  "from pg_class c "
 						  "left join pg_depend d on "
 						  "(c.relkind = '%c' and "
@@ -3251,7 +3257,8 @@ getTables(int *numTables)
 						  "NULL::oid as owning_tab, "
 						  "NULL::int4 as owning_col, "
 						  "NULL as reltablespace, "
-						  "NULL as reloptions "
+						  "NULL as reloptions, "
+						  "NULL as toast_reloptions "
 						  "from pg_class "
 						  "where relkind in ('%c', '%c', '%c') "
 						  "order by oid",
@@ -3271,7 +3278,8 @@ getTables(int *numTables)
 						  "NULL::oid as owning_tab, "
 						  "NULL::int4 as owning_col, "
 						  "NULL as reltablespace, "
-						  "NULL as reloptions "
+						  "NULL as reloptions, "
+						  "NULL as toast_reloptions "
 						  "from pg_class "
 						  "where relkind in ('%c', '%c', '%c') "
 						  "order by oid",
@@ -3301,7 +3309,8 @@ getTables(int *numTables)
 						  "NULL::oid as owning_tab, "
 						  "NULL::int4 as owning_col, "
 						  "NULL as reltablespace, "
-						  "NULL as reloptions "
+						  "NULL as reloptions, "
+						  "NULL as toast_reloptions "
 						  "from pg_class c "
 						  "where relkind in ('%c', '%c') "
 						  "order by oid",
@@ -3344,6 +3353,7 @@ getTables(int *numTables)
 	i_owning_col = PQfnumber(res, "owning_col");
 	i_reltablespace = PQfnumber(res, "reltablespace");
 	i_reloptions = PQfnumber(res, "reloptions");
+	i_toastreloptions = PQfnumber(res, "toast_reloptions");
 
 	if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
 	{
@@ -3389,6 +3399,7 @@ getTables(int *numTables)
 		}
 		tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
 		tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
+		tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions));
 
 		/* other fields were zeroed above */
 
@@ -9700,8 +9711,24 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 			appendPQExpBuffer(q, ")");
 		}
 
-		if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
-			appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions);
+		if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
+			(tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
+		{
+			bool	addcomma = false;
+
+			appendPQExpBuffer(q, "\nWITH (");
+			if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
+			{
+				addcomma = true;
+				appendPQExpBuffer(q, "%s", tbinfo->reloptions);
+			}
+			if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
+			{
+				appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
+								  tbinfo->toast_reloptions);
+			}
+			appendPQExpBuffer(q, ")");
+		}
 
 		appendPQExpBuffer(q, ";\n");
 
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 2f70c704280..f18703ca85c 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.149 2009/01/27 12:40:15 petere Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.150 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -221,6 +221,7 @@ typedef struct _tableInfo
 	char		relkind;
 	char	   *reltablespace;	/* relation tablespace */
 	char	   *reloptions;		/* options specified by WITH (...) */
+	char	   *toast_reloptions; /* ditto, for the TOAST table */
 	bool		hasindex;		/* does it have any indexes? */
 	bool		hasrules;		/* does it have any rules? */
 	bool		hastriggers;	/* does it have any triggers? */
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 1c23b3f004d..7c02f3b12b3 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.11 2009/01/26 19:41:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.12 2009/02/02 19:31:39 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,6 +44,9 @@ typedef enum relopt_kind
 	RELOPT_KIND_MAX = 255
 } relopt_kind;
 
+/* reloption namespaces allowed for heaps -- currently only TOAST */
+#define HEAP_RELOPT_NAMESPACES { "toast", NULL }
+
 /* generic struct to hold shared data */
 typedef struct relopt_gen
 {
@@ -240,6 +243,7 @@ extern void add_string_reloption(int kind, char *name, char *desc,
 					 char *default_val, validate_string_relopt validator);
 
 extern Datum transformRelOptions(Datum oldOptions, List *defList,
+					char *namspace, char *validnsps[],
 					bool ignoreOids, bool isReset);
 extern List *untransformRelOptions(Datum options);
 extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h
index 541bfb7dbcd..2d5eb61d29a 100644
--- a/src/include/catalog/toasting.h
+++ b/src/include/catalog/toasting.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/toasting.h,v 1.5 2009/01/01 17:23:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/toasting.h,v 1.6 2009/02/02 19:31:40 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,7 @@
 /*
  * toasting.c prototypes
  */
-extern void AlterTableCreateToastTable(Oid relOid);
+extern void AlterTableCreateToastTable(Oid relOid, Datum reloptions);
 extern void BootstrapToastTable(char *relName,
 					Oid toastOid, Oid toastIndexOid);
 
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index c8701402ca5..7fba58bef88 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.92 2009/01/01 17:23:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.93 2009/02/02 19:31:40 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -145,6 +145,8 @@ extern int64 defGetInt64(DefElem *def);
 extern List *defGetQualifiedName(DefElem *def);
 extern TypeName *defGetTypeName(DefElem *def);
 extern int	defGetTypeLength(DefElem *def);
-extern DefElem *defWithOids(bool value);
+extern char *reloptGetString(ReloptElem *relopt);
+extern bool reloptGetBoolean(ReloptElem *relopt);
+extern ReloptElem *reloptWithOids(bool value);
 
 #endif   /* DEFREM_H */
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index e497953d4c8..64c3c739f0d 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.65 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.66 2009/02/02 19:31:40 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -69,4 +69,6 @@ extern DefElem *makeDefElem(char *name, Node *arg);
 
 extern OptionDefElem *makeOptionDefElem(int op, DefElem *def);
 
+extern ReloptElem *makeReloptElem(char *name, char *namspc, Node *arg);
+
 #endif   /* MAKEFUNC_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 91efce94623..31881976bd8 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.219 2009/01/22 20:16:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.220 2009/02/02 19:31:40 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -363,6 +363,7 @@ typedef enum NodeTag
 	T_Constraint,
 	T_DefElem,
 	T_OptionDefElem,
+	T_ReloptElem,
 	T_RangeTblEntry,
 	T_SortGroupClause,
 	T_WindowClause,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b73e9f2cda6..7523982662d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.389 2009/01/22 20:16:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.390 2009/02/02 19:31:40 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -532,6 +532,17 @@ typedef struct OptionDefElem
 	DefElem		   *def;			/* The actual definition */
 } OptionDefElem;
 
+/*
+ * Reloption definition.  As DefElem, with optional option namespace.
+ */
+typedef struct ReloptElem
+{
+	NodeTag		type;
+	char	   *nmspc;
+	char	   *optname;
+	Node	   *arg;
+} ReloptElem;
+
 /*
  * LockingClause - raw representation of FOR UPDATE/SHARE options
  *
-- 
GitLab