diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 6b72c02781f5dbe1c29f34c04712faf125eba2e9..fd95672deecab8d6c2860a0e1df9bca239307a15 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.211 2007/02/02 00:07:03 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.212 2007/02/03 14:06:53 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2834,11 +2834,10 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 			{
 				ExprState 	*e;
 				text	    *data;
-				bool		is_document;
 				bool		preserve_whitespace;
 
-				/* arguments are known to be text, bool, bool */
-				Assert(list_length(xmlExpr->args) == 3);
+				/* arguments are known to be text, bool */
+				Assert(list_length(xmlExpr->args) == 2);
 
 				e = (ExprState *) linitial(xmlExpr->args);
 				value = ExecEvalExpr(e, econtext, &isnull, NULL);
@@ -2848,12 +2847,6 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 
 				e = (ExprState *) lsecond(xmlExpr->args);
 				value = ExecEvalExpr(e, econtext, &isnull, NULL);
-				if (isnull)		/* probably can't happen */
-					return (Datum) 0;
-				is_document = DatumGetBool(value);
-
-				e = (ExprState *) lthird(xmlExpr->args);
-				value = ExecEvalExpr(e, econtext, &isnull, NULL);
 				if (isnull)		/* probably can't happen */
 					return (Datum) 0;
 				preserve_whitespace = DatumGetBool(value);
@@ -2861,7 +2854,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 				*isNull = false;
 
 				return PointerGetDatum(xmlparse(data,
-												is_document,
+												xexpr->xmloption,
 												preserve_whitespace));
 			}
 			break;
@@ -2900,7 +2893,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 				text		*version;
 				int			standalone;
 
-				/* arguments are known to be xml, text, bool */
+				/* arguments are known to be xml, text, int */
 				Assert(list_length(xmlExpr->args) == 3);
 
 				e = (ExprState *) linitial(xmlExpr->args);
@@ -2928,6 +2921,24 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 			}
 			break;
 
+		case IS_XMLSERIALIZE:
+			{
+				ExprState	*e;
+
+				/* argument type is known to be xml */
+				Assert(list_length(xmlExpr->args) == 1);
+
+				e = (ExprState *) linitial(xmlExpr->args);
+				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				if (isnull)
+					return (Datum) 0;
+
+				*isNull = false;
+
+				return PointerGetDatum(xmltotext_with_xmloption(DatumGetXmlP(value), xexpr->xmloption));
+			}
+			break;
+
 		case IS_DOCUMENT:
 			{
 				ExprState 	*e;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f213f216de461cbe0f7a3ec8cccc10b4bbb63e29..2d38d7fd60c0160a97a399c6fd7c5ae12f78d777 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.364 2007/01/23 05:07:17 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.365 2007/02/03 14:06:54 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1116,6 +1116,9 @@ _copyXmlExpr(XmlExpr *from)
 	COPY_NODE_FIELD(named_args);
 	COPY_NODE_FIELD(arg_names);
 	COPY_NODE_FIELD(args);
+	COPY_SCALAR_FIELD(xmloption);
+	COPY_SCALAR_FIELD(type);
+	COPY_SCALAR_FIELD(typmod);
 
 	return newnode;
 }
@@ -1723,6 +1726,18 @@ _copyLockingClause(LockingClause *from)
 	return newnode;
 }
 
+static XmlSerialize *
+_copyXmlSerialize(XmlSerialize *from)
+{
+	XmlSerialize *newnode = makeNode(XmlSerialize);
+
+	COPY_SCALAR_FIELD(xmloption);
+	COPY_NODE_FIELD(expr);
+	COPY_NODE_FIELD(typename);
+
+	return newnode;
+}
+
 static Query *
 _copyQuery(Query *from)
 {
@@ -3430,6 +3445,9 @@ copyObject(void *from)
 		case T_FuncWithArgs:
 			retval = _copyFuncWithArgs(from);
 			break;
+		case T_XmlSerialize:
+			retval = _copyXmlSerialize(from);
+			break;
 
 		default:
 			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 31754a7bc023f47e6e5bbefd67da0849ef041cf9..c17a40bbbb246013f89a3c66be2771a1404667d4 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.297 2007/01/23 05:07:17 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.298 2007/02/03 14:06:54 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -462,6 +462,9 @@ _equalXmlExpr(XmlExpr *a, XmlExpr *b)
 	COMPARE_NODE_FIELD(named_args);
 	COMPARE_NODE_FIELD(arg_names);
 	COMPARE_NODE_FIELD(args);
+	COMPARE_SCALAR_FIELD(xmloption);
+	COMPARE_SCALAR_FIELD(type);
+	COMPARE_SCALAR_FIELD(typmod);
 
 	return true;
 }
@@ -1830,6 +1833,15 @@ _equalFkConstraint(FkConstraint *a, FkConstraint *b)
 	return true;
 }
 
