diff --git a/doc/src/sgml/errcodes.sgml b/doc/src/sgml/errcodes.sgml
index bf06cfaf5e5874d6f821c54acff1e8f51d0ae1d6..ced6197d978527fefb601f3cb9f6e0bedcd60eea 100644
--- a/doc/src/sgml/errcodes.sgml
+++ b/doc/src/sgml/errcodes.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/errcodes.sgml,v 1.20 2006/06/16 23:29:26 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/errcodes.sgml,v 1.21 2006/12/24 00:29:17 tgl Exp $ -->
 
 <appendix id="errcodes-appendix">
  <title><productname>PostgreSQL</productname> Error Codes</title>
@@ -541,6 +541,29 @@
 <entry>untranslatable_character</entry>
 </row>
 
+<row>
+<entry><literal>2200M</literal></entry>
+<entry>INVALID XML DOCUMENT</entry>
+<entry>invalid_xml_document</entry>
+</row>
+
+<row>
+<entry><literal>2200N</literal></entry>
+<entry>INVALID XML CONTENT</entry>
+<entry>invalid_xml_content</entry>
+</row>
+
+<row>
+<entry><literal>2200S</literal></entry>
+<entry>INVALID XML COMMENT</entry>
+<entry>invalid_xml_comment</entry>
+</row>
+
+<row>
+<entry><literal>2200T</literal></entry>
+<entry>INVALID XML PROCESSING INSTRUCTION</entry>
+<entry>invalid_xml_processing_instruction</entry>
+</row>
 
 <row>
 <entry spanname="span13"><emphasis role="bold">Class 23 &mdash; Integrity Constraint Violation</></entry>
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index a56ba9ad9b8461c2fe02f34e61b2d8e86fc536dc..3119671fc4be7f443c38f8ecd6164b00e49317fa 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/installation.sgml,v 1.269 2006/12/21 16:05:13 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/installation.sgml,v 1.270 2006/12/24 00:29:17 tgl Exp $ -->
 
 <chapter id="installation">
  <title><![%standalone-include[<productname>PostgreSQL</>]]>
@@ -909,7 +909,7 @@ su - postgres
        <term><option>--with-libxml</option></term>
        <listitem>
         <para>
-         Build with libxml, required for SQL/XML support.
+         Build with libxml (enables SQL/XML support).
         </para>
        </listitem>
       </varlistentry>
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 1e9865c300755d6c3998eb12d15a62d0b66f67c7..145da9b46368d67b3f98f50c19bbf5bd0664aaf3 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.201 2006/12/23 00:43:09 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.202 2006/12/24 00:29:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -117,11 +117,11 @@ static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
 static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
 			   ExprContext *econtext,
 			   bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
+						 bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
 			   ExprContext *econtext,
 			   bool *isNull, ExprDoneCond *isDone);
-static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
-						 bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalNullTest(NullTestState *nstate,
 				 ExprContext *econtext,
 				 bool *isNull, ExprDoneCond *isDone);
@@ -2638,6 +2638,237 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
 	return result;
 }
 
+/* ----------------------------------------------------------------
+ *		ExecEvalXml
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
+			bool *isNull, ExprDoneCond *isDone)
+{
+	XmlExpr		   *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
+	text 		   *result;
+	StringInfoData 	buf;
+	Datum			value;
+	bool 			isnull;
+	char		   *str;
+	ListCell 	   *arg;
+	ListCell   *narg;
+	bool	found_arg;
+	int 			i;
+
+	if (isDone)
+		*isDone = ExprSingleResult;
+	*isNull = true;				/* until we get a result */
+
+	switch (xexpr->op)
+	{
+		case IS_XMLCONCAT:
+			initStringInfo(&buf);
+			foreach(arg, xmlExpr->args)
+			{
+				ExprState 	*e = (ExprState *) lfirst(arg);
+
+				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				if (!isnull)
+				{
+					/* we know the value is XML type */
+					str = DatumGetCString(DirectFunctionCall1(xml_out,
+															  value));
+					appendStringInfoString(&buf, str);
+					pfree(str);
+					*isNull = false;
+				}
+			}
+			break;
+
+		case IS_XMLELEMENT:
+			initStringInfo(&buf);
+			*isNull = false;
+			appendStringInfo(&buf, "<%s", xexpr->name);
+			i = 0;
+			forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
+			{
+				ExprState 	*e = (ExprState *) lfirst(arg);
+				char	*argname = strVal(lfirst(narg));
+
+				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				if (!isnull)
+				{
+					str = OutputFunctionCall(&xmlExpr->named_outfuncs[i],
+											 value);
+					appendStringInfo(&buf, " %s=\"%s\"", argname, str);
+					pfree(str);
+				}
+				i++;
+			}
+
+			found_arg = false;
+			foreach(arg, xmlExpr->args)
+			{
+				ExprState 	*e = (ExprState *) lfirst(arg);
+
+				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				if (!isnull)
+				{
+					if (!found_arg)
+					{
+						appendStringInfoChar(&buf, '>');
+						found_arg = true;
+					}
+
+					/* we know the value is XML type */
+					str = DatumGetCString(DirectFunctionCall1(xml_out,
+															  value));
+					appendStringInfoString(&buf, str);
+					pfree(str);
+				}
+			}
+
+			if (!found_arg)
+				appendStringInfo(&buf, "/>");
+			else
+				appendStringInfo(&buf, "</%s>", xexpr->name);
+			break;
+
+		case IS_XMLFOREST:
+			initStringInfo(&buf);
+			i = 0;
+			forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
+			{
+				ExprState 	*e = (ExprState *) lfirst(arg);
+				char	*argname = strVal(lfirst(narg));
+
+				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				if (!isnull)
+				{
+					str = OutputFunctionCall(&xmlExpr->named_outfuncs[i],
+											 value);
+					appendStringInfo(&buf, "<%s>%s</%s>",
+									 argname, str, argname);
+					pfree(str);
+					*isNull = false;
+				}
+				i++;
+			}
+			break;
+
+			/* The remaining cases don't need to set up buf */
+		case IS_XMLPARSE:
+			{
+				ExprState 	*e;
+				text	    *data;
+				bool		is_document;
+				bool		preserve_whitespace;
+
+				/* arguments are known to be text, bool, bool */
+				Assert(list_length(xmlExpr->args) == 3);
+
+				e = (ExprState *) linitial(xmlExpr->args);
+				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				if (isnull)
+					return (Datum) 0;
+				data = DatumGetTextP(value);
+
+				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);
+
+				*isNull = false;
+
+				return PointerGetDatum(xmlparse(data,
+												is_document,
+												preserve_whitespace));
+			}
+			break;
+
+		case IS_XMLPI:
+			{
+				ExprState 	*e;
+				text	    *arg;
+
+				/* optional argument is known to be text */
+				Assert(list_length(xmlExpr->args) <= 1);
+
+				if (xmlExpr->args)
+				{
+					e = (ExprState *) linitial(xmlExpr->args);
+					value = ExecEvalExpr(e, econtext, &isnull, NULL);
+					if (isnull)
+						return (Datum) 0;
+					arg = DatumGetTextP(value);
+				}
+				else
+					arg = NULL;
+
+				*isNull = false;
+
+				return PointerGetDatum(xmlpi(xexpr->name, arg));
+			}
+			break;
+
+		case IS_XMLROOT:
+			{
+				ExprState 	*e;
+				xmltype		*data;
+				text		*version;
+				int			standalone;
+
+				/* arguments are known to be xml, text, bool */
+				Assert(list_length(xmlExpr->args) == 3);
+
+				e = (ExprState *) linitial(xmlExpr->args);
+				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				if (isnull)
+					return (Datum) 0;
+				data = DatumGetXmlP(value);
+
+				e = (ExprState *) lsecond(xmlExpr->args);
+				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				if (isnull)
+					version = NULL;
+				else
+					version = DatumGetTextP(value);
+
+				e = (ExprState *) lthird(xmlExpr->args);
+				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				if (isnull)
+					standalone = 0;
+				else
+					standalone = (DatumGetBool(value) ? 1 : -1);
+
+				*isNull = false;
+
+				return PointerGetDatum(xmlroot(data,
+											   version,
+											   standalone));
+			}
+			break;
+	}
+
+	if (*isNull)
+		result = NULL;
+	else
+	{
+		int		len = buf.len + VARHDRSZ;
+
+		result = palloc(len);
+		VARATT_SIZEP(result) = len;
+		memcpy(VARDATA(result), buf.data, buf.len);
+	}
+
+	pfree(buf.data);
+	return PointerGetDatum(result);
+}
+
 /* ----------------------------------------------------------------
  *		ExecEvalNullIf
  *
@@ -2881,120 +3112,6 @@ ExecEvalBooleanTest(GenericExprState *bstate,
 	}
 }
 
-/* ----------------------------------------------------------------
- *		ExecEvalXml
- * ----------------------------------------------------------------
- */
- 
-static Datum
-ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
-			bool *isNull, ExprDoneCond *isDone)
-{
-	StringInfoData 	buf;
-	bool 			isnull;
-	ListCell 	   *arg;
-	text 		   *result = NULL;
-	int 			len;
-
-	initStringInfo(&buf);
-
-	*isNull = false;
-
-	if (isDone)
-		*isDone = ExprSingleResult;
-
-	switch (xmlExpr->op)
-	{
-		case IS_XMLCONCAT:
-			*isNull = true;
-
-			foreach(arg, xmlExpr->args)
-			{
-				ExprState 	*e = (ExprState *) lfirst(arg);
-				Datum 		value = ExecEvalExpr(e, econtext, &isnull, NULL);
-
-				if (!isnull)
-				{
-					appendStringInfoString(&buf, DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeout, value)));
-					*isNull = false;
-				}
-			}
-			break;
-
-		case IS_XMLELEMENT:
-			{
-				int state = 0, i = 0;
-				appendStringInfo(&buf, "<%s", xmlExpr->name);
-				foreach(arg, xmlExpr->named_args)
-				{
-					GenericExprState *gstate = (GenericExprState *) lfirst(arg);
-					Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
-					if (!isnull)
-					{
-						char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->named_args_tcache[i], value));
-						appendStringInfo(&buf, " %s=\"%s\"", xmlExpr->named_args_ncache[i], outstr);
-						pfree(outstr);
-					}
-					i++;
-				}
-				if (xmlExpr->args)
-				{
-					ExprState 	*expr = linitial(xmlExpr->args);
-					Datum 		value = ExecEvalExpr(expr, econtext, &isnull, NULL);
-
-					if (!isnull)
-					{
-						char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeout, value));
-						if (state == 0)
-						{
-							appendStringInfoChar(&buf, '>');
-							state = 1;
-						}
-						appendStringInfo(&buf, "%s", outstr);
-						pfree(outstr);
-					}
-			 	}
-
-				if (state == 0)
-					appendStringInfo(&buf, "/>");
-			 	else if (state == 1)
-					appendStringInfo(&buf, "</%s>", xmlExpr->name);		
-
-			}
-			break;
-
-		case IS_XMLFOREST:
-			{
-				/* only if all argumets are null returns null */
-				int i = 0; 
-				*isNull = true;
-				foreach(arg, xmlExpr->named_args)
-			 	{
-					GenericExprState *gstate = (GenericExprState *) lfirst(arg);
-					Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
-					if (!isnull)
-					{
-						char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->named_args_tcache[i], value));
-						appendStringInfo(&buf, "<%s>%s</%s>", xmlExpr->named_args_ncache[i], outstr, xmlExpr->named_args_ncache[i]);
-						pfree(outstr);
-						*isNull = false;
-					}
-					i += 1;
-				}		
-			}
-			break;
-		default:
-			break;
-	}
-
-	len = buf.len + VARHDRSZ;
-	result = palloc(len);
-	VARATT_SIZEP(result) = len;
-	memcpy(VARDATA(result), buf.data, buf.len);
-	pfree(buf.data);
-	PG_RETURN_TEXT_P(result);
-}
-
 /*
  * ExecEvalCoerceToDomain
  *
@@ -3794,59 +3911,45 @@ ExecInitExpr(Expr *node, PlanState *parent)
 			break;
 		case T_XmlExpr:
 			{
-				List			*outlist; 
-				ListCell		*arg;
 				XmlExpr			*xexpr = (XmlExpr *) node;
 				XmlExprState	*xstate = makeNode(XmlExprState);
-				int				i = 0; 
-				Oid				typeout;
-		
-				xstate->name = xexpr->name;
-								
+				List			*outlist;
+				ListCell		*arg;
+				int				i;
+
 				xstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalXml;
-				xstate->op = xexpr->op;
-				
+				xstate->named_outfuncs = (FmgrInfo *)
+					palloc0(list_length(xexpr->named_args) * sizeof(FmgrInfo));
 				outlist = NIL;
-				if (xexpr->named_args)
-				{
-					xstate->named_args_tcache = (Oid *) palloc(list_length(xexpr->named_args) * sizeof(int));
-					xstate->named_args_ncache = (char **) palloc(list_length(xexpr->named_args) * sizeof(char *));
-					
-					i = 0;
-					foreach(arg, xexpr->named_args)
-					{
-						bool		tpisvarlena;
-						Expr		*e = (Expr *) lfirst(arg);
-						ExprState	*estate = ExecInitExpr(e, parent);
-						TargetEntry	*tle;
-						outlist = lappend(outlist, estate);					
-						tle = (TargetEntry *) ((GenericExprState *) estate)->xprstate.expr;
-						getTypeOutputInfo(exprType((Node *)tle->expr), &typeout, &tpisvarlena);
-						xstate->named_args_ncache[i] = tle->resname;
-						xstate->named_args_tcache[i] = typeout;
-						i++;
-					}	
-				}
-				else
+				i = 0;
+				foreach(arg, xexpr->named_args)
 				{
-					xstate->named_args_tcache = NULL;
-					xstate->named_args_ncache = NULL;
+					Expr		*e = (Expr *) lfirst(arg);
+					ExprState	*estate;
+					Oid			typOutFunc;
+					bool		typIsVarlena;
+
+					estate = ExecInitExpr(e, parent);
+					outlist = lappend(outlist, estate);
+
+					getTypeOutputInfo(exprType((Node *) e),
+									  &typOutFunc, &typIsVarlena);
+					fmgr_info(typOutFunc, &xstate->named_outfuncs[i]);
+					i++;
 				}
 				xstate->named_args = outlist;
 
-				outlist = NIL;				
+				outlist = NIL;
 				foreach(arg, xexpr->args)
 				{
-					bool 		tpisvarlena;
-					ExprState 	*estate;
-					Expr 		*e = (Expr *) lfirst(arg);
-					getTypeOutputInfo(exprType((Node *)e), &typeout, &tpisvarlena);
+					Expr		*e = (Expr *) lfirst(arg);
+					ExprState	*estate;
+
 					estate = ExecInitExpr(e, parent);
 					outlist = lappend(outlist, estate);
 				}
-				xstate->arg_typeout = typeout;
 				xstate->args = outlist;
-				
+
 				state = (ExprState *) xstate;
 			}
 			break;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index ca841cb181aaed174ed03f1aa83970da5198d0b3..d46ed57d830e0b7a85622fd0bb32024bf857701a 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.356 2006/12/23 00:43:09 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.357 2006/12/24 00:29:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1093,6 +1093,23 @@ _copyMinMaxExpr(MinMaxExpr *from)
 	return newnode;
 }
 
+/*
+ * _copyXmlExpr
+ */
+static XmlExpr *
+_copyXmlExpr(XmlExpr *from)
+{
+	XmlExpr *newnode = makeNode(XmlExpr);
+
+	COPY_SCALAR_FIELD(op);
+	COPY_STRING_FIELD(name);
+	COPY_NODE_FIELD(named_args);
+	COPY_NODE_FIELD(arg_names);
+	COPY_NODE_FIELD(args);
+
+	return newnode;
+}
+
 /*
  * _copyNullIfExpr (same as OpExpr)
  */
