diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 94fc8fd79aa45388f73215f3466dd0f4e894d1f3..2a95d8fae73e06379d592679cdc5f6e512f7caca 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.105 2007/01/25 04:35:10 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.106 2007/01/25 11:53:50 petere Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -3558,6 +3558,38 @@ SELECT * FROM parent WHERE key = 2400;
       </listitem>
      </varlistentry>
      
+     <varlistentry id="guc-xmloption" xreflabel="xmloption">
+      <term><varname>xmloption</varname> (<type>string</type>)</term>
+      <indexterm>
+       <primary><varname>xmloption</> configuration parameter</primary>
+      </indexterm>
+      <indexterm>
+       <primary><varname>SET XML OPTION</></primary>
+      </indexterm>
+      <indexterm>
+       <primary><varname>XML option</></primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Sets whether <literal>DOCUMENT</literal> or
+        <literal>CONTENT</literal> is implicit when converting between
+        XML and character string values.  See <xref
+        linkend="datatype-xml"> for a description of this.  Valid
+        values are <literal>DOCUMENT</literal> and
+        <literal>CONTENT</literal>.  The default is
+        <literal>CONTENT</literal>.
+       </para>
+
+       <para>
+        According to the SQL standard, the command to set this option is
+<synopsis>
+SET XML OPTION { DOCUMENT | CONTENT };
+</synopsis>
+        This syntax is also available in PostgreSQL.
+       </para>
+      </listitem>
+     </varlistentry>
+     
      </variablelist>
     </sect2>
      <sect2 id="runtime-config-client-format">
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 47c2e5c74af35c043b12982222d5dd03ba18e24f..f0ba6c32c715ee3351265b8310f7fbc9d040dadd 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.185 2007/01/18 13:59:11 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.186 2007/01/25 11:53:50 petere Exp $ -->
 
  <chapter id="datatype">
   <title id="datatype-title">Data Types</title>
@@ -3474,6 +3474,24 @@ XMLSERIALIZE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable> AS <repla
     you to simply cast the value.
    </para>
 
+   <para>
+    When character string values are cast to or from type
+    <type>xml</type> without going through <type>XMLPARSE</type> or
+    <type>XMLSERIALIZE</type>, respectively, the choice of
+    <literal>DOCUMENT</literal> versus <literal>CONTENT</literal> is
+    determined by the <quote>XML option</quote> session configuration
+    parameter, which can be set using the standard command
+<synopsis>
+SET XML OPTION { DOCUMENT | CONTENT };
+</synopsis>
+    or the more PostgreSQL-like syntax
+<synopsis>
+SET xmloption TO { DOCUMENT | CONTENT };
+</synopsis>
+    The default is <literal>CONTENT</literal>, so all forms of XML
+    data are allowed.
+   </para>
+
    <para>
     Care must be taken when dealing with multiple character encodings
     on the client, server, and in the XML data passed through them.
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 60f9d35f1f762b908c72320b7e33a46e6a1cf15b..75a9e42a24df3ac1fb97a640990197c6173f73e9 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.208 2007/01/20 09:27:19 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.209 2007/01/25 11:53:50 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2797,10 +2797,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 
 				e = (ExprState *) lthird(xmlExpr->args);
 				value = ExecEvalExpr(e, econtext, &isnull, NULL);
-				if (isnull)
-					standalone = 0;
-				else
-					standalone = (DatumGetBool(value) ? 1 : -1);
+				standalone = DatumGetInt32(value);
 
 				*isNull = false;
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 217b1a0465961e14ea434e5d0d7eeb6c47f893b3..c256d73eadb084c5b1623ae842645b24a4158a2f 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.576 2007/01/23 05:07:17 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.577 2007/01/25 11:53:51 petere Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -60,6 +60,7 @@
 #include "utils/date.h"
 #include "utils/datetime.h"
 #include "utils/numeric.h"
+#include "utils/xml.h"
 
 
 /* Location tracking support --- simpler than bison's default */
@@ -439,7 +440,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
 
 	WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
 
-	XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
+	XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
 	XMLPI XMLROOT XMLSERIALIZE
 
 	YEAR_P YES_P