+static bool
+_equalXmlSerialize(XmlSerialize *a, XmlSerialize *b)
+{
+	COMPARE_SCALAR_FIELD(xmloption);
+	COMPARE_NODE_FIELD(expr);
+	COMPARE_NODE_FIELD(typename);
+
+	return true;
+}
 
 /*
  * Stuff from pg_list.h
@@ -2411,6 +2423,9 @@ equal(void *a, void *b)
 		case T_FuncWithArgs:
 			retval = _equalFuncWithArgs(a, b);
 			break;
+		case T_XmlSerialize:
+			retval = _equalXmlSerialize(a, b);
+			break;
 
 		default:
 			elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index b79b7d1a2d8f8a12017cfc17c428f50fe6d6c212..939c21f45a45d9da8fdd14c7ad5e207036f560d3 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.295 2007/01/22 20:00:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.296 2007/02/03 14:06:54 petere Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -933,6 +933,9 @@ _outXmlExpr(StringInfo str, XmlExpr *node)
 	WRITE_NODE_FIELD(named_args);
 	WRITE_NODE_FIELD(arg_names);
 	WRITE_NODE_FIELD(args);
+	WRITE_ENUM_FIELD(xmloption, XmlOptionType);
+	WRITE_OID_FIELD(type);
+	WRITE_INT_FIELD(typmod);
 }
 
 static void
@@ -1521,6 +1524,16 @@ _outLockingClause(StringInfo str, LockingClause *node)
 	WRITE_BOOL_FIELD(noWait);
 }
 
+static void
+_outXmlSerialize(StringInfo str, XmlSerialize *node)
+{
+	WRITE_NODE_TYPE("XMLSERIALIZE");
+
+	WRITE_ENUM_FIELD(xmloption, XmlOptionType);
+	WRITE_NODE_FIELD(expr);
+	WRITE_NODE_FIELD(typename);
+}
+
 static void
 _outColumnDef(StringInfo str, ColumnDef *node)
 {
@@ -2290,6 +2303,9 @@ _outNode(StringInfo str, void *obj)
 			case T_LockingClause:
 				_outLockingClause(str, obj);
 				break;
+			case T_XmlSerialize:
+				_outXmlSerialize(str, obj);
+				break;
 
 			default:
 
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index b90c8dd7130d0e9d6e1763e733c88da4c0244ce3..17d36b4efe6db40a92b054b9bf9a6ad988755fe2 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.201 2007/01/09 02:14:12 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.202 2007/02/03 14:06:54 petere Exp $
  *
  * NOTES
  *	  Path and Plan nodes do not have any readfuncs support, because we
@@ -723,6 +723,9 @@ _readXmlExpr(void)
 	READ_NODE_FIELD(named_args);
 	READ_NODE_FIELD(arg_names);
 	READ_NODE_FIELD(args);
+	READ_ENUM_FIELD(xmloption, XmlOptionType);
+	READ_OID_FIELD(type);
+	READ_INT_FIELD(typmod);
 
 	READ_DONE();
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1f1dfdb761d5e239484a10d71b9c069e7f0083e1..cf25c5607a64e439e3d9c427f0318fb324856676 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.578 2007/02/01 19:10:27 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.579 2007/02/03 14:06:54 petere Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -350,7 +350,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
 %type <target>	xml_attribute_el
 %type <list>	xml_attribute_list xml_attributes
 %type <node>	xml_root_version opt_xml_root_standalone
-%type <boolean>	document_or_content xml_whitespace_option
+%type <ival>	document_or_content
+%type <boolean> xml_whitespace_option
 
 
 /*
@@ -1117,7 +1118,7 @@ set_rest:  var_name TO var_list_or_default
 				{
 					VariableSetStmt *n = makeNode(VariableSetStmt);
 					n->name = "xmloption";
-					n->args = list_make1(makeStringConst($3 ? "DOCUMENT" : "CONTENT", NULL));
+					n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", NULL));
 					$$ = n;
 				}
 		;
@@ -7903,10 +7904,11 @@ func_expr:	func_name '(' ')'
 				}
 			| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
 				{
-					$$ = makeXmlExpr(IS_XMLPARSE, NULL, NIL,
-									 list_make3($4,
-												makeBoolAConst($3),
-												makeBoolAConst($5)));
+					XmlExpr *x = (XmlExpr *) makeXmlExpr(IS_XMLPARSE, NULL, NIL,
+														 list_make2($4,
+																	makeBoolAConst($5)));
+					x->xmloption = $3;
+					$$ = (Node *)x;
 				}
 			| XMLPI '(' NAME_P ColLabel ')'
 				{
@@ -7921,14 +7923,13 @@ func_expr:	func_name '(' ')'
 					$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
 									 list_make3($3, $5, $6));
 				}
-			| XMLSERIALIZE '(' document_or_content a_expr AS Typename ')'
+			| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
 				{
-					/*
-					 * FIXME: This should be made distinguishable from
-					 * CAST (for reverse compilation at least).  Also,
-					 * what about the document/content option??
-					 */
-					$$ = makeTypeCast($4, $6);
+					XmlSerialize *n = makeNode(XmlSerialize);
+					n->xmloption = $3;
+					n->expr = $4;
+					n->typename = $6;
+					$$ = (Node *)n;
 				}
 		;
 