@@ -1138,22 +1155,6 @@ _copyBooleanTest(BooleanTest *from)
 	return newnode;
 }
 
-/*
- * _copyXmlExpr
- */
-static XmlExpr *
-_copyXmlExpr(XmlExpr *from)
-{
-	XmlExpr *newnode = makeNode(XmlExpr);
-
-	COPY_SCALAR_FIELD(op);
-	COPY_STRING_FIELD(name);
-	COPY_NODE_FIELD(named_args);
-	COPY_NODE_FIELD(args);
-
-	return newnode;
-}
-
 /*
  * _copyCoerceToDomain
  */
@@ -2977,6 +2978,9 @@ copyObject(void *from)
 		case T_MinMaxExpr:
 			retval = _copyMinMaxExpr(from);
 			break;
+		case T_XmlExpr:
+			retval = _copyXmlExpr(from);
+			break;
 		case T_NullIfExpr:
 			retval = _copyNullIfExpr(from);
 			break;
@@ -2986,9 +2990,6 @@ copyObject(void *from)
 		case T_BooleanTest:
 			retval = _copyBooleanTest(from);
 			break;
-		case T_XmlExpr:
-			retval = _copyXmlExpr(from);
-			break;
 		case T_CoerceToDomain:
 			retval = _copyCoerceToDomain(from);
 			break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index a7c4ef4e2a819e5838176bf382ff7752088d5bd4..29bff448c7f53ce4387cb401cc66c13aa0876427 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.290 2006/12/23 00:43:10 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.291 2006/12/24 00:29:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -454,6 +454,18 @@ _equalMinMaxExpr(MinMaxExpr *a, MinMaxExpr *b)
 	return true;
 }
 
+static bool
+_equalXmlExpr(XmlExpr *a, XmlExpr *b)
+{
+	COMPARE_SCALAR_FIELD(op);
+	COMPARE_STRING_FIELD(name);
+	COMPARE_NODE_FIELD(named_args);
+	COMPARE_NODE_FIELD(arg_names);
+	COMPARE_NODE_FIELD(args);
+
+	return true;
+}
+
 static bool
 _equalNullIfExpr(NullIfExpr *a, NullIfExpr *b)
 {
@@ -495,17 +507,6 @@ _equalBooleanTest(BooleanTest *a, BooleanTest *b)
 	return true;
 }
 
-static bool
-_equalXmlExpr(XmlExpr *a, XmlExpr *b)
-{
-	COMPARE_SCALAR_FIELD(op);
-	COMPARE_STRING_FIELD(name);
-	COMPARE_NODE_FIELD(named_args);
-	COMPARE_NODE_FIELD(args);
-
-	return true;
-}
-
 static bool
 _equalCoerceToDomain(CoerceToDomain *a, CoerceToDomain *b)
 {
@@ -1971,6 +1972,9 @@ equal(void *a, void *b)
 		case T_MinMaxExpr:
 			retval = _equalMinMaxExpr(a, b);
 			break;
+		case T_XmlExpr:
+			retval = _equalXmlExpr(a, b);
+			break;
 		case T_NullIfExpr:
 			retval = _equalNullIfExpr(a, b);
 			break;
@@ -1980,9 +1984,6 @@ equal(void *a, void *b)
 		case T_BooleanTest:
 			retval = _equalBooleanTest(a, b);
 			break;
-		case T_XmlExpr:
-			retval = _equalXmlExpr(a, b);
-			break;
 		case T_CoerceToDomain:
 			retval = _equalCoerceToDomain(a, b);
 			break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index b18b6988cfa776163141f877c8b570eaf6ae52c5..4911d6ed4044c33a197fe268836e5847783c213c 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.288 2006/12/23 00:43:10 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.289 2006/12/24 00:29:18 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -892,6 +892,18 @@ _outMinMaxExpr(StringInfo str, MinMaxExpr *node)
 	WRITE_NODE_FIELD(args);
 }
 
+static void
+_outXmlExpr(StringInfo str, XmlExpr *node)
+{
+	WRITE_NODE_TYPE("XMLEXPR");
+	
+	WRITE_ENUM_FIELD(op, XmlExprOp);
+	WRITE_STRING_FIELD(name);
+	WRITE_NODE_FIELD(named_args);
+	WRITE_NODE_FIELD(arg_names);
+	WRITE_NODE_FIELD(args);
+}
+
 static void
 _outNullIfExpr(StringInfo str, NullIfExpr *node)
 {
@@ -922,17 +934,6 @@ _outBooleanTest(StringInfo str, BooleanTest *node)
 	WRITE_ENUM_FIELD(booltesttype, BoolTestType);
 }
 