@@ -1112,6 +1113,13 @@ set_rest:  var_name TO var_list_or_default
 					n->args = NIL;
 					$$ = n;
 				}
+			| XML_P OPTION document_or_content
+				{
+					VariableSetStmt *n = makeNode(VariableSetStmt);
+					n->name = "xmloption";
+					n->args = list_make1(makeStringConst($3 ? "DOCUMENT" : "CONTENT", NULL));
+					$$ = n;
+				}
 		;
 
 var_name:
@@ -7938,21 +7946,13 @@ xml_root_version: VERSION_P a_expr
 		;
 
 opt_xml_root_standalone: ',' STANDALONE_P YES_P
-				{ $$ = (Node *) makeBoolAConst(true); }
+				{ $$ = (Node *) makeIntConst(XML_STANDALONE_YES); }
 			| ',' STANDALONE_P NO
-				{ $$ = (Node *) makeBoolAConst(false); }
+				{ $$ = (Node *) makeIntConst(XML_STANDALONE_NO); }
 			| ',' STANDALONE_P NO VALUE_P
-				{
-					A_Const *val = makeNode(A_Const);
-					val->val.type = T_Null;
-					$$ = (Node *) val;
-				}
+				{ $$ = (Node *) makeIntConst(XML_STANDALONE_NO_VALUE); }
 			| /*EMPTY*/
-				{
-					A_Const *val = makeNode(A_Const);
-					val->val.type = T_Null;
-					$$ = (Node *) val;
-				}
+				{ $$ = (Node *) makeIntConst(XML_STANDALONE_OMITTED); }
 		;
 
 xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')'	{ $$ = $3; }
@@ -8864,6 +8864,7 @@ unreserved_keyword:
 			| WITHOUT
 			| WORK
 			| WRITE