@@ -7980,17 +7981,13 @@ xml_attribute_el: a_expr AS ColLabel
 				}
 		;
 
-document_or_content: DOCUMENT_P						{ $$ = TRUE; }
-			| CONTENT_P								{ $$ = FALSE; }
+document_or_content: DOCUMENT_P						{ $$ = XMLOPTION_DOCUMENT; }
+			| CONTENT_P								{ $$ = XMLOPTION_CONTENT; }
 		;
 
-/*
- * XXX per SQL spec, the default should be STRIP WHITESPACE, but since we
- * haven't implemented that yet, temporarily default to PRESERVE.
- */
 xml_whitespace_option: PRESERVE WHITESPACE_P		{ $$ = TRUE; }
 			| STRIP_P WHITESPACE_P					{ $$ = FALSE; }
-			| /*EMPTY*/								{ $$ = TRUE; }
+			| /*EMPTY*/								{ $$ = FALSE; }
 		;
 
 /*
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index a807ef12de4d36fb29c64c2c01d0de133470a207..e7a37a2cfa62d906fd9bc2d7ee927c4fc755a416 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.209 2007/01/25 11:53:51 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.210 2007/02/03 14:06:54 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,6 +57,7 @@ static Node *transformRowExpr(ParseState *pstate, RowExpr *r);
 static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
 static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
 static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
+static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
 static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
 static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
 static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
@@ -224,6 +225,10 @@ transformExpr(ParseState *pstate, Node *expr)
 			result = transformXmlExpr(pstate, (XmlExpr *) expr);
 			break;
 
+		case T_XmlSerialize:
+			result = transformXmlSerialize(pstate, (XmlSerialize *) expr);
+			break;
+
 		case T_NullTest:
 			{
 				NullTest   *n = (NullTest *) expr;
@@ -1424,6 +1429,8 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 		newx->arg_names = lappend(newx->arg_names, makeString(argname));
 	}
 
+	newx->xmloption = x->xmloption;
+
 	if (x->op == IS_XMLELEMENT)
 	{
 		foreach(lc, newx->arg_names)
@@ -1484,6 +1491,9 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 					newe = coerce_to_specific_type(pstate, newe, INT4OID,
 												   "XMLROOT");
 				break;
+			case IS_XMLSERIALIZE:
+				/* not handled here */
+				break;
 			case IS_DOCUMENT:
 				newe = coerce_to_specific_type(pstate, newe, XMLOID,
 											   "IS DOCUMENT");
@@ -1496,6 +1506,38 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 	return (Node *) newx;
 }
 
+static Node *
+transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
+{
+	Oid			targetType;
+	int32		targetTypmod;
+	XmlExpr	   *xexpr;
+
+	xexpr = makeNode(XmlExpr);
+	xexpr->op = IS_XMLSERIALIZE;
+	xexpr->args = list_make1(coerce_to_specific_type(pstate,
+													 transformExpr(pstate, xs->expr),
+													 XMLOID,
+													 "XMLSERIALIZE"));
+
+	targetType = typenameTypeId(pstate, xs->typename);
+	targetTypmod = typenameTypeMod(pstate, xs->typename, targetType);
+
+	xexpr->xmloption = xs->xmloption;
+	/* We actually only need these to be able to parse back the expression. */
+	xexpr->type = targetType;
+	xexpr->typmod = targetTypmod;
+
+	/*
+	 * The actual target type is determined this way.  SQL allows char
+	 * and varchar as target types.  We allow anything that can be
+	 * cast implicitly from text.  This way, user-defined text-like
+	 * data types automatically fit in.
+	 */
+	return (Node *) coerce_to_target_type(pstate, (Node *) xexpr, TEXTOID, targetType, targetTypmod,
+										  COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+}
+
 static Node *
 transformBooleanTest(ParseState *pstate, BooleanTest *b)
 {
@@ -1789,6 +1831,8 @@ exprType(Node *expr)
 		case T_XmlExpr:
 			if (((XmlExpr *) expr)->op == IS_DOCUMENT)
 				type = BOOLOID;
+			else if (((XmlExpr *) expr)->op == IS_XMLSERIALIZE)
+				type = TEXTOID;
 			else
 				type = XMLOID;
 			break;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index dea29d1d8aa4995c859037ddfbee8491851ccfb1..cc4bc091d249e7272e9f67da6c4ef4e67178829f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.153 2007/01/14 13:11:54 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.154 2007/02/03 14:06:54 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1337,11 +1337,17 @@ FigureColnameInternal(Node *node, char **name)
 				case IS_XMLROOT:
 					*name = "xmlroot";
 					return 2;
+				case IS_XMLSERIALIZE:
+					*name = "xmlserialize";
+					return 2;
 				case IS_DOCUMENT:
 					/* nothing */
 					break;
 			} 
 			break;
+		case T_XmlSerialize:
+			*name = "xmlserialize";
+			return 2;
 		default:
 			break;
 	}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 668266d1c4de29b91b5e1aea52cdd2d235e2843e..3cd317361f44801d5e0ff89ef28717a7a655201e 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.247 2007/01/30 02:39:27 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.248 2007/02/03 14:06:54 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3856,9 +3856,19 @@ get_rule_expr(Node *node, deparse_context *context,
 					case IS_XMLROOT:
 						appendStringInfoString(buf, "XMLROOT(");
 						break;
+					case IS_XMLSERIALIZE:
+						appendStringInfoString(buf, "XMLSERIALIZE(");
+						break;
 					case IS_DOCUMENT:
 						break;
 				}