-static void
-_outXmlExpr(StringInfo str, XmlExpr *node)
-{
-	WRITE_NODE_TYPE("XMLEXPR");
-	
-	WRITE_ENUM_FIELD(op, XmlExprOp);
-	WRITE_STRING_FIELD(name);
-	WRITE_NODE_FIELD(named_args);
-	WRITE_NODE_FIELD(args);
-}
-
 static void
 _outCoerceToDomain(StringInfo str, CoerceToDomain *node)
 {
@@ -2026,6 +2027,9 @@ _outNode(StringInfo str, void *obj)
 			case T_MinMaxExpr:
 				_outMinMaxExpr(str, obj);
 				break;
+			case T_XmlExpr:
+				_outXmlExpr(str, obj);
+				break;
 			case T_NullIfExpr:
 				_outNullIfExpr(str, obj);
 				break;
@@ -2035,9 +2039,6 @@ _outNode(StringInfo str, void *obj)
 			case T_BooleanTest:
 				_outBooleanTest(str, obj);
 				break;
-			case T_XmlExpr:
-				_outXmlExpr(str, obj);
-				break;
 			case T_CoerceToDomain:
 				_outCoerceToDomain(str, obj);
 				break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 37b39439eb0d4f69066b5c5525f0497d654e38cb..781eeee14f16727414f863e12b051a74dd4d9d83 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.198 2006/12/23 00:43:10 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.199 2006/12/24 00:29:18 tgl Exp $
  *
  * NOTES
  *	  Path and Plan nodes do not have any readfuncs support, because we
@@ -708,6 +708,23 @@ _readMinMaxExpr(void)
 	READ_DONE();
 }
 
+/*
+ * _readXmlExpr
+ */
+static XmlExpr *
+_readXmlExpr(void)
+{
+	READ_LOCALS(XmlExpr);
+
+	READ_ENUM_FIELD(op, XmlExprOp);
+	READ_STRING_FIELD(name);
+	READ_NODE_FIELD(named_args);
+	READ_NODE_FIELD(arg_names);
+	READ_NODE_FIELD(args);
+
+	READ_DONE();
+}
+
 /*
  * _readNullIfExpr
  */
@@ -764,22 +781,6 @@ _readBooleanTest(void)
 	READ_DONE();
 }
 
-/*
- * _readXmlExpr
- */
-static XmlExpr *
-_readXmlExpr(void)
-{
-	READ_LOCALS(XmlExpr);
-
-	READ_ENUM_FIELD(op, XmlExprOp);
-	READ_STRING_FIELD(name);
-	READ_NODE_FIELD(named_args);
-	READ_NODE_FIELD(args);
-
-	READ_DONE();
-}
-
 /*
  * _readCoerceToDomain
  */
@@ -1024,14 +1025,14 @@ parseNodeString(void)
 		return_value = _readCoalesceExpr();
 	else if (MATCH("MINMAX", 6))
 		return_value = _readMinMaxExpr();
+	else if (MATCH("XMLEXPR", 7))
+		return_value = _readXmlExpr();
 	else if (MATCH("NULLIFEXPR", 10))
 		return_value = _readNullIfExpr();
 	else if (MATCH("NULLTEST", 8))
 		return_value = _readNullTest();
 	else if (MATCH("BOOLEANTEST", 11))
 		return_value = _readBooleanTest();
-	else if (MATCH("XMLEXPR", 7))
-		return_value = _readXmlExpr();
 	else if (MATCH("COERCETODOMAIN", 14))
 		return_value = _readCoerceToDomain();
 	else if (MATCH("COERCETODOMAINVALUE", 19))
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 0f720c40e932e8a5563d1cdab4cd1188f62545ba..5ad97aabc3439d997d5246face2ccd16643d7b79 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.225 2006/12/23 00:43:10 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.226 2006/12/24 00:29:18 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -557,10 +557,10 @@ expression_returns_set_walker(Node *node, void *context)
 		return false;
 	if (IsA(node, MinMaxExpr))
 		return false;
-	if (IsA(node, NullIfExpr))
-		return false;
 	if (IsA(node, XmlExpr))
 		return false;
+	if (IsA(node, NullIfExpr))
+		return false;
 
 	return expression_tree_walker(node, expression_returns_set_walker,
 								  context);
@@ -872,14 +872,14 @@ contain_nonstrict_functions_walker(Node *node, void *context)
 		return true;
 	if (IsA(node, MinMaxExpr))
 		return true;
+	if (IsA(node, XmlExpr))
+		return true;
 	if (IsA(node, NullIfExpr))
 		return true;
 	if (IsA(node, NullTest))
 		return true;
 	if (IsA(node, BooleanTest))
 		return true;
-	if (IsA(node, XmlExpr))
-		return true;
 	return expression_tree_walker(node, contain_nonstrict_functions_walker,
 								  context);
 }
@@ -3328,22 +3328,23 @@ expression_tree_walker(Node *node,
 			return walker(((CoalesceExpr *) node)->args, context);
 		case T_MinMaxExpr:
 			return walker(((MinMaxExpr *) node)->args, context);
-		case T_NullIfExpr:
-			return walker(((NullIfExpr *) node)->args, context);
-		case T_NullTest:
-			return walker(((NullTest *) node)->arg, context);
-		case T_BooleanTest:
-			return walker(((BooleanTest *) node)->arg, context);
 		case T_XmlExpr:
 			{
 				XmlExpr *xexpr = (XmlExpr *) node;
 				
 				if (walker(xexpr->named_args, context))
 					return true;
+				/* we assume walker doesn't care about arg_names */
 				if (walker(xexpr->args, context))
 					return true;
 			}
 			break;
+		case T_NullIfExpr:
+			return walker(((NullIfExpr *) node)->args, context);
+		case T_NullTest:
+			return walker(((NullTest *) node)->arg, context);
+		case T_BooleanTest:
+			return walker(((BooleanTest *) node)->arg, context);
 		case T_CoerceToDomain:
 			return walker(((CoerceToDomain *) node)->arg, context);
 		case T_TargetEntry:
@@ -3874,6 +3875,7 @@ expression_tree_mutator(Node *node,
 
 				FLATCOPY(newnode, xexpr, XmlExpr);
 				MUTATE(newnode->named_args, xexpr->named_args, List *);
+				/* assume mutator does not care about arg_names */
 				MUTATE(newnode->args, xexpr->args, List *);
 				return (Node *) newnode;
 			}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index cc400407363e660df5060a223cf8c1b27a8cf152..a1511870f28a425bd6f37e69b33313d9bca2a9c8 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.569 2006/12/21 16:05:14 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.570 2006/12/24 00:29:18 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -348,8 +348,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
-%type <ival>	opt_xml_root_standalone document_or_content xml_whitespace_option
+%type <node>	xml_root_version opt_xml_root_standalone
+%type <boolean>	document_or_content xml_whitespace_option
 
 
 /*
@@ -371,13 +371,13 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
 	CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
 	CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
 	COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS
-	CONTENT CONVERSION_P CONVERT COPY CREATE CREATEDB
+	CONTENT_P CONVERSION_P CONVERT COPY CREATE CREATEDB
 	CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME
 	CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
 
 	DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
 	DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
-	DESC DISABLE_P DISTINCT DO DOCUMENT DOMAIN_P DOUBLE_P DROP
+	DESC DISABLE_P DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
 
 	EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
 	EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
@@ -404,7 +404,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
 
 	MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
 
-	NAME NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
+	NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
 	NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
 	NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NUMERIC
 
@@ -423,9 +423,9 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
 
 	SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
 	SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
-	SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE START STATEMENT
-	STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP SUBSTRING SUPERUSER_P SYMMETRIC
-	SYSID SYSTEM_P
+	SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE_P START STATEMENT
+	STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
+	SYMMETRIC SYSID SYSTEM_P
 
 	TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP
 	TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
@@ -434,15 +434,15 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
 	UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
 	UPDATE USER USING
 
-	VACUUM VALID VALIDATOR VALUE VALUES VARCHAR VARYING
-	VERBOSE VERSION VIEW VOLATILE
+	VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARYING
+	VERBOSE VERSION_P VIEW VOLATILE
 
-	WHEN WHERE WHITESPACE WITH WITHOUT WORK WRITE
+	WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
 
 	XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
 	XMLPI XMLROOT XMLSERIALIZE
 
-	YEAR_P YES
+	YEAR_P YES_P
 
 	ZONE
 
@@ -493,7 +493,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
  * left-associativity among the JOIN rules themselves.
  */
 %left		JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
-%right		PRESERVE STRIP
+/* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */
+%right		PRESERVE STRIP_P
 %%
 
 /*
@@ -7880,95 +7881,54 @@ func_expr:	func_name '(' ')'
 				}
 			| XMLCONCAT '(' expr_list ')'
 				{		
-					$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NULL, $3);
+					$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3);
 				}
-			| XMLELEMENT '(' NAME ColLabel ')'
+			| XMLELEMENT '(' NAME_P ColLabel ')'
 				{
-					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, NULL);
+					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL);
 				}
-			| XMLELEMENT '(' NAME ColLabel ',' xml_attributes ')'
+			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
 				{
-					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NULL);
+					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL);
 				}
-			| XMLELEMENT '(' NAME ColLabel ',' expr_list ')'
+			| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
 				{
-					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, $6);
+					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6);
 				}
-			| XMLELEMENT '(' NAME ColLabel ',' xml_attributes ',' expr_list ')'
+			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
 				{
 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8);
 				}
 			| XMLFOREST '(' xml_attribute_list ')'
 				{
-					$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NULL);
+					$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL);
 				}
 			| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
 				{
-					FuncCall *n = makeNode(FuncCall);
-					n->funcname = SystemFuncName("xmlparse");
-					n->args = list_make3(makeBoolAConst($3 == DOCUMENT), $4, makeBoolAConst($5 == PRESERVE));
-					n->agg_star = FALSE;
-					n->agg_distinct = FALSE;
-					n->location = @1;
-					$$ = (Node *)n;
+					$$ = makeXmlExpr(IS_XMLPARSE, NULL, NIL,
+									 list_make3($4,
+												makeBoolAConst($3),
+												makeBoolAConst($5)));
 				}
-			| XMLPI '(' NAME ColLabel ')'
+			| XMLPI '(' NAME_P ColLabel ')'
 				{
-					FuncCall *n = makeNode(FuncCall);
-					n->funcname = SystemFuncName("xmlpi");
-					n->args = list_make1(makeStringConst($4, NULL));
-					n->agg_star = FALSE;
-					n->agg_distinct = FALSE;
-					n->location = @1;
-					$$ = (Node *)n;
+					$$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL);
 				}
-			| XMLPI '(' NAME ColLabel ',' a_expr ')'
+			| XMLPI '(' NAME_P ColLabel ',' a_expr ')'
 				{
-					FuncCall *n = makeNode(FuncCall);
-					n->funcname = SystemFuncName("xmlpi");
-					n->args = list_make2(makeStringConst($4, NULL), $6);
-					n->agg_star = FALSE;
-					n->agg_distinct = FALSE;
-					n->location = @1;
-					$$ = (Node *)n;
+					$$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6));
 				}
 			| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
 				{
-					FuncCall *n = makeNode(FuncCall);
-					Node *ver;
-					A_Const *sa;
-
-					if ($5)
-						ver = $5;
-					else
-					{
-						A_Const *val;
-
-						val = makeNode(A_Const);
-						val->val.type = T_Null;
-						ver = (Node *) val;
-					}
-
-					if ($6)
-						sa = makeBoolAConst($6 == 1);
-					else
-					{
-						sa = makeNode(A_Const);
-						sa->val.type = T_Null;
-					}
-
-					n->funcname = SystemFuncName("xmlroot");
-					n->args = list_make3($3, ver, sa);
-					n->agg_star = FALSE;
-					n->agg_distinct = FALSE;
-					n->location = @1;
-					$$ = (Node *)n;
+					$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
+									 list_make3($3, $5, $6));
 				}
 			| XMLSERIALIZE '(' document_or_content a_expr AS Typename ')'
 				{
 					/*
 					 * FIXME: This should be made distinguishable from
-					 * CAST (for reverse compilation at least).
+					 * CAST (for reverse compilation at least).  Also,
+					 * what about the document/content option??
 					 */
 					$$ = makeTypeCast($4, $6);
 				}