+			| XML_P
 			| YEAR_P
 			| YES_P
 			| ZONE
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index b8607c7c002a3dab01c139212df2a4b808d3ba18..368f3e06947972e98cc00c34508431f6b6b40b3f 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.183 2007/01/23 05:07:18 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.184 2007/01/25 11:53:51 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -380,6 +380,7 @@ static const ScanKeyword ScanKeywords[] = {
 	{"without", WITHOUT},
 	{"work", WORK},
 	{"write", WRITE},
+	{"xml", XML_P},
 	{"xmlattributes", XMLATTRIBUTES},
 	{"xmlconcat", XMLCONCAT},
 	{"xmlelement", XMLELEMENT},
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 394a507f2ef11949206debd9fe396919a44bf2d6..a807ef12de4d36fb29c64c2c01d0de133470a207 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.208 2007/01/14 13:11:53 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.209 2007/01/25 11:53:51 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1481,7 +1481,8 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 					newe = coerce_to_specific_type(pstate, newe, TEXTOID,
 												   "XMLROOT");
 				else
-					newe = coerce_to_boolean(pstate, newe, "XMLROOT");
+					newe = coerce_to_specific_type(pstate, newe, INT4OID,
+												   "XMLROOT");
 				break;
 			case IS_DOCUMENT:
 				newe = coerce_to_specific_type(pstate, newe, XMLOID,
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 3b283d247f0f1688e9fcdeafba15139a85ac3b21..d9a9ce5bc369cf0702eac945c0715d2db0647110 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.21 2007/01/23 23:39:16 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.22 2007/01/25 11:53:51 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -67,11 +67,14 @@ static void 	xml_ereport_by_code(int level, int sqlcode,
 									const char *msg, int errcode);
 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);
 
 #endif /* USE_LIBXML */
 
 XmlBinaryType xmlbinary;
+XmlOptionType xmloption;
+
 
 #define NO_XML_SUPPORT() \
 	ereport(ERROR, \
@@ -97,7 +100,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, false, true, NULL);
+	doc = xml_parse(vardata, (xmloption == XMLOPTION_DOCUMENT), true, NULL);
 	xmlFreeDoc(doc);
 
 	PG_RETURN_XML_P(vardata);
@@ -129,48 +132,13 @@ xml_out_internal(xmltype *x, pg_enc target_encoding)
 	str[len] = '\0';
 
 #ifdef USE_LIBXML
-	/*
-	 * On output, we adjust the XML declaration as follows.  (These
-	 * rules are the moral equivalent of the clause "Serialization of
-	 * an XML value" in the SQL standard.)
-	 *
-	 * We try to avoid generating an XML declaration if possible.
-	 * This is so that you don't get trivial things like xml '<foo/>'
-	 * resulting in '<?xml version="1.0"?><foo/>', which would surely
-	 * be annoying.  We must provide a declaration if the standalone
-	 * property is specified or if we include an encoding
-	 * specification.  If we have a declaration, we must specify a
-	 * version (XML requires this).  Otherwise we only make a
-	 * declaration if the version is not "1.0", which is the default
-	 * version specified in SQL:2003.
-	 */
 	if ((res_code = parse_xml_decl((xmlChar *) str, &len, &version, &encoding, &standalone)) == 0)
 	{
 		StringInfoData buf;
 
 		initStringInfo(&buf);
 
-		if ((version && strcmp((char *) version, PG_XML_DEFAULT_VERSION) != 0)
-			|| (target_encoding && target_encoding != PG_UTF8)
-			|| standalone != -1)
-		{
-			appendStringInfoString(&buf, "<?xml");
-			if (version)
-				appendStringInfo(&buf, " version=\"%s\"", version);
-			else
-				appendStringInfo(&buf, " version=\"%s\"", PG_XML_DEFAULT_VERSION);
-			if (target_encoding && target_encoding != PG_UTF8)
-				/* XXX might be useful to convert this to IANA names
-				 * (ISO-8859-1 instead of LATIN1 etc.); needs field
-				 * experience */
-				appendStringInfo(&buf, " encoding=\"%s\"", pg_encoding_to_char(target_encoding));
-			if (standalone == 1)
-				appendStringInfoString(&buf, " standalone=\"yes\"");
-			else if (standalone == 0)
-				appendStringInfoString(&buf, " standalone=\"no\"");
-			appendStringInfoString(&buf, "?>");
-		}
-		else
+		if (!print_xml_decl(&buf, version, target_encoding, standalone))
 		{
 			/*
 			 * If we are not going to produce an XML declaration, eat
@@ -231,7 +199,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, false, true, encoding);
+	doc = xml_parse(result, (xmloption == XMLOPTION_DOCUMENT), true, encoding);
 	xmlFreeDoc(doc);
 
 	newstr = (char *) pg_do_encoding_conversion((unsigned char *) str,
@@ -296,6 +264,7 @@ stringinfo_to_xmltype(StringInfo buf)
 }
 
 
+#ifdef NOT_USED
 static xmltype *
 cstring_to_xmltype(const char *string)
 {
@@ -309,6 +278,7 @@ cstring_to_xmltype(const char *string)
 
 	return result;
 }
+#endif
 
 
 static xmltype *
@@ -394,9 +364,11 @@ xmlconcat(List *args)
 		if (standalone < 0)
 			global_standalone = -1;
 
-		if (!global_version)
+		if (!version)
+			global_version_no_value = true;
+		else if (!global_version)
 			global_version = xmlStrdup(version);
-		else if (version && xmlStrcmp(version, global_version) != 0)
+		else if (xmlStrcmp(version, global_version) != 0)
 			global_version_no_value = true;
 
 		appendStringInfoString(&buf, str + len);
@@ -409,17 +381,10 @@ xmlconcat(List *args)
 
 		initStringInfo(&buf2);
 
-		if (!global_version_no_value && global_version)
-			appendStringInfo(&buf2, "<?xml version=\"%s\"", global_version);
-		else
-			appendStringInfo(&buf2, "<?xml version=\"%s\"", PG_XML_DEFAULT_VERSION);
-
-		if (global_standalone == 1)
-			appendStringInfoString(&buf2, " standalone=\"yes\"");
-		else if (global_standalone == 0)
-			appendStringInfoString(&buf2, " standalone=\"no\"");
-
-		appendStringInfoString(&buf2, "?>");
+		print_xml_decl(&buf2,
+					   (!global_version_no_value && global_version) ? global_version : NULL,
+					   0,
+					   global_standalone);
 
 		appendStringInfoString(&buf2, buf.data);
 		buf = buf2;
@@ -458,7 +423,7 @@ texttoxml(PG_FUNCTION_ARGS)
 {
 	text	   *data = PG_GETARG_TEXT_P(0);
 
-	PG_RETURN_XML_P(xmlparse(data, false, true));
+	PG_RETURN_XML_P(xmlparse(data, (xmloption == XMLOPTION_DOCUMENT), true));
 }
 
 
@@ -595,44 +560,45 @@ xmltype *
 xmlroot(xmltype *data, text *version, int standalone)
 {
 #ifdef USE_LIBXML
-	xmltype	   *result;
-	xmlDocPtr	doc;
-	xmlBufferPtr buffer;
-	xmlSaveCtxtPtr save;
+	char	   *str;
+	size_t		len;
+	xmlChar	   *orig_version;
+	int			orig_standalone;
+	StringInfoData buf;
 
-	doc = xml_parse((text *) data, true, true, NULL);
+	len = VARSIZE(data) - VARHDRSZ;
+	str = palloc(len + 1);
+	memcpy(str, VARDATA(data), len);
+	str[len] = '\0';
+
+	parse_xml_decl((xmlChar *) str, &len, &orig_version, NULL, &orig_standalone);
 
 	if (version)
-		doc->version = xmlStrdup(xml_text2xmlChar(version));
+		orig_version = xml_text2xmlChar(version);
 	else
-		doc->version = NULL;
+		orig_version = NULL;
 
 	switch (standalone)
 	{
-		case 1:
-			doc->standalone = 1;
+		case XML_STANDALONE_YES:
+			orig_standalone = 1;
+			break;
+		case XML_STANDALONE_NO:
+			orig_standalone = 0;
 			break;
-		case -1:
-			doc->standalone = 0;
+		case XML_STANDALONE_NO_VALUE:
+			orig_standalone = -1;
 			break;
-		default:
-			doc->standalone = -1;
+		case XML_STANDALONE_OMITTED:
+			/* leave original value */
 			break;
 	}
 
-	buffer = xmlBufferCreate();
-	save = xmlSaveToBuffer(buffer, "UTF-8", 0);
-	xmlSaveDoc(save, doc);
-	xmlSaveClose(save);
-
-	xmlFreeDoc(doc);
+	initStringInfo(&buf);
+	print_xml_decl(&buf, orig_version, 0, orig_standalone);
+	appendStringInfoString(&buf, str + len);
 
-	result = cstring_to_xmltype((char *) pg_do_encoding_conversion((unsigned char *) xmlBufferContent(buffer),
-																   xmlBufferLength(buffer),
-																   PG_UTF8,
-																   GetDatabaseEncoding()));
-	xmlBufferFree(buffer);
-	return result;
+	return stringinfo_to_xmltype(&buf);
 #else
 	NO_XML_SUPPORT();
 	return NULL;
@@ -971,6 +937,53 @@ finished:
 }
 
 
+/*
+ * Write an XML declaration.  On output, we adjust the XML declaration
+ * as follows.  (These rules are the moral equivalent of the clause
+ * "Serialization of an XML value" in the SQL standard.)
+ *
+ * We try to avoid generating an XML declaration if possible.  This is
+ * so that you don't get trivial things like xml '<foo/>' resulting in
+ * '<?xml version="1.0"?><foo/>', which would surely be annoying.  We
+ * must provide a declaration if the standalone property is specified
+ * or if we include an encoding declaration.  If we have a
+ * declaration, we must specify a version (XML requires this).
+ * Otherwise we only make a declaration if the version is not "1.0",
+ * which is the default version specified in SQL:2003.
+ */
+static bool
+print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone)
+{
+	if ((version && strcmp((char *) version, PG_XML_DEFAULT_VERSION) != 0)
+		|| (encoding && encoding != PG_UTF8)
+		|| standalone != -1)
+	{
+		appendStringInfoString(buf, "<?xml");
+
+		if (version)
+			appendStringInfo(buf, " version=\"%s\"", version);
+		else
+			appendStringInfo(buf, " version=\"%s\"", PG_XML_DEFAULT_VERSION);
+
+		if (encoding && encoding != PG_UTF8)
+			/* XXX might be useful to convert this to IANA names
+			 * (ISO-8859-1 instead of LATIN1 etc.); needs field
+			 * experience */
+			appendStringInfo(buf, " encoding=\"%s\"", pg_encoding_to_char(encoding));
+
+		if (standalone == 1)
+			appendStringInfoString(buf, " standalone=\"yes\"");
+		else if (standalone == 0)
+			appendStringInfoString(buf, " standalone=\"no\"");
+		appendStringInfoString(buf, "?>");
+
+		return true;
+	}
+	else
+		return false;
+}
+
+
 /*
  * Convert a C string to XML internal representation
  *
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 9f2cdc43f77130bd28be296cd6105e6f1b7b5c3d..dad28983336307855599440d7f944ec38737b0cd 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.370 2007/01/25 04:35:11 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.371 2007/01/25 11:53:51 petere Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -145,6 +145,7 @@ static const char *assign_canonical_path(const char *newval, bool doit, GucSourc
 static const char *assign_backslash_quote(const char *newval, bool doit, GucSource source);
 static const char *assign_timezone_abbreviations(const char *newval, bool doit, GucSource source);
 static const char *assign_xmlbinary(const char *newval, bool doit, GucSource source);
+static const char *assign_xmloption(const char *newval, bool doit, GucSource source);
 
 static bool assign_tcp_keepalives_idle(int newval, bool doit, GucSource source);
 static bool assign_tcp_keepalives_interval(int newval, bool doit, GucSource source);
@@ -233,6 +234,7 @@ static char *XactIsoLevel_string;
 static char *data_directory;
 static char *custom_variable_classes;
 static char *xmlbinary_string;
+static char *xmloption_string;
 static int	max_function_args;
 static int	max_index_keys;
 static int	max_identifier_length;
@@ -2292,6 +2294,16 @@ static struct config_string ConfigureNamesString[] =
 		"base64", assign_xmlbinary, NULL
 	},
 
+	{
+		{"xmloption", PGC_USERSET, CLIENT_CONN_STATEMENT,
+			gettext_noop("Sets whether XML data in implicit parsing and serialization "
+						 "operations is to be considered as documents or content fragments."),
+			gettext_noop("Valid values are DOCUMENT and CONTENT.")
+		},
+		&xmloption_string,
+		"content", assign_xmloption, NULL
+	},
+
 	{
 		{"temp_tablespaces", PGC_USERSET, PGC_S_FILE,
 			gettext_noop("Sets the tablespaces suitable for creating new objects and sort files."),
@@ -6516,6 +6528,24 @@ assign_xmlbinary(const char *newval, bool doit, GucSource source)
 	return newval;
 }
 
+static const char *
+assign_xmloption(const char *newval, bool doit, GucSource source)
+{
+	XmlOptionType xo;
+
+	if (pg_strcasecmp(newval, "document") == 0)
+		xo = XMLOPTION_DOCUMENT;
+	else if (pg_strcasecmp(newval, "content") == 0)
+		xo = XMLOPTION_CONTENT;
+	else
+		return NULL;			/* reject */
+
+	if (doit)
+		xmloption = xo;
+
+	return newval;
+}
+
 static bool
 assign_tcp_keepalives_idle(int newval, bool doit, GucSource source)
 {
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 3b9730c75bbf07ab3b0fad7ce330fbf713624c87..b3c24fb2c5f538c412280b0cc75a1eabb97bfbfb 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -406,6 +406,8 @@
 #default_transaction_read_only = off
 #statement_timeout = 0			# 0 is disabled
 #vacuum_freeze_min_age = 100000000
+#xmlbinary = 'base64'
+#xmloption = 'content'
 
 # - Locale and Formatting -
 
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index b580fffd82c04494b8162ae754dff5d57112c154..f5b33512cfdfc0f1b720099a71050e5d4880509b 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.12 2007/01/20 09:27:20 petere Exp $
+ * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.13 2007/01/25 11:53:51 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,6 +34,14 @@ extern Datum xmlconcat2(PG_FUNCTION_ARGS);
 extern Datum texttoxml(PG_FUNCTION_ARGS);
 extern Datum xmlvalidate(PG_FUNCTION_ARGS);
 
+typedef enum
+{
+	XML_STANDALONE_YES,
+	XML_STANDALONE_NO,
+	XML_STANDALONE_NO_VALUE,
+	XML_STANDALONE_OMITTED
+} XmlStandaloneType;
+
 extern xmltype *xmlconcat(List *args);
 extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
 extern xmltype *xmlparse(text *data, bool is_doc, bool preserve_whitespace);
@@ -53,4 +61,12 @@ 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/xml.out b/src/test/regress/expected/xml.out
index d91d76530361db24f63442645ba977731f15b22d..0c08667706884fc334e90276c307b40fc9ca2ad6 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -53,13 +53,19 @@ SELECT xmlconcat('hello', 'you');
 (1 row)
 
 SELECT xmlconcat(1, 2);
-ERROR:  argument of XMLCONCAT must be type xml, not type integer
+ERROR:  argument of XMLCONCAT must be type "xml", not type integer
 SELECT xmlconcat('bad', '<syntax');
 ERROR:  invalid XML content
 DETAIL:  Entity: line 1: parser error : Couldn't find end of Start Tag syntax line 1
 <syntax
        ^
 SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
+  xmlconcat   
+--------------
+ <foo/><bar/>
+(1 row)
+
+SELECT xmlconcat('<?xml version="1.1"?><foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
              xmlconcat             
 -----------------------------------
  <?xml version="1.1"?><foo/><bar/>
@@ -205,23 +211,48 @@ SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
  xmlroot 
 ---------
  <foo/>
- 
 (1 row)
 
 SELECT xmlroot(xml '<foo/>', version '2.0');
-        xmlroot        
------------------------
- <?xml version="2.0"?>
- <foo/>
- 
+           xmlroot           
+-----------------------------
+ <?xml version="2.0"?><foo/>
+(1 row)
+
+SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
+                   xmlroot                    
+----------------------------------------------
+ <?xml version="1.0" standalone="yes"?><foo/>
+(1 row)
+
+SELECT xmlroot(xml '<?xml version="1.1"?><foo/>', version no value, standalone yes);
+                   xmlroot                    
+----------------------------------------------
+ <?xml version="1.0" standalone="yes"?><foo/>
 (1 row)
 
 SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no);
-                xmlroot                
----------------------------------------
- <?xml version="1.1" standalone="no"?>
+                   xmlroot                   
+---------------------------------------------
+ <?xml version="1.1" standalone="no"?><foo/>
+(1 row)
+
+SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no);
+                   xmlroot                   
+---------------------------------------------
+ <?xml version="1.0" standalone="no"?><foo/>
+(1 row)
+
+SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no value);
+ xmlroot 
+---------
  <foo/>