+				if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
+				{
+					if (xexpr->xmloption == XMLOPTION_DOCUMENT)
+						appendStringInfoString(buf, "DOCUMENT ");
+					else
+						appendStringInfoString(buf, "CONTENT ");
+				}
 				if (xexpr->name)
 				{
 					appendStringInfo(buf, "NAME %s",
@@ -3899,24 +3909,17 @@ get_rule_expr(Node *node, deparse_context *context,
 						case IS_XMLELEMENT:
 						case IS_XMLFOREST:
 						case IS_XMLPI:
+						case IS_XMLSERIALIZE:
 							/* no extra decoration needed */
 							get_rule_expr((Node *) xexpr->args, context, true);
 							break;
 						case IS_XMLPARSE:
-							Assert(list_length(xexpr->args) == 3);
-
-							con = (Const *) lsecond(xexpr->args);
-							Assert(IsA(con, Const));
-							Assert(!con->constisnull);
-							if (DatumGetBool(con->constvalue))
-								appendStringInfoString(buf, "DOCUMENT ");
-							else
-								appendStringInfoString(buf, "CONTENT ");
+							Assert(list_length(xexpr->args) == 2);
 
 							get_rule_expr((Node *) linitial(xexpr->args),
 										  context, true);
 
-							con = (Const *) lthird(xexpr->args);
+							con = (Const *) lsecond(xexpr->args);
 							Assert(IsA(con, Const));
 							Assert(!con->constisnull);
 							if (DatumGetBool(con->constvalue))
@@ -3944,12 +3947,26 @@ get_rule_expr(Node *node, deparse_context *context,
 							Assert(IsA(con, Const));
 							if (con->constisnull)
 								/* suppress STANDALONE NO VALUE */ ;
-							else if (DatumGetBool(con->constvalue))
-								appendStringInfoString(buf,
-													   ", STANDALONE YES");
 							else
-								appendStringInfoString(buf,
-													   ", STANDALONE NO");
+							{
+								switch (DatumGetInt32(con->constvalue))
+								{
+									case XML_STANDALONE_YES:
+										appendStringInfoString(buf,
+															   ", STANDALONE YES");
+										break;
+									case XML_STANDALONE_NO:
+										appendStringInfoString(buf,
+															   ", STANDALONE NO");
+										break;
+									case XML_STANDALONE_NO_VALUE:
+										appendStringInfoString(buf,
+															   ", STANDALONE NO VALUE");
+										break;
+									default:
+										break;
+								}
+							}
 							break;
 						case IS_DOCUMENT:
 							get_rule_expr_paren((Node *) xexpr->args, context, false, node);
@@ -3957,6 +3974,9 @@ get_rule_expr(Node *node, deparse_context *context,
 					}
 
 				}
+				if (xexpr->op == IS_XMLSERIALIZE)
+					appendStringInfo(buf, " AS %s", format_type_with_typemod(xexpr->type,
+																			 xexpr->typmod));
 				if (xexpr->op == IS_DOCUMENT)
 					appendStringInfoString(buf, " IS DOCUMENT");
 				else
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 7d963148d0e11dfa6afe267d29c26dae2ce79c7b..70e566327da1278c328078d9fe5933da4ddb6ca8 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.24 2007/01/27 14:50:51 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.25 2007/02/03 14:06:55 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -80,7 +80,7 @@ static void 	xml_ereport_by_code(int level, int sqlcode,
 static xmlChar *xml_text2xmlChar(text *in);
 static int		parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone);
 static bool		print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone);
-static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encoding);
+static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding);
 
 #endif /* USE_LIBXML */
 
@@ -112,7 +112,7 @@ xml_in(PG_FUNCTION_ARGS)
 	 * Parse the data to check if it is well-formed XML data.  Assume
 	 * that ERROR occurred if parsing failed.
 	 */
-	doc = xml_parse(vardata, (xmloption == XMLOPTION_DOCUMENT), true, NULL);
+	doc = xml_parse(vardata, xmloption, true, NULL);
 	xmlFreeDoc(doc);
 
 	PG_RETURN_XML_P(vardata);