@@ -7977,17 +7937,35 @@ func_expr:	func_name '(' ')'
 /*
  * SQL/XML support
  */
-xml_root_version: VERSION a_expr	{ $$ = $2; }
-			| VERSION NO VALUE		{ $$ = NULL; }
+xml_root_version: VERSION_P a_expr
+				{ $$ = $2; }
+			| VERSION_P NO VALUE_P
+				{
+					A_Const *val = makeNode(A_Const);
+					val->val.type = T_Null;
+					$$ = (Node *) val;
+				}
 		;
 
-opt_xml_root_standalone: ',' STANDALONE YES	{ $$ = 1; }
-			| ',' STANDALONE NO				{ $$ = -1; }
-			| ',' STANDALONE NO VALUE		{ $$ = 0; }
-			| /*EMPTY*/						{ $$ = 0; }
+opt_xml_root_standalone: ',' STANDALONE_P YES_P
+				{ $$ = (Node *) makeBoolAConst(true); }
+			| ',' STANDALONE_P NO
+				{ $$ = (Node *) makeBoolAConst(false); }
+			| ',' STANDALONE_P NO VALUE_P
+				{
+					A_Const *val = makeNode(A_Const);
+					val->val.type = T_Null;
+					$$ = (Node *) val;
+				}
+			| /*EMPTY*/
+				{
+					A_Const *val = makeNode(A_Const);
+					val->val.type = T_Null;
+					$$ = (Node *) val;
+				}
 		;
 
-xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
+xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')'	{ $$ = $3; }
 		;
 
 xml_attribute_list:	xml_attribute_el					{ $$ = list_make1($1); }
@@ -8000,7 +7978,7 @@ xml_attribute_el: a_expr AS ColLabel
 					$$->name = $3;
 					$$->indirection = NULL;
 					$$->val = (Node *) $1;
-
+					$$->location = @1;
 				}
 			| a_expr
 				{
@@ -8008,16 +7986,21 @@ xml_attribute_el: a_expr AS ColLabel
 					$$->name = NULL;
 					$$->indirection = NULL;
 					$$->val = (Node *) $1;				
+					$$->location = @1;
 				}
 		;
 
-document_or_content: DOCUMENT { $$ = DOCUMENT; }
-			| CONTENT { $$ = CONTENT; }
+document_or_content: DOCUMENT_P						{ $$ = TRUE; }
+			| CONTENT_P								{ $$ = FALSE; }
 		;
 
-xml_whitespace_option: PRESERVE WHITESPACE { $$ = PRESERVE; }
-			| STRIP WHITESPACE { $$ = STRIP; }
-			| /*EMPTY*/ { $$ = STRIP; }
+/*
+ * 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; }
 		;
 
 /*
@@ -8712,7 +8695,7 @@ unreserved_keyword:
 			| CONCURRENTLY
 			| CONNECTION
 			| CONSTRAINTS
-			| CONTENT
+			| CONTENT_P
 			| CONVERSION_P
 			| COPY
 			| CREATEDB
@@ -8732,7 +8715,7 @@ unreserved_keyword:
 			| DELIMITER
 			| DELIMITERS
 			| DISABLE_P
-			| DOCUMENT
+			| DOCUMENT_P
 			| DOMAIN_P
 			| DOUBLE_P
 			| DROP
@@ -8792,7 +8775,7 @@ unreserved_keyword:
 			| MODE
 			| MONTH_P
 			| MOVE
-			| NAME
+			| NAME_P
 			| NAMES
 			| NEXT
 			| NO
@@ -8853,18 +8836,18 @@ unreserved_keyword:
 			| SHOW
 			| SIMPLE
 			| STABLE
-			| STANDALONE
+			| STANDALONE_P
 			| START
 			| STATEMENT
 			| STATISTICS
 			| STDIN
 			| STDOUT
 			| STORAGE
-			| STRIP
+			| STRICT_P
+			| STRIP_P
 			| SUPERUSER_P
 			| SYSID
 			| SYSTEM_P
-			| STRICT_P
 			| TABLESPACE
 			| TEMP
 			| TEMPLATE
@@ -8883,18 +8866,18 @@ unreserved_keyword:
 			| VACUUM
 			| VALID
 			| VALIDATOR
+			| VALUE_P
 			| VARYING
-			| VERSION
+			| VERSION_P
 			| VIEW
-			| VALUE
 			| VOLATILE
-			| WHITESPACE
+			| WHITESPACE_P
 			| WITH
 			| WITHOUT
 			| WORK
 			| WRITE
 			| YEAR_P
-			| YES
+			| YES_P
 			| ZONE
 		;
 
@@ -8948,8 +8931,8 @@ col_name_keyword:
 			| VALUES
 			| VARCHAR
 			| XMLATTRIBUTES
-			| XMLELEMENT
 			| XMLCONCAT
+			| XMLELEMENT
 			| XMLFOREST
 			| XMLPARSE
 			| XMLPI
@@ -9492,10 +9475,16 @@ doNegateFloat(Value *v)
 static Node *
 makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
 {
-	XmlExpr *x = makeNode(XmlExpr);
+	XmlExpr    *x = makeNode(XmlExpr);
+
 	x->op = op;
 	x->name = name;
+	/*
+	 * named_args is a list of ResTarget; it'll be split apart into separate
+	 * expression and name lists in transformXmlExpr().
+	 */
 	x->named_args = named_args;