- 
+(1 row)
+
+SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value);
+                   xmlroot                    
+----------------------------------------------
+ <?xml version="1.0" standalone="yes"?><foo/>
 (1 row)
 
 SELECT xmlroot (
@@ -239,11 +270,9 @@ SELECT xmlroot (
   version '1.0',
   standalone yes
 );
-                      xmlroot                       
-----------------------------------------------------
- <?xml version="1.0" standalone="yes"?>
- <gazonk name="val" num="2"><qux>foo</qux></gazonk>
- 
+                                         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;
@@ -313,3 +342,29 @@ SELECT xmlpi(name "123");
  <?_x0031_23?>
 (1 row)
 
+PREPARE foo (xml) AS SELECT xmlconcat('<foo/>', $1);
+SET XML OPTION DOCUMENT;
+EXECUTE foo ('<bar/>');
+  xmlconcat   
+--------------
+ <foo/><bar/>
+(1 row)
+
+EXECUTE foo ('bad');
+ERROR:  invalid XML document
+DETAIL:  Entity: line 1: parser error : Start tag expected, '<' not found
+bad
+^
+SET XML OPTION CONTENT;
+EXECUTE foo ('<bar/>');
+  xmlconcat   
+--------------
+ <foo/><bar/>
+(1 row)
+
+EXECUTE foo ('good');
+ xmlconcat  
+------------
+ <foo/>good
+(1 row)
+
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index dd35f1bf4e71a5405d3181a61e3f1c199be4ea86..89124ebb98e2874c738b2d2108e9f74896e33799 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -30,11 +30,13 @@ ERROR:  no XML support in this installation
 SELECT xmlconcat('hello', 'you');
 ERROR:  no XML support in this installation
 SELECT xmlconcat(1, 2);
-ERROR:  argument of XMLCONCAT must be type xml, not type integer
+ERROR:  argument of XMLCONCAT must be type "xml", not type integer
 SELECT xmlconcat('bad', '<syntax');
 ERROR:  no XML support in this installation
 SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
 ERROR:  no XML support in this installation
+SELECT xmlconcat('<?xml version="1.1"?><foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
+ERROR:  no XML support in this installation
 SELECT xmlelement(name element,
                   xmlattributes (1 as one, 'deuce' as two),
                   'content');
@@ -92,8 +94,18 @@ SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
 ERROR:  no XML support in this installation
 SELECT xmlroot(xml '<foo/>', version '2.0');
 ERROR:  no XML support in this installation
+SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
+ERROR:  no XML support in this installation
+SELECT xmlroot(xml '<?xml version="1.1"?><foo/>', version no value, standalone yes);
+ERROR:  no XML support in this installation
 SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no);
 ERROR:  no XML support in this installation
+SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no);
+ERROR:  no XML support in this installation
+SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no value);
+ERROR:  no XML support in this installation
+SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value);
+ERROR:  no XML support in this installation
 SELECT xmlroot (
   xmlelement (
     name gazonk,
@@ -144,3 +156,15 @@ SELECT xmlpi(name ":::_xml_abc135.%-&_");
 ERROR:  no XML support in this installation
 SELECT xmlpi(name "123");
 ERROR:  no XML support in this installation
+PREPARE foo (xml) AS SELECT xmlconcat('<foo/>', $1);
+ERROR:  no XML support in this installation
+SET XML OPTION DOCUMENT;
+EXECUTE foo ('<bar/>');
+ERROR:  prepared statement "foo" does not exist
+EXECUTE foo ('bad');
+ERROR:  prepared statement "foo" does not exist
+SET XML OPTION CONTENT;
+EXECUTE foo ('<bar/>');
+ERROR:  prepared statement "foo" does not exist
+EXECUTE foo ('good');
+ERROR:  prepared statement "foo" does not exist
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index 8e321831596b76c4369281afd690e0f9e605cbfb..b3117c2424f2f073451a6b0b9b3a72637b04c06f 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -25,6 +25,7 @@ SELECT xmlconcat('hello', 'you');
 SELECT xmlconcat(1, 2);
 SELECT xmlconcat('bad', '<syntax');
 SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
+SELECT xmlconcat('<?xml version="1.1"?><foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
 
 
 SELECT xmlelement(name element,
@@ -69,7 +70,13 @@ 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);
+SELECT xmlroot(xml '<?xml version="1.1"?><foo/>', version no value, standalone yes);
 SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no);
+SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no);
+SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no value);
+SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value);
+
 
 SELECT xmlroot (
   xmlelement (
@@ -107,3 +114,14 @@ SELECT xmlelement(name employees, xmlagg(xmlelement(name name, name))) FROM emp;
 
 SELECT xmlpi(name ":::_xml_abc135.%-&_");
 SELECT xmlpi(name "123");
+
+
+PREPARE foo (xml) AS SELECT xmlconcat('<foo/>', $1);
+
+SET XML OPTION DOCUMENT;
+EXECUTE foo ('<bar/>');
+EXECUTE foo ('bad');
+
+SET XML OPTION CONTENT;
+EXECUTE foo ('<bar/>');
+EXECUTE foo ('good');