diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 788e7dc5afa902eb275e863d4ab1ff0e9f5d225f..9139a9bec54b004e15f67b1107814e97dac075fc 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.234 2004/05/06 14:01:33 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.235 2004/05/08 21:21:18 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -155,6 +155,7 @@ _outIntList(StringInfo str, List *list)
 	List	   *l;
 
 	appendStringInfoChar(str, '(');
+	appendStringInfoChar(str, 'i');
 	foreach(l, list)
 		appendStringInfo(str, " %d", lfirsti(l));
 	appendStringInfoChar(str, ')');
@@ -170,6 +171,7 @@ _outOidList(StringInfo str, List *list)
 	List	   *l;
 
 	appendStringInfoChar(str, '(');
+	appendStringInfoChar(str, 'o');
 	foreach(l, list)
 		appendStringInfo(str, " %u", lfirsto(l));
 	appendStringInfoChar(str, ')');
@@ -179,8 +181,9 @@ _outOidList(StringInfo str, List *list)
  * _outBitmapset -
  *	   converts a bitmap set of integers
  *
- * Note: for historical reasons, the output is formatted exactly like
- * an integer List would be.
+ * Note: the output format is "(b int int ...)", similar to an integer List.
+ * Currently bitmapsets do not appear in any node type that is stored in
+ * rules, so there is no support in readfuncs.c for reading this format.
  */
 static void
 _outBitmapset(StringInfo str, Bitmapset *bms)
@@ -189,6 +192,7 @@ _outBitmapset(StringInfo str, Bitmapset *bms)
 	int			x;
 
 	appendStringInfoChar(str, '(');
+	appendStringInfoChar(str, 'b');
 	tmpset = bms_copy(bms);
 	while ((x = bms_first_member(tmpset)) >= 0)
 		appendStringInfo(str, " %d", x);
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 074a83890232ae205712e7335e6cd144df26c719..14f73b1860ea2d12a37b9dac644d915d7736c6d5 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.65 2003/11/29 19:51:49 pgsql Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.66 2004/05/08 21:21:18 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -194,12 +194,20 @@ pretty_format_node_dump(const char *dump)
 					}
 					j = indentDist - 1;
 					/* j will equal indentDist on next loop iteration */
+					/* suppress whitespace just after } */
+					while (dump[i+1] == ' ')
+						i++;
 					break;
 				case ')':
-					/* force line break after ')' */
-					line[j + 1] = '\0';
-					appendStringInfo(&str, "%s\n", line);
-					j = indentDist - 1;
+					/* force line break after ), unless another ) follows */
+					if (dump[i+1] != ')')
+					{
+						line[j + 1] = '\0';
+						appendStringInfo(&str, "%s\n", line);
+						j = indentDist - 1;
+						while (dump[i+1] == ' ')
+							i++;
+					}
 					break;
 				case '{':
 					/* force line break before { */
diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c
index 402c9991131f9e97a23b9bddf5db2c0207f0b7c2..e90b413591c22f2bec2097dc55397b5d9879f1b5 100644
--- a/src/backend/nodes/read.c
+++ b/src/backend/nodes/read.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.40 2004/05/06 14:01:33 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.41 2004/05/08 21:21:18 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -261,7 +261,8 @@ nodeTokenType(char *token, int length)
  * lexical tokenizer pg_strtok().	It can read
  *	* Value token nodes (integers, floats, or strings);
  *	* General nodes (via parseNodeString() from readfuncs.c);
- *	* Lists of the above.
+ *	* Lists of the above;
+ *	* Lists of integers or OIDs.
  * The return value is declared void *, not Node *, to avoid having to
  * cast it explicitly in callers that assign to fields of different types.
  *