@@ -211,7 +211,7 @@ xml_recv(PG_FUNCTION_ARGS)
 	 * Parse the data to check if it is well-formed XML data.  Assume
 	 * that ERROR occurred if parsing failed.
 	 */
-	doc = xml_parse(result, (xmloption == XMLOPTION_DOCUMENT), true, encoding);
+	doc = xml_parse(result, xmloption, true, encoding);
 	xmlFreeDoc(doc);
 
 	newstr = (char *) pg_do_encoding_conversion((unsigned char *) str,
@@ -435,7 +435,29 @@ texttoxml(PG_FUNCTION_ARGS)
 {
 	text	   *data = PG_GETARG_TEXT_P(0);
 
-	PG_RETURN_XML_P(xmlparse(data, (xmloption == XMLOPTION_DOCUMENT), true));
+	PG_RETURN_XML_P(xmlparse(data, xmloption, true));
+}
+
+
+Datum
+xmltotext(PG_FUNCTION_ARGS)
+{
+	xmltype	   *data = PG_GETARG_XML_P(0);
+
+	PG_RETURN_TEXT_P(xmltotext_with_xmloption(data, xmloption));
+}
+
+
+text *
+xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg)
+{
+	if (xmloption_arg == XMLOPTION_DOCUMENT && !xml_is_document(data))
+		ereport(ERROR,
+				(errcode(ERRCODE_NOT_AN_XML_DOCUMENT),
+				 errmsg("not an XML document")));
+
+	/* It's actually binary compatible, save for the above check. */
+	return (text *) data;
 }
 
 
@@ -499,12 +521,12 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
 
 
 xmltype *
-xmlparse(text *data, bool is_document, bool preserve_whitespace)
+xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace)
 {
 #ifdef USE_LIBXML
 	xmlDocPtr	doc;
 
-	doc = xml_parse(data, is_document, preserve_whitespace, NULL);
+	doc = xml_parse(data, xmloption_arg, preserve_whitespace, NULL);
 	xmlFreeDoc(doc);
 
 	return (xmltype *) data;
@@ -723,7 +745,7 @@ xml_is_document(xmltype *arg)
 
 	PG_TRY();
 	{
-		doc = xml_parse((text *) arg, true, true, NULL);
+		doc = xml_parse((text *) arg, XMLOPTION_DOCUMENT, true, NULL);
 		result = true;
 	}
 	PG_CATCH();
@@ -996,7 +1018,7 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan
  * TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
  */
 static xmlDocPtr
-xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encoding)
+xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding)
 {
 	int32				len;
 	xmlChar				*string;
@@ -1024,7 +1046,7 @@ xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encod
 			xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
 						"could not allocate parser context");
 
-		if (is_document)
+		if (xmloption_arg == XMLOPTION_DOCUMENT)
 		{
 			/*
 			 * Note, that here we try to apply DTD defaults
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 8157a3f6a597246c7071e2acea802fbe94f8edaf..2f1bb8ae1a46e36f7e94b944dca9ba38894cdda5 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.378 2007/01/31 19:33:54 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.379 2007/02/03 14:06:55 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200701311
+#define CATALOG_VERSION_NO	200702031
 
 #endif
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 4fbf237dad220dffa22e83533ae8bcf20aa372c9..0047f865af2328e07f19c27f21a3dbab2a2f75c1 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -10,7 +10,7 @@
  *
  * Copyright (c) 2002-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.30 2007/01/31 19:33:54 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.31 2007/02/03 14:06:55 petere Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -300,7 +300,7 @@ DATA(insert ( 1266	 25  939 i ));
 DATA(insert (	25 1266  938 e ));
 DATA(insert ( 1700	 25 1688 i ));
 DATA(insert (	25 1700 1686 e ));
-DATA(insert (  142   25    0 e ));
+DATA(insert (  142   25 2922 e ));
 DATA(insert (   25  142	2896 e ));
 
 /*
@@ -340,7 +340,7 @@ DATA(insert ( 1266 1043  939 a ));
 DATA(insert ( 1043 1266  938 e ));
 DATA(insert ( 1700 1043 1688 a ));
 DATA(insert ( 1043 1700 1686 e ));
-DATA(insert (  142 1043    0 e ));
+DATA(insert (  142 1043 2922 e ));
 DATA(insert ( 1043  142 2896 e ));
 
 /*
@@ -381,7 +381,7 @@ DATA(insert ( 1266 1042  939 a ));
 DATA(insert ( 1042 1266  938 e ));
 DATA(insert ( 1700 1042 1688 a ));
 DATA(insert ( 1042 1700 1686 e ));
-DATA(insert (  142 1042    0 e ));
+DATA(insert (  142 1042 2922 e ));
 
 /*
  * Length-coercion functions
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index eaee34109626fed34d5486437c45f9c545e90e97..500d23954220cd0e4f3778a4bb97afb4570c0a19 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.441 2007/01/28 16:16:52 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.442 2007/02/03 14:06:55 petere Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -4045,6 +4045,8 @@ DATA(insert OID = 2900 (  xmlconcat2       PGNSP PGUID 12 1 0 f f f f i 2 142 "1
 DESCR("aggregate transition function");
 DATA(insert OID = 2901 (  xmlagg           PGNSP PGUID 12 1 0 t f f f i 1 142 "142" _null_ _null_ _null_ aggregate_dummy - _null_ ));
 DESCR("concatenate XML values");
+DATA(insert OID = 2922 (  text             PGNSP PGUID 12 1 0 f f t f s 1 25 "142" _null_ _null_ _null_ xmltotext - _null_ ));
+DESCR("serialize an XML value to a character string");
 
 /* uuid */ 
 DATA(insert OID = 2952 (  uuid_in		   PGNSP PGUID 12 1 0 f f t f i 1 2950 "2275" _null_ _null_ _null_ uuid_in - _null_ ));
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index f3762facdd629ad7d4dda2b1f0a7dad98a360b0a..2452f792940788985bb36782abc2ab9d9bfbb7e4 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.193 2007/01/23 05:07:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.194 2007/02/03 14:06:55 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -331,6 +331,7 @@ typedef enum NodeTag
 	T_FunctionParameter,
 	T_LockingClause,
 	T_RowMarkClause,
+	T_XmlSerialize,
 
 	/*
 	 * TAGS FOR RANDOM OTHER STUFF
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a252308bdb26b4966924c78d6d340b3556e2c2f2..0db72763021e2e23f5806bfcdc1d6b9ee2f0f7df 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.339 2007/01/23 05:07:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.340 2007/02/03 14:06:55 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -485,6 +485,17 @@ typedef struct LockingClause
 	bool		noWait;			/* NOWAIT option */
 } LockingClause;
 