+	x->arg_names = NIL;
 	x->args = args;
 	return (Node *) x;
 }
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index b5e49e955fc1e30173731bff1f457b0a30e8e6e7..4865d360b3efd2e51d77f9a780f4bceaacb65300 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.178 2006/12/21 16:05:14 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.179 2006/12/24 00:29:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -89,7 +89,7 @@ static const ScanKeyword ScanKeywords[] = {
 	{"connection", CONNECTION},
 	{"constraint", CONSTRAINT},
 	{"constraints", CONSTRAINTS},
-	{"content", CONTENT},
+	{"content", CONTENT_P},
 	{"conversion", CONVERSION_P},
 	{"convert", CONVERT},
 	{"copy", COPY},
@@ -124,7 +124,7 @@ static const ScanKeyword ScanKeywords[] = {
 	{"disable", DISABLE_P},
 	{"distinct", DISTINCT},
 	{"do", DO},
-	{"document", DOCUMENT},
+	{"document", DOCUMENT_P},
 	{"domain", DOMAIN_P},
 	{"double", DOUBLE_P},
 	{"drop", DROP},
@@ -220,7 +220,7 @@ static const ScanKeyword ScanKeywords[] = {
 	{"mode", MODE},
 	{"month", MONTH_P},
 	{"move", MOVE},
-	{"name", NAME},
+	{"name", NAME_P},
 	{"names", NAMES},
 	{"national", NATIONAL},
 	{"natural", NATURAL},
@@ -317,7 +317,7 @@ static const ScanKeyword ScanKeywords[] = {
 	{"smallint", SMALLINT},
 	{"some", SOME},
 	{"stable", STABLE},
-	{"standalone", STANDALONE},
+	{"standalone", STANDALONE_P},
 	{"start", START},
 	{"statement", STATEMENT},
 	{"statistics", STATISTICS},
@@ -325,7 +325,7 @@ static const ScanKeyword ScanKeywords[] = {
 	{"stdout", STDOUT},
 	{"storage", STORAGE},
 	{"strict", STRICT_P},
-	{"strip", STRIP},
+	{"strip", STRIP_P},
 	{"substring", SUBSTRING},
 	{"superuser", SUPERUSER_P},
 	{"symmetric", SYMMETRIC},
@@ -362,17 +362,17 @@ static const ScanKeyword ScanKeywords[] = {
 	{"vacuum", VACUUM},
 	{"valid", VALID},
 	{"validator", VALIDATOR},
-	{"value", VALUE},
+	{"value", VALUE_P},
 	{"values", VALUES},
 	{"varchar", VARCHAR},
 	{"varying", VARYING},
 	{"verbose", VERBOSE},
-	{"version", VERSION},
+	{"version", VERSION_P},
 	{"view", VIEW},
 	{"volatile", VOLATILE},
 	{"when", WHEN},
 	{"where", WHERE},
-	{"whitespace", WHITESPACE},
+	{"whitespace", WHITESPACE_P},
 	{"with", WITH},
 	{"without", WITHOUT},
 	{"work", WORK},
@@ -386,7 +386,7 @@ static const ScanKeyword ScanKeywords[] = {
 	{"xmlroot", XMLROOT},
 	{"xmlserialize", XMLSERIALIZE},
 	{"year", YEAR_P},
-	{"yes", YES},
+	{"yes", YES_P},
 	{"zone", ZONE},
 };
 
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 996c724d1cec46c1709e0d239d81c26336446037..145caab101a47822c76dfbd1ad28b1812d28ccf8 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.159 2006/11/28 12:54:41 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.160 2006/12/24 00:29:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1094,7 +1094,7 @@ transformLimitClause(ParseState *pstate, Node *clause,
 
 	qual = transformExpr(pstate, clause);
 
-	qual = coerce_to_bigint(pstate, qual, constructName);
+	qual = coerce_to_specific_type(pstate, qual, INT8OID, constructName);
 
 	/*
 	 * LIMIT can't refer to any vars or aggregates of the current query; we
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 5670ed4fe742188c1b00a03f57340b95a4881edd..45c8e97be1d24f5ab95a2c402c8b8176af83f362 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.148 2006/12/21 16:05:14 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.149 2006/12/24 00:29:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -840,8 +840,8 @@ coerce_to_boolean(ParseState *pstate, Node *node,
 }
 
 /*
- * coerce_to_integer()
- *		Coerce an argument of a construct that requires integer input.
+ * coerce_to_specific_type()
+ *		Coerce an argument of a construct that requires a specific data type.
  *		Also check that input is not a set.
  *
  * Returns the possibly-transformed node tree.
@@ -850,103 +850,26 @@ coerce_to_boolean(ParseState *pstate, Node *node,
  * processing is wanted.
  */
 Node *
-coerce_to_integer(ParseState *pstate, Node *node,
-				  const char *constructName)
-{
-	Oid			inputTypeId = exprType(node);
-
-	if (inputTypeId != INT4OID)
-	{
-		node = coerce_to_target_type(pstate, node, inputTypeId,
-									 INT4OID, -1,
-									 COERCION_ASSIGNMENT,
-									 COERCE_IMPLICIT_CAST);
-		if (node == NULL)
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-			/* translator: first %s is name of a SQL construct, eg LIMIT */
-				   errmsg("argument of %s must be type integer, not type %s",
-						  constructName, format_type_be(inputTypeId))));
-	}
-
-	if (expression_returns_set(node))
-		ereport(ERROR,
-				(errcode(ERRCODE_DATATYPE_MISMATCH),
-		/* translator: %s is name of a SQL construct, eg LIMIT */
-				 errmsg("argument of %s must not return a set",
-						constructName)));
-
-	return node;
-}
-
-/*
- * coerce_to_bigint()
- *		Coerce an argument of a construct that requires int8 input.
- *		Also check that input is not a set.
- *
- * Returns the possibly-transformed node tree.
- *
- * As with coerce_type, pstate may be NULL if no special unknown-Param
- * processing is wanted.
- */
-Node *
-coerce_to_bigint(ParseState *pstate, Node *node,
-				 const char *constructName)
-{
-	Oid			inputTypeId = exprType(node);
-
-	if (inputTypeId != INT8OID)
-	{
-		node = coerce_to_target_type(pstate, node, inputTypeId,
-									 INT8OID, -1,
-									 COERCION_ASSIGNMENT,
-									 COERCE_IMPLICIT_CAST);
-		if (node == NULL)
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-			/* translator: first %s is name of a SQL construct, eg LIMIT */
-					 errmsg("argument of %s must be type bigint, not type %s",
-							constructName, format_type_be(inputTypeId))));
-	}
-
-	if (expression_returns_set(node))
-		ereport(ERROR,
-				(errcode(ERRCODE_DATATYPE_MISMATCH),
-		/* translator: %s is name of a SQL construct, eg LIMIT */
-				 errmsg("argument of %s must not return a set",
-						constructName)));
-
-	return node;
-}
-
-/*
- * coerce_to_xml()
- *		Coerce an argument of a construct that requires xml input.
- *		Also check that input is not a set.
- *
- * Returns the possibly-transformed node tree.
- *
- * As with coerce_type, pstate may be NULL if no special unknown-Param
- * processing is wanted.
- */
-Node *
-coerce_to_xml(ParseState *pstate, Node *node,
-				 const char *constructName)
+coerce_to_specific_type(ParseState *pstate, Node *node,
+						Oid targetTypeId,
+						const char *constructName)
 {
 	Oid			inputTypeId = exprType(node);
 
-	if (inputTypeId != XMLOID)
+	if (inputTypeId != targetTypeId)
 	{
 		node = coerce_to_target_type(pstate, node, inputTypeId,
-									 XMLOID, -1,
+									 targetTypeId, -1,
 									 COERCION_ASSIGNMENT,
 									 COERCE_IMPLICIT_CAST);
 		if (node == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
 			/* translator: first %s is name of a SQL construct, eg LIMIT */
-					 errmsg("argument of %s must be type xml, not type %s",
-							constructName, format_type_be(inputTypeId))));
+				   errmsg("argument of %s must be type %s, not type %s",
+						  constructName,
+						  format_type_be(targetTypeId),
+						  format_type_be(inputTypeId))));
 	}
 
 	if (expression_returns_set(node))
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 2a48741b3a2fef31be935b3beacca84411c3c1f3..7dbbb9a33a8637b97338756d22cd8cf027dc2416 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.201 2006/12/23 00:43:11 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.202 2006/12/24 00:29:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -220,6 +220,10 @@ transformExpr(ParseState *pstate, Node *expr)
 			result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
 			break;
 
+		case T_XmlExpr:
+			result = transformXmlExpr(pstate, (XmlExpr *) expr);
+			break;
+
 		case T_NullTest:
 			{
 				NullTest   *n = (NullTest *) expr;
@@ -234,10 +238,6 @@ transformExpr(ParseState *pstate, Node *expr)
 			result = transformBooleanTest(pstate, (BooleanTest *) expr);
 			break;
 
-		case T_XmlExpr:
-			result = transformXmlExpr(pstate, (XmlExpr *) expr);
-			break;
-
 			/*********************************************
 			 * Quietly accept node types that may be presented when we are
 			 * called on an already-transformed tree.
@@ -1375,6 +1375,107 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
 	return (Node *) newm;
 }
 
+static Node *
+transformXmlExpr(ParseState *pstate, XmlExpr *x)
+{
+	XmlExpr *newx = makeNode(XmlExpr);
+	ListCell	*lc;
+	int			i;
+
+	newx->op = x->op;
+	if (x->name)
+		newx->name = map_sql_identifier_to_xml_name(x->name, false);
+	else
+		newx->name = NULL;
+
+	/*
+	 * gram.y built the named args as a list of ResTarget.  Transform each,
+	 * and break the names out as a separate list.
+	 */
+	newx->named_args = NIL;
+	newx->arg_names = NIL;
+
+	foreach(lc, x->named_args)
+	{
+		ResTarget 	*r = (ResTarget *) lfirst(lc);
+		Node 		*expr;
+		char 		*argname;
+
+		Assert(IsA(r, ResTarget));
+
+		expr = transformExpr(pstate, r->val);
+
+		if (r->name)
+			argname = map_sql_identifier_to_xml_name(r->name, false);
+		else if (IsA(r->val, ColumnRef))
+			argname = map_sql_identifier_to_xml_name(FigureColname(r->val),
+													 true);
+		else
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_SYNTAX_ERROR),
+					 x->op == IS_XMLELEMENT
+					 ? errmsg("unnamed attribute value must be a column reference")
+					 : errmsg("unnamed element value must be a column reference")));
+			argname = NULL;		/* keep compiler quiet */
+		}
+
+		newx->named_args = lappend(newx->named_args, expr);
+		newx->arg_names = lappend(newx->arg_names, makeString(argname));
+	}
+
+	/* The other arguments are of varying types depending on the function */
+	newx->args = NIL;
+	i = 0;
+	foreach(lc, x->args)
+	{
+		Node	   *e = (Node *) lfirst(lc);
+		Node	   *newe;
+
+		newe = transformExpr(pstate, e);
+		switch (x->op)
+		{
+			case IS_XMLCONCAT:
+				newe = coerce_to_specific_type(pstate, newe, XMLOID,
+											   "XMLCONCAT");
+				break;
+			case IS_XMLELEMENT:
+				newe = coerce_to_specific_type(pstate, newe, XMLOID,
+											   "XMLELEMENT");
+				break;
+			case IS_XMLFOREST:
+				newe = coerce_to_specific_type(pstate, newe, XMLOID,
+											   "XMLFOREST");
+				break;
+			case IS_XMLPARSE:
+				if (i == 0)
+					newe = coerce_to_specific_type(pstate, newe, TEXTOID,
+												   "XMLPARSE");
+				else
+					newe = coerce_to_boolean(pstate, newe, "XMLPARSE");
+				break;
+			case IS_XMLPI:
+				newe = coerce_to_specific_type(pstate, newe, TEXTOID,
+											   "XMLPI");
+				break;
+			case IS_XMLROOT:
+				if (i == 0)
+					newe = coerce_to_specific_type(pstate, newe, XMLOID,
+												   "XMLROOT");
+				else if (i == 1)
+					newe = coerce_to_specific_type(pstate, newe, TEXTOID,
+												   "XMLROOT");
+				else
+					newe = coerce_to_boolean(pstate, newe, "XMLROOT");
+				break;
+		}
+		newx->args = lappend(newx->args, newe);
+		i++;
+	}
+		
+	return (Node *) newx;
+}
+
 static Node *
 transformBooleanTest(ParseState *pstate, BooleanTest *b)
 {
@@ -1415,56 +1516,6 @@ transformBooleanTest(ParseState *pstate, BooleanTest *b)
 	return (Node *) b;
 }
 