@@ -300,14 +301,68 @@ nodeRead(char *token, int tok_len)
 			{
 				List	   *l = NIL;
 
-				for (;;)
+				/*----------
+				 * Could be an integer list:	(i int int ...)
+				 * or an OID list:				(o int int ...)
+				 * or a list of nodes/values:	(node node ...)
+				 *----------
+				 */
+				token = pg_strtok(&tok_len);
+				if (token == NULL)
+					elog(ERROR, "unterminated List structure");
+				if (tok_len == 1 && token[0] == 'i')
 				{
-					token = pg_strtok(&tok_len);
-					if (token == NULL)
-						elog(ERROR, "unterminated List structure");
-					if (token[0] == ')')
-						break;
-					l = lappend(l, nodeRead(token, tok_len));
+					/* List of integers */
+					for (;;)
+					{
+						int		val;
+						char   *endptr;
+
+						token = pg_strtok(&tok_len);
+						if (token == NULL)
+							elog(ERROR, "unterminated List structure");
+						if (token[0] == ')')
+							break;
+						val = (int) strtol(token, &endptr, 10);
+						if (endptr != token + tok_len)
+							elog(ERROR, "unrecognized integer: \"%.*s\"",
+								 tok_len, token);
+						l = lappendi(l, val);
+					}
+				}
+				else if (tok_len == 1 && token[0] == 'o')
+				{
+					/* List of OIDs */
+					for (;;)
+					{
+						Oid		val;
+						char   *endptr;
+
+						token = pg_strtok(&tok_len);
+						if (token == NULL)
+							elog(ERROR, "unterminated List structure");
+						if (token[0] == ')')
+							break;
+						val = (Oid) strtoul(token, &endptr, 10);
+						if (endptr != token + tok_len)
+							elog(ERROR, "unrecognized OID: \"%.*s\"",
+								 tok_len, token);
+						l = lappendo(l, val);
+					}
+				}
+				else
+				{
+					/* List of other node types */
+					for (;;)
+					{
+						/* We have already scanned next token... */
+						if (token[0] == ')')
+							break;
+						l = lappend(l, nodeRead(token, tok_len));
+						token = pg_strtok(&tok_len);
+						if (token == NULL)
+							elog(ERROR, "unterminated List structure");
+					}
 				}
 				result = (Node *) l;
 				break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 0e3745997002b59affc277a877b48c607dbceab9..ebd3c636c29db03287b068330eb5dd2e0dc890eb 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.167 2004/05/06 14:01:33 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.168 2004/05/08 21:21:18 tgl Exp $
  *
  * NOTES
  *	  Path and Plan nodes do not have any readfuncs support, because we
@@ -101,15 +101,15 @@
 	token = pg_strtok(&length);		/* skip :fldname */ \
 	local_node->fldname = nodeRead(NULL, 0)
 
-/* Read an integer-list field */
+/* Read an integer-list field (XXX combine me with READ_NODE_FIELD) */
 #define READ_INTLIST_FIELD(fldname) \
 	token = pg_strtok(&length);		/* skip :fldname */ \
-	local_node->fldname = toIntList(nodeRead(NULL, 0))
+	local_node->fldname = nodeRead(NULL, 0)
 
-/* Read an OID-list field */
+/* Read an OID-list field (XXX combine me with READ_NODE_FIELD) */
 #define READ_OIDLIST_FIELD(fldname) \
 	token = pg_strtok(&length);		/* skip :fldname */ \
-	local_node->fldname = toOidList(nodeRead(NULL, 0))
+	local_node->fldname = nodeRead(NULL, 0)
 
 /* Routine exit */
 #define READ_DONE() \
@@ -135,56 +135,6 @@
 static Datum readDatum(bool typbyval);
 
 
-/* Convert Value list returned by nodeRead into list of integers */
-static List *
-toIntList(List *list)
-{
-	List	   *l;
-
-	foreach(l, list)
-	{
-		Value	   *v = (Value *) lfirst(l);
-
-		if (!IsA(v, Integer))
-			elog(ERROR, "unexpected node type: %d", (int) nodeTag(v));
-		lfirsti(l) = intVal(v);
-		pfree(v);
-	}
-	return list;
-}
-
-/* Convert Value list returned by nodeRead into list of OIDs */
-static List *
-toOidList(List *list)
-{
-	List	   *l;
-
-	foreach(l, list)
-	{
-		Value	   *v = (Value *) lfirst(l);
-
-		/*
-		 * This is a bit tricky because OID is unsigned, and so nodeRead
-		 * might have concluded the value doesn't fit in an integer. Must
-		 * cope with T_Float as well.
-		 */
-		if (IsA(v, Integer))
-		{
-			lfirsto(l) = (Oid) intVal(v);
-			pfree(v);
-		}
-		else if (IsA(v, Float))
-		{
-			lfirsto(l) = atooid(strVal(v));
-			pfree(strVal(v));
-			pfree(v);
-		}
-		else
-			elog(ERROR, "unexpected node type: %d", (int) nodeTag(v));
-	}
-	return list;
-}
-
 /*
  * _readQuery
  */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 3380178a0dd39ec1a7b6f0b74f97d0bda7277cd4..46a8a2d06f30473cdb0c4d28ec94e440d1655030 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.227 2004/05/02 13:39:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.228 2004/05/08 21:21:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200405020
+#define CATALOG_VERSION_NO	200405081
 
 #endif