+/*
+ * XMLSERIALIZE
+ */
+typedef struct XmlSerialize
+{
+	NodeTag		type;
+	XmlOptionType xmloption;
+	Node	   *expr;
+	TypeName   *typename;
+} XmlSerialize;
+
 
 /****************************************************************************
  *	Nodes for a Query tree
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index cea0cd2f6a5c24ac83e036133821019c2141e87f..298ac0d95d6f7920b3312bdd7e3e8151227f3bd1 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.123 2007/01/14 13:11:54 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.124 2007/02/03 14:06:56 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -726,9 +726,16 @@ typedef enum XmlExprOp
 	IS_XMLPARSE,				/* XMLPARSE(text, is_doc, preserve_ws) */
 	IS_XMLPI,					/* XMLPI(name [, args]) */
 	IS_XMLROOT,					/* XMLROOT(xml, version, standalone) */
+	IS_XMLSERIALIZE,			/* XMLSERIALIZE(is_document, xmlval) */
 	IS_DOCUMENT					/* xmlval IS DOCUMENT */
 } XmlExprOp;
 
+typedef enum
+{
+	XMLOPTION_DOCUMENT,
+	XMLOPTION_CONTENT
+} XmlOptionType;
+
 typedef struct XmlExpr
 {
 	Expr		xpr;
@@ -737,6 +744,9 @@ typedef struct XmlExpr
 	List	   *named_args;		/* non-XML expressions for xml_attributes */
 	List	   *arg_names;		/* parallel list of Value strings */
 	List	   *args;			/* list of expressions */
+	XmlOptionType xmloption;	/* DOCUMENT or CONTENT */
+	Oid			type;			/* target type for XMLSERIALIZE */
+	int32		typmod;
 } XmlExpr;
 
 /*
diff --git a/src/include/utils/errcodes.h b/src/include/utils/errcodes.h
index 0e4d83a80237509d5d37edcdd76cc8a375641c36..010918ab41f2491922debe5b2845881692b7e8e5 100644
--- a/src/include/utils/errcodes.h
+++ b/src/include/utils/errcodes.h
@@ -11,7 +11,7 @@
  *
  * Copyright (c) 2003-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.22 2007/01/05 22:19:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.23 2007/02/03 14:06:56 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -148,6 +148,7 @@
 #define ERRCODE_INVALID_BINARY_REPRESENTATION	MAKE_SQLSTATE('2','2', 'P','0','3')
 #define ERRCODE_BAD_COPY_FILE_FORMAT		MAKE_SQLSTATE('2','2', 'P','0','4')
 #define ERRCODE_UNTRANSLATABLE_CHARACTER	MAKE_SQLSTATE('2','2', 'P','0','5')
+#define ERRCODE_NOT_AN_XML_DOCUMENT			MAKE_SQLSTATE('2', '2', '0', '0', 'L')
 #define ERRCODE_INVALID_XML_DOCUMENT			MAKE_SQLSTATE('2', '2', '0', '0', 'M')
 #define ERRCODE_INVALID_XML_CONTENT			MAKE_SQLSTATE('2', '2', '0', '0', 'N')
 #define ERRCODE_INVALID_XML_COMMENT			MAKE_SQLSTATE('2', '2', '0', '0', 'S')
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index f5b33512cfdfc0f1b720099a71050e5d4880509b..f207917ea85a1bf1dd088314af4b12e70607464e 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.13 2007/01/25 11:53:51 petere Exp $
+ * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.14 2007/02/03 14:06:56 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,10 +17,12 @@
 
 #include "fmgr.h"
 #include "nodes/execnodes.h"
+#include "nodes/primnodes.h"
 
 typedef struct varlena xmltype;
 
 #define DatumGetXmlP(X)		((xmltype *) PG_DETOAST_DATUM(X))
+#define XmlPGetDatum(X)		PointerGetDatum(X)
 
 #define PG_GETARG_XML_P(n)	DatumGetXmlP(PG_GETARG_DATUM(n))
 #define PG_RETURN_XML_P(x)	PG_RETURN_POINTER(x)
@@ -32,6 +34,7 @@ extern Datum xml_send(PG_FUNCTION_ARGS);
 extern Datum xmlcomment(PG_FUNCTION_ARGS);
 extern Datum xmlconcat2(PG_FUNCTION_ARGS);
 extern Datum texttoxml(PG_FUNCTION_ARGS);
+extern Datum xmltotext(PG_FUNCTION_ARGS);
 extern Datum xmlvalidate(PG_FUNCTION_ARGS);
 
 typedef enum
@@ -44,10 +47,11 @@ typedef enum
 
 extern xmltype *xmlconcat(List *args);
 extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
-extern xmltype *xmlparse(text *data, bool is_doc, bool preserve_whitespace);
+extern xmltype *xmlparse(text *data, XmlOptionType xmloption, bool preserve_whitespace);
 extern xmltype *xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null);
 extern xmltype *xmlroot(xmltype *data, text *version, int standalone);
 extern bool xml_is_document(xmltype *arg);
+extern text *xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg);
 
 extern char *map_sql_identifier_to_xml_name(char *ident, bool fully_escaped);
 extern char *map_xml_name_to_sql_identifier(char *name);
@@ -61,12 +65,6 @@ typedef enum
 
 extern XmlBinaryType xmlbinary;
 
-typedef enum
-{
-	XMLOPTION_DOCUMENT,
-	XMLOPTION_CONTENT
-} XmlOptionType;
-
 extern XmlOptionType xmloption;
 
 #endif /* XML_H */
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 33bebcfa66aa008ee80ed1a55ed17e0e863cdfd2..fcbfe3cad510ac9a612c53be1531e90c42ca9ecd 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -288,8 +288,6 @@ WHERE c.castfunc = p.oid AND
 -- those are binary-compatible while the reverse way goes through rtrim().
 -- As of 8.2, this finds the cast from cidr to inet, because that is a
 -- trivial binary coercion while the other way goes through inet_to_cidr().