-static Node *
-transformXmlExpr(ParseState *pstate, XmlExpr *x)
-{
-	ListCell	*lc;
-	XmlExpr *newx = makeNode(XmlExpr);
-
-	newx->op = x->op;
-	if (x->name)
-		newx->name = map_sql_identifier_to_xml_name(x->name, false);
-	else
-		newx->name = NULL;
-
-	foreach(lc, x->named_args)
-	{
-		ResTarget 	*r = (ResTarget *) lfirst(lc);
-		Node 		*expr = transformExpr(pstate, r->val);
-		char 		*argname = NULL;
-
-		if (r->name)
-			argname = map_sql_identifier_to_xml_name(r->name, false);
-		else if (IsA(r->val, ColumnRef))
-			argname = map_sql_identifier_to_xml_name(FigureColname(r->val), true);
-		else
-			ereport(ERROR,
-					(errcode(ERRCODE_SYNTAX_ERROR),
-					 x->op == IS_XMLELEMENT
-					 ? errmsg("unnamed attribute value must be a column reference")
-					 : errmsg("unnamed element value must be a column reference")));
-
-		newx->named_args = lappend(newx->named_args, 
-								   makeTargetEntry((Expr *) expr, 0, argname, false)); 
-	}
-
-	foreach(lc, x->args)
-	{
-		Node	   *e = (Node *) lfirst(lc);
-		Node	   *newe;
-
-		newe = coerce_to_xml(pstate, transformExpr(pstate, e),
-							 (x->op == IS_XMLCONCAT 
-							  ? "XMLCONCAT"
-							  : (x->op == IS_XMLELEMENT
-								 ? "XMLELEMENT"
-								 : "XMLFOREST")));
-		newx->args = lappend(newx->args, newe);
-	}
-		
-	return (Node *) newx;
-}
-
 /*
  * Construct a whole-row reference to represent the notation "relation.*".
  *
@@ -1715,6 +1766,9 @@ exprType(Node *expr)
 		case T_MinMaxExpr:
 			type = ((MinMaxExpr *) expr)->minmaxtype;
 			break;
+		case T_XmlExpr:
+			type = XMLOID;
+			break;
 		case T_NullIfExpr:
 			type = exprType((Node *) linitial(((NullIfExpr *) expr)->args));
 			break;
@@ -1724,9 +1778,6 @@ exprType(Node *expr)
 		case T_BooleanTest:
 			type = BOOLOID;
 			break;
-		case T_XmlExpr:
-			type = XMLOID;
-			break;
 		case T_CoerceToDomain:
 			type = ((CoerceToDomain *) expr)->resulttype;
 			break;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 906d96e45c6c6f069476dae44952c5236819a0b5..ef4b9083ac652c702aef78cf4e9e727c94ad0d02 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.150 2006/12/21 16:05:14 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.151 2006/12/24 00:29:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1328,6 +1328,15 @@ FigureColnameInternal(Node *node, char **name)
 				case IS_XMLFOREST:
 					*name = "xmlforest";
 					return 2;
+				case IS_XMLPARSE:
+					*name = "xmlparse";
+					return 2;
+				case IS_XMLPI:
+					*name = "xmlpi";
+					return 2;
+				case IS_XMLROOT:
+					*name = "xmlroot";
+					return 2;
 			} 
 			break;
 		default:
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index b2ff95f457b758576b38504e6a1355384b87ec95..699b4a9370462431f72d0b6223fae151cf3da660 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2,7 +2,7 @@
  * ruleutils.c	- Functions to convert stored expressions/querytrees
  *				back to source text
  *
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.237 2006/12/23 00:43:11 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.238 2006/12/24 00:29:19 tgl Exp $
  **********************************************************************/
 
 #include "postgres.h"
@@ -2988,8 +2988,8 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
 		case T_RowExpr:
 		case T_CoalesceExpr:
 		case T_MinMaxExpr:
-		case T_NullIfExpr:
 		case T_XmlExpr:
+		case T_NullIfExpr:
 		case T_Aggref:
 		case T_FuncExpr:
 			/* function-like: name(..) or name[..] */
@@ -3097,8 +3097,8 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
 				case T_RowExpr:	/* other separators */
 				case T_CoalesceExpr:	/* own parentheses */
 				case T_MinMaxExpr:		/* own parentheses */
-				case T_NullIfExpr:		/* other separators */
 				case T_XmlExpr:			/* own parentheses */
+				case T_NullIfExpr:		/* other separators */
 				case T_Aggref:	/* own parentheses */
 				case T_CaseExpr:		/* other separators */
 					return true;
@@ -3146,8 +3146,8 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
 				case T_RowExpr:	/* other separators */
 				case T_CoalesceExpr:	/* own parentheses */
 				case T_MinMaxExpr:		/* own parentheses */
-				case T_NullIfExpr:		/* other separators */
 				case T_XmlExpr:			/* own parentheses */
+				case T_NullIfExpr:		/* other separators */
 				case T_Aggref:	/* own parentheses */
 				case T_CaseExpr:		/* other separators */
 					return true;
@@ -3779,6 +3779,140 @@ get_rule_expr(Node *node, deparse_context *context,
 			}
 			break;
 
