aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/xml.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/xml.c')
-rw-r--r--src/backend/utils/adt/xml.c86
1 files changed, 66 insertions, 20 deletions
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index eaf5b4d5502..6587f4e4fc9 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.98 2010/07/06 19:18:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.99 2010/08/05 04:21:54 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3295,24 +3295,20 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
/*
- * Evaluate XPath expression and return array of XML values.
+ * Common code for xpath() and xmlexists()
*
- * As we have no support of XQuery sequences yet, this function seems
- * to be the most useful one (array of XML functions plays a role of
- * some kind of substitution for XQuery sequences).
+ * Evaluate XPath expression and return number of nodes in res_items
+ * and array of XML values in astate.
*
* It is up to the user to ensure that the XML passed is in fact
* an XML document - XPath doesn't work easily on fragments without
* a context node being known.
*/
-Datum
-xpath(PG_FUNCTION_ARGS)
-{
#ifdef USE_LIBXML
- text *xpath_expr_text = PG_GETARG_TEXT_P(0);
- xmltype *data = PG_GETARG_XML_P(1);
- ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
- ArrayBuildState *astate = NULL;
+static void
+xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
+ int *res_nitems, ArrayBuildState **astate)
+{
xmlParserCtxtPtr ctxt = NULL;
xmlDocPtr doc = NULL;
xmlXPathContextPtr xpathctx = NULL;
@@ -3324,7 +3320,6 @@ xpath(PG_FUNCTION_ARGS)
xmlChar *string;
xmlChar *xpath_expr;
int i;
- int res_nitems;
int ndim;
Datum *ns_names_uris;
bool *ns_names_uris_nulls;
@@ -3339,7 +3334,7 @@ xpath(PG_FUNCTION_ARGS)
* ARRAY[ARRAY['myns', 'http://example.com'], ARRAY['myns2',
* 'http://example2.com']].
*/
- ndim = ARR_NDIM(namespaces);
+ ndim = namespaces ? ARR_NDIM(namespaces) : 0;
if (ndim != 0)
{
int *dims;
@@ -3439,6 +3434,13 @@ xpath(PG_FUNCTION_ARGS)
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
"invalid XPath expression");
+ /*
+ * Version 2.6.27 introduces a function named
+ * xmlXPathCompiledEvalToBoolean, which would be enough for
+ * xmlexists, but we can derive the existence by whether any
+ * nodes are returned, thereby preventing a library version
+ * upgrade and keeping the code the same.
+ */
xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
if (xpathobj == NULL) /* TODO: reason? */
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
@@ -3446,21 +3448,22 @@ xpath(PG_FUNCTION_ARGS)
/* return empty array in cases when nothing is found */
if (xpathobj->nodesetval == NULL)
- res_nitems = 0;
+ *res_nitems = 0;
else
- res_nitems = xpathobj->nodesetval->nodeNr;
+ *res_nitems = xpathobj->nodesetval->nodeNr;
- if (res_nitems)
+ if (*res_nitems && astate)
{
+ *astate = NULL;
for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
{
Datum elem;
bool elemisnull = false;
elem = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
- astate = accumArrayResult(astate, elem,
- elemisnull, XMLOID,
- CurrentMemoryContext);
+ *astate = accumArrayResult(*astate, elem,
+ elemisnull, XMLOID,
+ CurrentMemoryContext);
}
}
}
@@ -3485,6 +3488,28 @@ xpath(PG_FUNCTION_ARGS)
xmlXPathFreeContext(xpathctx);
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
+}
+#endif /* USE_LIBXML */
+
+/*
+ * Evaluate XPath expression and return array of XML values.
+ *
+ * As we have no support of XQuery sequences yet, this function seems
+ * to be the most useful one (array of XML functions plays a role of
+ * some kind of substitution for XQuery sequences).
+ */
+Datum
+xpath(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+ text *xpath_expr_text = PG_GETARG_TEXT_P(0);
+ xmltype *data = PG_GETARG_XML_P(1);
+ ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
+ int res_nitems;
+ ArrayBuildState *astate;
+
+ xpath_internal(xpath_expr_text, data, namespaces,
+ &res_nitems, &astate);
if (res_nitems == 0)
PG_RETURN_ARRAYTYPE_P(construct_empty_array(XMLOID));
@@ -3495,3 +3520,24 @@ xpath(PG_FUNCTION_ARGS)
return 0;
#endif
}
+
+/*
+ * Determines if the node specified by the supplied XPath exists
+ * in a given XML document, returning a boolean.
+ */
+Datum xmlexists(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+ text *xpath_expr_text = PG_GETARG_TEXT_P(0);
+ xmltype *data = PG_GETARG_XML_P(1);
+ int res_nitems;
+
+ xpath_internal(xpath_expr_text, data, NULL,
+ &res_nitems, NULL);
+
+ PG_RETURN_BOOL(res_nitems > 0);
+#else
+ NO_XML_SUPPORT();
+ return 0;
+#endif
+}