--- As of 8.3, this finds casts from xml to text, varchar, and bpchar,
--- because the other direction has to go through xmlparse().
 SELECT *
 FROM pg_cast c
 WHERE c.castfunc = 0 AND
@@ -302,10 +300,7 @@ WHERE c.castfunc = 0 AND
          25 |       1042 |        0 | i
        1043 |       1042 |        0 | i
         650 |        869 |        0 | i
-        142 |         25 |        0 | e
-        142 |       1043 |        0 | e
-        142 |       1042 |        0 | e
-(6 rows)
+(3 rows)
 
 -- **************** pg_operator ****************
 -- Look for illegal values in pg_operator fields.
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 0c08667706884fc334e90276c307b40fc9ca2ad6..6d79a4166e7cd95c5c92be30bf13c2896614ede4 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -275,13 +275,21 @@ SELECT xmlroot (
  <?xml version="1.0" standalone="yes"?><gazonk name="val" num="2"><qux>foo</qux></gazonk>
 (1 row)
 
-SELECT xmlserialize(content data as character varying) FROM xmltest;
-        data        
+SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
+    xmlserialize    
 --------------------
  <value>one</value>
  <value>two</value>
 (2 rows)
 
+SELECT xmlserialize(content 'good' as char(10));
+ xmlserialize 
+--------------
+ good      
+(1 row)
+
+SELECT xmlserialize(document 'bad' as text);
+ERROR:  not an XML document
 SELECT xml '<foo>bar</foo>' IS DOCUMENT;
  ?column? 
 ----------
@@ -368,3 +376,27 @@ EXECUTE foo ('good');
  <foo/>good
 (1 row)
 
+-- Test backwards parsing
+CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
+CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
+CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
+CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
+CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
+CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
+CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
+CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
+CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
+SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%';
+ table_name |                                                        view_definition                                                         
+------------+--------------------------------------------------------------------------------------------------------------------------------
+ xmlview1   | SELECT xmlcomment('test'::text) AS xmlcomment;
+ xmlview2   | SELECT XMLCONCAT('hello'::"xml", 'you'::"xml") AS "xmlconcat";
+ xmlview3   | SELECT XMLELEMENT(NAME element, XMLATTRIBUTES(1 AS ":one:", 'deuce' AS two), 'content&') AS "xmlelement";
+ xmlview4   | SELECT XMLELEMENT(NAME employee, XMLFOREST(emp."name" AS "name", emp.age AS age, emp.salary AS pay)) AS "xmlelement" FROM emp;
+ xmlview5   | SELECT XMLPARSE(CONTENT '<abc>x</abc>'::text STRIP WHITESPACE) AS "xmlparse";
+ xmlview6   | SELECT XMLPI(NAME foo, 'bar'::text) AS "xmlpi";
+ xmlview7   | SELECT XMLROOT('<foo/>'::"xml", VERSION NO VALUE, STANDALONE YES) AS "xmlroot";
+ xmlview8   | SELECT (XMLSERIALIZE(CONTENT 'good'::"xml" AS character(10)))::character(10) AS "xmlserialize";
+ xmlview9   | SELECT XMLSERIALIZE(CONTENT 'good'::"xml" AS text) AS "xmlserialize";
+(9 rows)
+
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 89124ebb98e2874c738b2d2108e9f74896e33799..899ed4cd266c3fe5f9d15bc548751d2d435b88e2 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -122,11 +122,15 @@ SELECT xmlroot (
   standalone yes
 );
 ERROR:  no XML support in this installation
-SELECT xmlserialize(content data as character varying) FROM xmltest;
- data 
-------
+SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
+ xmlserialize 
+--------------
 (0 rows)
 
+SELECT xmlserialize(content 'good' as char(10));
+ERROR:  no XML support in this installation
+SELECT xmlserialize(document 'bad' as text);
+ERROR:  no XML support in this installation
 SELECT xml '<foo>bar</foo>' IS DOCUMENT;
 ERROR:  no XML support in this installation
 SELECT xml '<foo>bar</foo><bar>foo</bar>' IS DOCUMENT;
@@ -168,3 +172,27 @@ EXECUTE foo ('<bar/>');
 ERROR:  prepared statement "foo" does not exist
 EXECUTE foo ('good');
 ERROR:  prepared statement "foo" does not exist
+-- Test backwards parsing
+CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
+CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
+ERROR:  no XML support in this installation
+CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
+ERROR:  no XML support in this installation
+CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
+ERROR:  no XML support in this installation
+CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
+CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
+ERROR:  no XML support in this installation
+CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
+ERROR:  no XML support in this installation
+CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
+ERROR:  no XML support in this installation
+CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
+ERROR:  no XML support in this installation
+SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%';
+ table_name |                                view_definition                                
+------------+-------------------------------------------------------------------------------
+ xmlview1   | SELECT xmlcomment('test'::text) AS xmlcomment;
+ xmlview5   | SELECT XMLPARSE(CONTENT '<abc>x</abc>'::text STRIP WHITESPACE) AS "xmlparse";
+(2 rows)
+
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 7eff2195dfb5f36343d8cc5a4e17369667e3bccb..cbf9baf6728c17d17b8c5f0374a29c764eb5fae2 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -238,9 +238,6 @@ WHERE c.castfunc = p.oid AND
 -- As of 8.2, this finds the cast from cidr to inet, because that is a
 -- trivial binary coercion while the other way goes through inet_to_cidr().
 
--- As of 8.3, this finds casts from xml to text, varchar, and bpchar,
--- because the other direction has to go through xmlparse().
-
 SELECT *
 FROM pg_cast c
 WHERE c.castfunc = 0 AND
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index b3117c2424f2f073451a6b0b9b3a72637b04c06f..2f919fb42a015c69b5d6bf61d136ec958297cd69 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -68,6 +68,7 @@ SELECT xmlpi(name foo, null);
 SELECT xmlpi(name xmlstuff, null);
 SELECT xmlpi(name foo, '   bar');
 
+
 SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
 SELECT xmlroot(xml '<foo/>', version '2.0');
 SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
@@ -95,7 +96,9 @@ SELECT xmlroot (
 );
 
 
-SELECT xmlserialize(content data as character varying) FROM xmltest;
+SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
+SELECT xmlserialize(content 'good' as char(10));
+SELECT xmlserialize(document 'bad' as text);
 
 
 SELECT xml '<foo>bar</foo>' IS DOCUMENT;
@@ -125,3 +128,18 @@ EXECUTE foo ('bad');
 SET XML OPTION CONTENT;
 EXECUTE foo ('<bar/>');
 EXECUTE foo ('good');
+
+
+-- Test backwards parsing
+
+CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
+CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
+CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
+CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
+CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
+CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
+CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
+CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
+CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
+
+SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%';