--- src/backend/utils/adt/xml.c	2009-02-28 02:12:16.000000000 -0700
+++ ../git/src/backend/utils/adt/xml.c	2009-02-28 01:35:14.000000000 -0700
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.83 2009/01/07 13:44:37 tgl Exp $
+ * $PostgreSQL$
  *
  *-------------------------------------------------------------------------
  */
@@ -110,6 +110,8 @@
 			   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_with_nodes(text *data, XmlOptionType xmloption_arg,
+		  bool preserve_whitespace, xmlChar * encoding, xmlNodePtr *chunks);
 static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg,
 		  bool preserve_whitespace, xmlChar * encoding);
 static text *xml_xmlnodetoxmltype(xmlNodePtr cur);
@@ -1125,8 +1127,8 @@
  * yet do not use SAX - see xmlreader.c)
  */
 static xmlDocPtr
-xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
-		  xmlChar * encoding)
+xml_parse_with_nodes(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
+		  xmlChar * encoding, xmlNodePtr *chunks)
 {
 	int32		len;
 	xmlChar    *string;
@@ -1185,7 +1187,7 @@
 								res_code);
 
 		res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
-											   utf8string + count, NULL);
+											   utf8string + count, chunks);
 		if (res_code != 0)
 			xml_ereport(ERROR, ERRCODE_INVALID_XML_CONTENT,
 						"invalid XML content");
@@ -1200,6 +1202,15 @@
 	return doc;
 }
 
+static xmlDocPtr
+xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
+		  xmlChar * encoding)
+{
+	return xml_parse_with_nodes(
+		data, xmloption_arg, preserve_whitespace, encoding, NULL
+	);
+}
+
 
 /*
  * xmlChar<->text conversions
@@ -3174,6 +3185,30 @@
 }
 #endif
 
+/*
+ * Provide access to the document's content fragment.
+ */
+static void
+xpathfun_fragment(xmlXPathParserContextPtr ctxt, int nargs)
+{
+	xmlNodeSetPtr nset = NULL;
+	xmlNodePtr cur;
+
+	if (nargs != 0)
+	{
+	   xmlXPathSetArityError(ctxt);
+		return;
+	}
+
+	cur = ctxt->context->node;
+	while (cur != NULL)
+	{
+		nset = xmlXPathNodeSetMerge(nset, xmlXPathNodeSetCreate(cur));
+		cur = cur->next;
+	}
+
+	valuePush(ctxt, xmlXPathWrapNodeSet(nset));
+}
 
 /*
  * Evaluate XPath expression and return array of XML values.
@@ -3193,15 +3228,12 @@
 	xmltype    *data = PG_GETARG_XML_P(1);
 	ArrayType  *namespaces = PG_GETARG_ARRAYTYPE_P(2);
 	ArrayBuildState *astate = NULL;
-	xmlParserCtxtPtr ctxt;
 	xmlDocPtr	doc;
+	xmlNodePtr	chunks;
 	xmlXPathContextPtr xpathctx;
 	xmlXPathCompExprPtr xpathcomp;
 	xmlXPathObjectPtr xpathobj;
-	char	   *datastr;
-	int32		len;
 	int32		xpath_len;
-	xmlChar    *string;
 	xmlChar    *xpath_expr;
 	int			i;
 	int			res_nitems;
@@ -3248,51 +3280,12 @@
 		ns_count = 0;
 	}
 
-	datastr = VARDATA(data);
-	len = VARSIZE(data) - VARHDRSZ;
-	xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ;
-	if (xpath_len == 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DATA_EXCEPTION),
-				 errmsg("empty XPath expression")));
-
 	xml_init();
 
-	/*
-	 * To handle both documents and fragments, regardless of the fact whether
-	 * the XML datum has a single root (XML well-formedness), we wrap the XML
-	 * datum in a dummy element (<x>...</x>) and extend the XPath expression
-	 * accordingly.  To do it, throw away the XML prolog, if any.
-	 */
-	if (len >= 5 &&
-		xmlStrncmp((xmlChar *) datastr, (xmlChar *) "<?xml", 5) == 0)
-	{
-		i = 5;
-		while (i < len &&
-			   !(datastr[i - 1] == '?' && datastr[i] == '>'))
-			i++;
-
-		if (i == len)
-			xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
-						"could not parse XML data");
-
-		++i;
-
-		datastr += i;
-		len -= i;
-	}
-
-	string = (xmlChar *) palloc((len + 8) * sizeof(xmlChar));
-	memcpy(string, "<x>", 3);
-	memcpy(string + 3, datastr, len);
-	memcpy(string + 3 + len, "</x>", 5);
-	len += 7;
-
-	xpath_expr = (xmlChar *) palloc((xpath_len + 3) * sizeof(xmlChar));
-	memcpy(xpath_expr, "/x", 2);
-	memcpy(xpath_expr + 2, VARDATA(xpath_expr_text), xpath_len);
-	xpath_expr[xpath_len + 2] = '\0';
-	xpath_len += 2;
+	xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ;
+	xpath_expr = (xmlChar *) palloc((xpath_len + 1) * sizeof(xmlChar));
+	memcpy(xpath_expr, VARDATA(xpath_expr_text), xpath_len);
+	xpath_expr[xpath_len] = '\0';
 
 	xmlInitParser();
 
@@ -3300,19 +3293,19 @@
 	 * redundant XML parsing (two parsings for the same value during one
 	 * command execution are possible)
 	 */
-	ctxt = xmlNewParserCtxt();
-	if (ctxt == NULL)
-		xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
-					"could not allocate parser context");
-	doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
+	doc = xml_parse_with_nodes(data, xmloption, true, NULL, &chunks);
 	if (doc == NULL)
 		xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
 					"could not parse XML data");
+
 	xpathctx = xmlXPathNewContext(doc);
 	if (xpathctx == NULL)
 		xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
 					"could not allocate XPath context");
-	xpathctx->node = xmlDocGetRootElement(doc);
+
+	xmlXPathRegisterFunc(xpathctx, (xmlChar *) "fragment", (xmlXPathFunction) xpathfun_fragment);
+
+	xpathctx->node = chunks;
 	if (xpathctx->node == NULL)
 		xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
 					"could not find root XML element");
@@ -3376,7 +3369,6 @@
 	xmlXPathFreeObject(xpathobj);
 	xmlXPathFreeContext(xpathctx);
 	xmlFreeDoc(doc);
-	xmlFreeParserCtxt(ctxt);
 
 	if (res_nitems == 0)
 		PG_RETURN_ARRAYTYPE_P(construct_empty_array(XMLOID));
