diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2010-08-05 04:21:54 +0000 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2010-08-05 04:21:54 +0000 |
commit | 641459f26954b04f74d098a758b716297b6554ea (patch) | |
tree | 7f1e5144dbc7adee38988339c47cd6af1d9b8de4 /src/backend/utils/adt/xml.c | |
parent | 26e47efb66b7b41f1c4464105abd3da58a7bf04f (diff) | |
download | postgresql-641459f26954b04f74d098a758b716297b6554ea.tar.gz postgresql-641459f26954b04f74d098a758b716297b6554ea.zip |
Add xmlexists function
by Mike Fowler, reviewed by Peter Eisentraut
Diffstat (limited to 'src/backend/utils/adt/xml.c')
-rw-r--r-- | src/backend/utils/adt/xml.c | 86 |
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 +} |