mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Add xmlexists function
by Mike Fowler, reviewed by Peter Eisentraut
This commit is contained in:
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user