+		case T_XmlExpr:
+			{
+				XmlExpr *xexpr = (XmlExpr *) node;
+				bool	needcomma = false;
+				ListCell   *arg;
+				ListCell   *narg;
+				Const	   *con;
+
+				switch (xexpr->op)
+				{
+					case IS_XMLCONCAT:
+						appendStringInfoString(buf, "XMLCONCAT(");
+						break;
+					case IS_XMLELEMENT:
+						appendStringInfoString(buf, "XMLELEMENT(");
+						break;
+					case IS_XMLFOREST:
+						appendStringInfoString(buf, "XMLFOREST(");
+						break;
+					case IS_XMLPARSE:
+						appendStringInfoString(buf, "XMLPARSE(");
+						break;
+					case IS_XMLPI:
+						appendStringInfoString(buf, "XMLPI(");
+						break;
+					case IS_XMLROOT:
+						appendStringInfoString(buf, "XMLROOT(");
+						break;
+				}
+				if (xexpr->name)
+				{
+					/*
+					 * XXX need to de-escape the name
+					 */
+					appendStringInfo(buf, "NAME %s",
+									 quote_identifier(xexpr->name));
+					needcomma = true;
+				}
+				if (xexpr->named_args)
+				{
+					if (xexpr->op != IS_XMLFOREST)
+					{
+						if (needcomma)
+							appendStringInfoString(buf, ", ");
+						appendStringInfoString(buf, "XMLATTRIBUTES(");
+						needcomma = false;
+					}
+					forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
+					{
+						Node 	*e = (Node *) lfirst(arg);
+						char	*argname = strVal(lfirst(narg));
+
+						if (needcomma)
+							appendStringInfoString(buf, ", ");
+						get_rule_expr((Node *) e, context, true);
+						/*
+						 * XXX need to de-escape the name
+						 */
+						appendStringInfo(buf, " AS %s",
+										 quote_identifier(argname));
+						needcomma = true;
+					}
+					if (xexpr->op != IS_XMLFOREST)
+						appendStringInfoChar(buf, ')');
+				}
+				if (xexpr->args)
+				{
+					if (needcomma)
+						appendStringInfoString(buf, ", ");
+					switch (xexpr->op)
+					{
+						case IS_XMLCONCAT:
+						case IS_XMLELEMENT:
+						case IS_XMLFOREST:
+						case IS_XMLPI:
+							/* 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 ");
+
+							get_rule_expr((Node *) linitial(xexpr->args),
+										  context, true);
+
+							con = (Const *) lthird(xexpr->args);
+							Assert(IsA(con, Const));
+							Assert(!con->constisnull);
+							if (DatumGetBool(con->constvalue))
+								appendStringInfoString(buf,
+													   " PRESERVE WHITESPACE");
+							else
+								appendStringInfoString(buf,
+													   " STRIP WHITESPACE");
+							break;
+						case IS_XMLROOT:
+							Assert(list_length(xexpr->args) == 3);
+
+							get_rule_expr((Node *) linitial(xexpr->args),
+										  context, true);
+
+							appendStringInfoString(buf, ", VERSION ");
+							con = (Const *) lsecond(xexpr->args);
+							if (IsA(con, Const) &&
+								con->constisnull)
+								appendStringInfoString(buf, "NO VALUE");
+							else
+								get_rule_expr((Node *) con, context, false);
+
+							con = (Const *) lthird(xexpr->args);
+							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");
+							break;
+					}
+
+				}
+				appendStringInfoChar(buf, ')');
+			}
+			break;
+
 		case T_NullIfExpr:
 			{
 				NullIfExpr *nullifexpr = (NullIfExpr *) node;
@@ -3849,28 +3983,6 @@ get_rule_expr(Node *node, deparse_context *context,
 			}
 			break;
 
-		case T_XmlExpr:
-			{
-				XmlExpr *xexpr = (XmlExpr *) node;
-
-				switch (xexpr->op)
-				{
-					case IS_XMLCONCAT:
-						appendStringInfo(buf, "XMLCONCAT(");
-						break;
-					case IS_XMLELEMENT:
-						appendStringInfo(buf, "XMLELEMENT(");
-						break;
-					case IS_XMLFOREST:
-						appendStringInfo(buf, "XMLFOREST(");
-						break;
-				}
-				get_rule_expr((Node *) xexpr->named_args, context, true);
-				get_rule_expr((Node *) xexpr->args, context, true);
-				appendStringInfoChar(buf, ')');
-			}
-			break;
-
 		case T_CoerceToDomain:
 			{
 				CoerceToDomain *ctest = (CoerceToDomain *) node;
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index d765c8657fb5a5110ca464b1a4af8e5d5b9be805..a6dc1a6e5f02a876e46add2f20e783b32912e494 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.2 2006/12/23 04:56:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.3 2006/12/24 00:29:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -41,15 +41,6 @@
 
 #ifdef USE_LIBXML
 
-/*
- * A couple of useful macros (similar to ones from libxml/parse.c)
- */
-#define CMP4( s, c1, c2, c3, c4 ) \
-  ( ((unsigned char *) s)[ 0 ] == c1 && ((unsigned char *) s)[ 1 ] == c2 && \
-    ((unsigned char *) s)[ 2 ] == c3 && ((unsigned char *) s)[ 3 ] == c4 )
-#define CMP5( s, c1, c2, c3, c4, c5 ) \
-  ( CMP4( s, c1, c2, c3, c4 ) && ((unsigned char *) s)[ 4 ] == c5 )
-
 #define PG_XML_DEFAULT_URI "dummy.xml"
 #define XML_ERRBUF_SIZE 200
 
@@ -177,31 +168,18 @@ xmlcomment(PG_FUNCTION_ARGS)
 
 
 Datum
-xmlparse(PG_FUNCTION_ARGS)
+texttoxml(PG_FUNCTION_ARGS)
 {
-#ifdef USE_LIBXML
-	text	   *data;
-	bool		is_document;
-	bool		preserve_whitespace;
-
-	data = PG_GETARG_TEXT_P(0);
+	text	   *data = PG_GETARG_TEXT_P(0);
 
-	if (PG_NARGS() >= 2)
-		is_document = PG_GETARG_BOOL(1);
-	else
-		is_document = false;
+	PG_RETURN_XML_P(xmlparse(data, false, true));
+}
 
-	if (PG_NARGS() >= 3)
-		preserve_whitespace = PG_GETARG_BOOL(2);
-	else
-		/*
-		 * Since the XMLPARSE grammar makes STRIP WHITESPACE the
-		 * default, this argument should really default to false.  But
-		 * until we have actually implemented whitespace stripping,
-		 * this would be annoying.
-		 */
-		preserve_whitespace = true;
 
+xmltype *
+xmlparse(text *data, bool is_document, bool preserve_whitespace)
+{
+#ifdef USE_LIBXML
 	if (!preserve_whitespace)
 		ereport(WARNING,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -213,111 +191,93 @@ xmlparse(PG_FUNCTION_ARGS)
 	 * valies defined by internal DTD are applied'.  As for external
 	 * DTDs, we try to support them too, (see SQL/XML:10.16.7.e)
 	 */
-	xml_parse(data, XML_PARSE_DTDATTR, is_document); /* assume that ERROR occurred if parsing failed */
+	xml_parse(data, XML_PARSE_DTDATTR, is_document);
 
-	PG_RETURN_XML_P(data);
+	return (xmltype *) data;
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return NULL;
 #endif
 }
 
 
-Datum
-xmlpi(PG_FUNCTION_ARGS)
+xmltype *
+xmlpi(char *target, text *arg)
 {
 #ifdef USE_LIBXML
-	char	   *target = NameStr(*PG_GETARG_NAME(0));
+	xmltype *result;
 	StringInfoData buf;
 
-	if (strlen(target) >= 3
-		&& (target[0] == 'x' || target[0] == 'X')
-		&& (target[1] == 'm' || target[1] == 'M')
-		&& (target[2] == 'l' || target[2] == 'L'))
-	{
+	if (pg_strncasecmp(target, "xml", 3) == 0)
 		ereport(ERROR,
-				(errcode(ERRCODE_SYNTAX_ERROR),
+				(errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
 				 errmsg("invalid XML processing instruction"),
 				 errdetail("XML processing instruction target name cannot start with \"xml\".")));
-	}
 
 	initStringInfo(&buf);
 
-	appendStringInfo(&buf, "<?");
-	appendStringInfoString(&buf, map_sql_identifier_to_xml_name(target, false));
-	if (PG_NARGS() > 1)
+	appendStringInfo(&buf, "<?%s", target);
+
+	if (arg != NULL)
 	{
-		text *arg = PG_GETARG_TEXT_P(1);
 		char *string;
 
-		string = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(arg)));
-		if (strstr(string, "?>"))
+		string = DatumGetCString(DirectFunctionCall1(textout,
+													 PointerGetDatum(arg)));
+		if (strstr(string, "?>") != NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
 				 errmsg("invalid XML processing instruction"),
 				 errdetail("XML processing instruction cannot contain \"?>\".")));
 
-		appendStringInfoString(&buf, " ");
+		appendStringInfoChar(&buf, ' ');
 		appendStringInfoString(&buf, string);
+		pfree(string);
 	}
 	appendStringInfoString(&buf, "?>");
 
-	PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
+	result = stringinfo_to_xmltype(&buf);
+	pfree(buf.data);
+	return result;
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return NULL;
 #endif
 }
 
 
-Datum
-xmlroot(PG_FUNCTION_ARGS)
+xmltype *
+xmlroot(xmltype *data, text *version, int standalone)
 {
 #ifdef USE_LIBXML
-	xmltype	   *data;
-	text	   *version;
-	int			standalone;
+	xmltype *result;
 	StringInfoData buf;
 
-	if (PG_ARGISNULL(0))
-		PG_RETURN_NULL();
-	else
-		data = PG_GETARG_XML_P(0);
-
-	if (PG_ARGISNULL(1))
-		version = NULL;
-	else
-		version = PG_GETARG_TEXT_P(1);
-
-	if (PG_ARGISNULL(2))
-		standalone = 0;
-	else
-	{
-		bool tmp = PG_GETARG_BOOL(2);
-		standalone = (tmp ? 1 : -1);
-	}
+	initStringInfo(&buf);
 
 	/*
 	 * FIXME: This is probably supposed to be cleverer if there
 	 * already is an XML preamble.
 	 */
-	initStringInfo(&buf);
-
 	appendStringInfo(&buf,"<?xml");
-	if (version) {
+	if (version)
+	{
 		appendStringInfo(&buf, " version=\"");
 		appendStringInfoText(&buf, version);
 		appendStringInfo(&buf, "\"");
 	}
 	if (standalone)
-		appendStringInfo(&buf, " standalone=\"%s\"", (standalone == 1 ? "yes" : "no"));
+		appendStringInfo(&buf, " standalone=\"%s\"",
+						 (standalone == 1 ? "yes" : "no"));
 	appendStringInfo(&buf, "?>");
 	appendStringInfoText(&buf, (text *) data);
 
-	PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
+	result = stringinfo_to_xmltype(&buf);
+	pfree(buf.data);
+	return result;
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return NULL;
 #endif
 }
 
@@ -456,7 +416,7 @@ xml_parse(text *data, int opts, bool is_document)
 
 	/* first, we try to parse the string as XML doc, then, as XML chunk */
 	ereport(DEBUG3, (errmsg("string to parse: %s", string)));
-	if (len > 4 && CMP5(string, '<', '?', 'x', 'm', 'l'))
+	if (len >= 5 && strncmp((char *) string, "<?xml", 5) == 0)
 	{
 		/* consider it as DOCUMENT */
 		doc = xmlCtxtReadMemory(ctxt, (char *) string, len,
@@ -918,10 +878,8 @@ map_sql_identifier_to_xml_name(char *ident, bool fully_escaped)
 			appendStringInfo(&buf, "_x003A_");
 		else if (*p == '_' && *(p+1) == 'x')
 			appendStringInfo(&buf, "_x005F_");
-		else if (fully_escaped && p == ident
-				 && ( *p == 'x' || *p == 'X')
-				 && ( *(p+1) == 'm' || *(p+1) == 'M')
-				 && ( *(p+2) == 'l' || *(p+2) == 'L'))
+		else if (fully_escaped && p == ident &&
+				 pg_strncasecmp(p, "xml", 3) == 0)
 		{
 			if (*p == 'x')
 				appendStringInfo(&buf, "_x0078_");
@@ -932,9 +890,10 @@ map_sql_identifier_to_xml_name(char *ident, bool fully_escaped)
 		{
 			pg_wchar u = sqlchar_to_unicode(p);
 
-			if (!is_valid_xml_namechar(u)
-				|| (p == ident && !is_valid_xml_namefirst(u)))
-			appendStringInfo(&buf, "_x%04X_", (unsigned int) u);
+			if ((p == ident)
+				? !is_valid_xml_namefirst(u)
+				: !is_valid_xml_namechar(u))
+				appendStringInfo(&buf, "_x%04X_", (unsigned int) u);
 			else
 				appendBinaryStringInfo(&buf, p, pg_mblen(p));
 		}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index f0a840a3ddef5d349d23362731a9968b3b167258..68f5a639347d493d242ba5a5e7ca4a9962251a34 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.365 2006/12/23 00:43:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.366 2006/12/24 00:29:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200612221
+#define CATALOG_VERSION_NO	200612231
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 974a2db360ca4c5eca15e02174296ba348be78f6..0a3ccc07f6cd541a7334cc5cae5fd4bf7e857ba4 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.431 2006/12/21 16:05:15 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.432 2006/12/24 00:29:19 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -3983,17 +3983,9 @@ DATA(insert OID = 2894 (  xml_out		   PGNSP PGUID 12 f f t f i 1 2275 "142" _nul
 DESCR("I/O");
 DATA(insert OID = 2895 (  xmlcomment	   PGNSP PGUID 12 f f t f i 1 142 "25" _null_ _null_ _null_ xmlcomment - _null_ ));
 DESCR("generate an XML comment");
-DATA(insert OID = 2896 (  xmlparse		   PGNSP PGUID 12 f f t f i 1 142 "25" _null_ _null_ _null_ xmlparse - _null_ ));
+DATA(insert OID = 2896 (  xml			   PGNSP PGUID 12 f f t f i 1 142 "25" _null_ _null_ _null_ texttoxml - _null_ ));
 DESCR("perform a non-validating parse of a character string to produce an XML value");
-DATA(insert OID = 2897 (  xmlparse		   PGNSP PGUID 12 f f t f i 3 142 "25 16 16" _null_ _null_ _null_ xmlparse - _null_ ));
-DESCR("perform a non-validating parse of a character string to produce an XML value");
-DATA(insert OID = 2898 (  xmlpi			   PGNSP PGUID 12 f f t f i 1 142 "19" _null_ _null_ _null_ xmlpi - _null_ ));
-DESCR("generate an XML processing instruction");
-DATA(insert OID = 2899 (  xmlpi			   PGNSP PGUID 12 f f t f i 2 142 "19 25" _null_ _null_ _null_ xmlpi - _null_ ));
-DESCR("generate an XML processing instruction");
-DATA(insert OID = 2900 (  xmlroot		   PGNSP PGUID 12 f f f f i 3 142 "142 25 16" _null_ _null_ _null_ xmlroot - _null_ ));
-DESCR("create an XML value by modifying the properties of the XML root information item of another XML value");
-DATA(insert OID = 2901 (  xmlvalidate 	   PGNSP PGUID 12 f f t f i 2 16 "142 25" _null_ _null_ _null_ xmlvalidate - _null_ ));
+DATA(insert OID = 2897 (  xmlvalidate 	   PGNSP PGUID 12 f f t f i 2 16 "142 25" _null_ _null_ _null_ xmlvalidate - _null_ ));
 DESCR("validate an XML value");
 
 /*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 1db920aa0c1b0c4836c5b3e32b9d9ea564b123b9..f8e8f15a5dba916194f2b556a51c3d629b5f0579 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.163 2006/12/21 16:05:16 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.164 2006/12/24 00:29:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -710,6 +710,18 @@ typedef struct MinMaxExprState
 	FmgrInfo	cfunc;			/* lookup info for comparison func */
 } MinMaxExprState;
 
+/* ----------------
+ *		XmlExprState node
+ * ----------------
+ */
+typedef struct XmlExprState
+{
+	ExprState	xprstate;
+	List	   *named_args;		/* ExprStates for named arguments */
+	FmgrInfo   *named_outfuncs;	/* array of output fns for named arguments */
+	List	   *args;			/* ExprStates for other arguments */
+} XmlExprState;
+
 /* ----------------
  *		NullTestState node
  * ----------------
@@ -723,22 +735,6 @@ typedef struct NullTestState
 	TupleDesc	argdesc;		/* tupdesc for most recent input */
 } NullTestState;
 
-/* ----------------
- *		XmlExprState node
- * ----------------
- */
-typedef struct XmlExprState
-{
-	ExprState	xprstate;
-	XmlExprOp	op;
-	char	   *name;
-	List	   *named_args;
-	List	   *args;
-	Oid		   *named_args_tcache;
-	char	  **named_args_ncache;
-	Oid			arg_typeout;
-} XmlExprState;
-
 /* ----------------
  *		CoerceToDomainState node
  * ----------------
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index eb6ba18adab390357a05f9865d3b98b570b92b11..fa9dff9d961ba8f7857a31001b80201cf88f10c7 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.189 2006/12/21 16:05:16 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.190 2006/12/24 00:29:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -130,6 +130,7 @@ typedef enum NodeTag
 	T_RowCompareExpr,
 	T_CoalesceExpr,
 	T_MinMaxExpr,
+	T_XmlExpr,
 	T_NullIfExpr,
 	T_NullTest,
 	T_BooleanTest,
@@ -140,7 +141,6 @@ typedef enum NodeTag
 	T_RangeTblRef,
 	T_JoinExpr,
 	T_FromExpr,
-	T_XmlExpr,
 
 	/*
 	 * TAGS FOR EXPRESSION STATE NODES (execnodes.h)
@@ -166,10 +166,10 @@ typedef enum NodeTag
 	T_RowCompareExprState,
 	T_CoalesceExprState,
 	T_MinMaxExprState,
+	T_XmlExprState,
 	T_NullTestState,
 	T_CoerceToDomainState,
 	T_DomainConstraintState,
-	T_XmlExprState,
 
 	/*
 	 * TAGS FOR PLANNER NODES (relation.h)
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 5946300c9751fdc4a359dc421a8a6b8dce53f4f2..bd2c39040fc1253853650eeed5dbd43e51fc967d 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.120 2006/12/23 00:43:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.121 2006/12/24 00:29:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -711,6 +711,33 @@ typedef struct MinMaxExpr
 	List	   *args;			/* the arguments */
 } MinMaxExpr;
 
+/*
+ * XmlExpr - various SQL/XML functions requiring special grammar productions
+ *
+ * 'name' carries the "NAME foo" argument (already XML-escaped).
+ * 'named_args' and 'arg_names' represent an xml_attribute list.
+ * 'args' carries all other arguments.
+ */
+typedef enum XmlExprOp
+{
+	IS_XMLCONCAT,				/* XMLCONCAT(args) */
+	IS_XMLELEMENT,				/* XMLELEMENT(name, xml_attributes, args) */
+	IS_XMLFOREST,				/* XMLFOREST(xml_attributes) */
+	IS_XMLPARSE,				/* XMLPARSE(text, is_doc, preserve_ws) */
+	IS_XMLPI,					/* XMLPI(name [, args]) */
+	IS_XMLROOT					/* XMLROOT(xml, version, standalone) */
+} XmlExprOp;
+
+typedef struct XmlExpr
+{
+	Expr		xpr;
+	XmlExprOp	op;				/* xml function ID */
+	char	   *name;			/* name in xml(NAME foo ...) syntaxes */
+	List	   *named_args;		/* non-XML expressions for xml_attributes */
+	List	   *arg_names;		/* parallel list of Value strings */
+	List	   *args;			/* list of expressions */
+} XmlExpr;
+
 /*
  * NullIfExpr - a NULLIF expression
  *
@@ -765,26 +792,6 @@ typedef struct BooleanTest
 	BoolTestType booltesttype;	/* test type */
 } BooleanTest;
 
-/*
- * XmlExpr - holder for SQL/XML functions XMLCONCAT,
- * XMLELEMENT, XMLFOREST
- */
-typedef enum XmlExprOp
-{
-	IS_XMLCONCAT,
-	IS_XMLELEMENT,
-	IS_XMLFOREST,
-} XmlExprOp;
-
-typedef struct XmlExpr
-{
-	Expr		xpr;
-	XmlExprOp	op;				/* xml expression type */
-	char	   *name;			/* element name */
-	List	   *named_args;
-	List	   *args;
-} XmlExpr;
-
 /*
  * CoerceToDomain
  *
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index 9c077095e9e563822fff96fd50244bb74fec66f7..08573abd1ef422a9e75b34e7c682c3a1bf4c1ae2 100644
--- a/src/include/parser/parse_coerce.h
+++ b/src/include/parser/parse_coerce.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.67 2006/12/21 16:05:16 petere Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.68 2006/12/24 00:29:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,12 +55,9 @@ extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod,
 
 extern Node *coerce_to_boolean(ParseState *pstate, Node *node,
 				  const char *constructName);
-extern Node *coerce_to_integer(ParseState *pstate, Node *node,
-				  const char *constructName);
-extern Node *coerce_to_bigint(ParseState *pstate, Node *node,
-				 const char *constructName);
-extern Node *coerce_to_xml(ParseState *pstate, Node *node,
-				 const char *constructName);
+extern Node *coerce_to_specific_type(ParseState *pstate, Node *node,
+									 Oid targetTypeId,
+									 const char *constructName);
 
 extern Oid	select_common_type(List *typeids, const char *context);
 extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index a353d8837c93268aff4acd8aec7045ae8aef7804..713bdaeb115259f402ed1e62909a1f49543bc05b 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.2 2006/12/23 04:56:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.3 2006/12/24 00:29:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,11 +27,13 @@ typedef struct varlena xmltype;
 extern Datum xml_in(PG_FUNCTION_ARGS);
 extern Datum xml_out(PG_FUNCTION_ARGS);
 extern Datum xmlcomment(PG_FUNCTION_ARGS);
-extern Datum xmlparse(PG_FUNCTION_ARGS);
-extern Datum xmlpi(PG_FUNCTION_ARGS);
-extern Datum xmlroot(PG_FUNCTION_ARGS);
+extern Datum texttoxml(PG_FUNCTION_ARGS);
 extern Datum xmlvalidate(PG_FUNCTION_ARGS);
 
+extern xmltype *xmlparse(text *data, bool is_doc, bool preserve_whitespace);
+extern xmltype *xmlpi(char *target, text *arg);
+extern xmltype *xmlroot(xmltype *data, text *version, int standalone);
+
 extern char *map_sql_identifier_to_xml_name(char *ident, bool fully_escaped);
 
 #endif /* XML_H */
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index c28c2c6c8f3597a5535029b383afb6c3c23bc94e..bff815206169bc37e874743d859accc4aeaf6e19 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.180 2006/10/04 00:30:13 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.181 2006/12/24 00:29:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -4493,6 +4493,18 @@ exec_simple_check_node(Node *node)
 				return TRUE;
 			}
 
+		case T_XmlExpr:
+			{
+				XmlExpr *expr = (XmlExpr *) node;
+
+				if (!exec_simple_check_node((Node *) expr->named_args))
+					return FALSE;
+				if (!exec_simple_check_node((Node *) expr->args))
+					return FALSE;
+
+				return TRUE;
+			}
+
 		case T_NullIfExpr:
 			{
 				NullIfExpr *expr = (NullIfExpr *) node;
diff --git a/src/pl/plpgsql/src/plerrcodes.h b/src/pl/plpgsql/src/plerrcodes.h
index 478bf3b080683a8ca5526c450c198291946b465c..ba0c229ccd14be2d30d8ad71e6b72cab22fd1397 100644
--- a/src/pl/plpgsql/src/plerrcodes.h
+++ b/src/pl/plpgsql/src/plerrcodes.h
@@ -9,7 +9,7 @@
  *
  * Copyright (c) 2003-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plerrcodes.h,v 1.9 2006/06/16 23:29:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plerrcodes.h,v 1.10 2006/12/24 00:29:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -243,6 +243,22 @@
 	"untranslatable_character", ERRCODE_UNTRANSLATABLE_CHARACTER
 },
 
+{
+	"invalid_xml_document", ERRCODE_INVALID_XML_DOCUMENT
+},
+
+{
+	"invalid_xml_content", ERRCODE_INVALID_XML_CONTENT
+},
+
+{
+	"invalid_xml_comment", ERRCODE_INVALID_XML_COMMENT
+},
+
+{
+	"invalid_xml_processing_instruction", ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION
+},
+
 {
 	"integrity_constraint_violation", ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION
 },
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index a0e9483ebd0b172d65474078b1e34175670b7e21..7bfa35a46f8c4c25e5c1059ca8ed2d9d40e3e962 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -74,7 +74,7 @@ WHERE p1.oid != p2.oid AND
 SELECT p1.oid, p1.proname, p2.oid, p2.proname
 FROM pg_proc AS p1, pg_proc AS p2
 WHERE p1.oid < p2.oid AND
-    p1.prosrc = p2.prosrc AND p1.prosrc NOT IN ('xmlparse', 'xmlpi') AND
+    p1.prosrc = p2.prosrc AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     (p1.proisagg = false OR p2.proisagg = false) AND
     (p1.prolang != p2.prolang OR
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 4dd39eb164e8ed8a5717ccce590e194b83c8609a..b8c184f784b41804cca26365792c36fab55e63cd 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -77,7 +77,7 @@ WHERE p1.oid != p2.oid AND
 SELECT p1.oid, p1.proname, p2.oid, p2.proname
 FROM pg_proc AS p1, pg_proc AS p2
 WHERE p1.oid < p2.oid AND
-    p1.prosrc = p2.prosrc AND p1.prosrc NOT IN ('xmlparse', 'xmlpi') AND
+    p1.prosrc = p2.prosrc AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     (p1.proisagg = false OR p2.proisagg = false) AND
     (p1.prolang != p2.prolang OR