diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index e3cd95bedd4..a407b4a9000 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.68.2.6 2008/11/10 18:02:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.68.2.7 2009/02/28 19:13:28 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3320,41 +3320,15 @@ xpath(PG_FUNCTION_ARGS)
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 (...) and extend the XPath expression
- * accordingly. To do it, throw away the XML prolog, if any.
- */
- if (len >= 5 &&
- xmlStrncmp((xmlChar *) datastr, (xmlChar *) "'))
- i++;
-
- if (i == len)
- xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
- "could not parse XML data");
-
- ++i;
-
- datastr += i;
- len -= i;
- }
+ /* These extra chars for string and xpath_expr allow for hacks below */
string = (xmlChar *) palloc((len + 8) * sizeof(xmlChar));
- memcpy(string, "", 3);
- memcpy(string + 3, datastr, len);
- memcpy(string + 3 + len, "", 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_expr = (xmlChar *) palloc((xpath_len + 5) * sizeof(xmlChar));
+
+ memcpy (string, datastr, len);
+ string[len] = '\0';
+
xmlInitParser();
@@ -3367,9 +3341,74 @@ xpath(PG_FUNCTION_ARGS)
xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
"could not allocate parser context");
doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
- if (doc == NULL)
- xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
- "could not parse XML data");
+
+ if (doc == NULL || xmlDocGetRootElement(doc) == NULL)
+ {
+
+ /*
+ * In case we have a fragment rather than a well-formed XML document,
+ * which has a single root (XML well-formedness), we try again after
+ * transforming the xml by stripping away the XML prolog, if any, and
+ * wrapping the remainder in a dummy element (...),
+ * and later extending the XPath expression accordingly.
+ */
+ if (len >= 5 &&
+ xmlStrncmp((xmlChar *) datastr, (xmlChar *) "'))
+ i++;
+
+ if (i == len)
+ xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
+ "could not parse XML data");
+
+ ++i;
+
+ datastr += i;
+ len -= i;
+ }
+
+ memcpy(string, "", 3);
+ memcpy(string + 3, datastr, len);
+ memcpy(string + 3 + len, "", 5);
+ len += 7;
+
+ doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
+
+ if (doc == NULL)
+ xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
+ "could not parse XML data");
+
+ /* we already know xpath_len > 0 - see above , so this test is safe */
+
+ if (*VARDATA(xpath_expr_text) == '/')
+ {
+ memcpy(xpath_expr, "/x", 2);
+ memcpy(xpath_expr + 2, VARDATA(xpath_expr_text), xpath_len);
+ xpath_expr[xpath_len + 2] = '\0';
+ xpath_len += 2;
+ }
+ else
+ {
+ memcpy(xpath_expr, "/x//", 4);
+ memcpy(xpath_expr + 4, VARDATA(xpath_expr_text), xpath_len);
+ xpath_expr[xpath_len + 4] = '\0';
+ xpath_len += 4;
+ }
+
+ }
+ else
+ {
+ /*
+ * if we didn't need to mangle the XML, we don't need to mangle the
+ * xpath either.
+ */
+ memcpy(xpath_expr, VARDATA(xpath_expr_text), xpath_len);
+ xpath_expr[xpath_len] = '\0';
+ }
+
xpathctx = xmlXPathNewContext(doc);
if (xpathctx == NULL)
xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,