77 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88 * Portions Copyright (c) 1994, Regents of the University of California
99 *
10- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.98 2010/07/06 19:18:58 momjian Exp $
10+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.99 2010/08/05 04:21:54 petere Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -3295,24 +3295,20 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
32953295
32963296
32973297/*
3298- * Evaluate XPath expression and return array of XML values.
3298+ * Common code for xpath() and xmlexists()
32993299 *
3300- * As we have no support of XQuery sequences yet, this function seems
3301- * to be the most useful one (array of XML functions plays a role of
3302- * some kind of substitution for XQuery sequences).
3300+ * Evaluate XPath expression and return number of nodes in res_items
3301+ * and array of XML values in astate.
33033302 *
33043303 * It is up to the user to ensure that the XML passed is in fact
33053304 * an XML document - XPath doesn't work easily on fragments without
33063305 * a context node being known.
33073306 */
3308- Datum
3309- xpath (PG_FUNCTION_ARGS )
3310- {
33113307#ifdef USE_LIBXML
3312- text * xpath_expr_text = PG_GETARG_TEXT_P ( 0 );
3313- xmltype * data = PG_GETARG_XML_P ( 1 );
3314- ArrayType * namespaces = PG_GETARG_ARRAYTYPE_P ( 2 );
3315- ArrayBuildState * astate = NULL ;
3308+ static void
3309+ xpath_internal ( text * xpath_expr_text , xmltype * data , ArrayType * namespaces ,
3310+ int * res_nitems , ArrayBuildState * * astate )
3311+ {
33163312 xmlParserCtxtPtr ctxt = NULL ;
33173313 xmlDocPtr doc = NULL ;
33183314 xmlXPathContextPtr xpathctx = NULL ;
@@ -3324,7 +3320,6 @@ xpath(PG_FUNCTION_ARGS)
33243320 xmlChar * string ;
33253321 xmlChar * xpath_expr ;
33263322 int i ;
3327- int res_nitems ;
33283323 int ndim ;
33293324 Datum * ns_names_uris ;
33303325 bool * ns_names_uris_nulls ;
@@ -3339,7 +3334,7 @@ xpath(PG_FUNCTION_ARGS)
33393334 * ARRAY[ARRAY['myns', 'http://example.com'], ARRAY['myns2',
33403335 * 'http://example2.com']].
33413336 */
3342- ndim = ARR_NDIM (namespaces );
3337+ ndim = namespaces ? ARR_NDIM (namespaces ) : 0 ;
33433338 if (ndim != 0 )
33443339 {
33453340 int * dims ;
@@ -3439,28 +3434,36 @@ xpath(PG_FUNCTION_ARGS)
34393434 xml_ereport (ERROR , ERRCODE_INTERNAL_ERROR ,
34403435 "invalid XPath expression" );
34413436
3437+ /*
3438+ * Version 2.6.27 introduces a function named
3439+ * xmlXPathCompiledEvalToBoolean, which would be enough for
3440+ * xmlexists, but we can derive the existence by whether any
3441+ * nodes are returned, thereby preventing a library version
3442+ * upgrade and keeping the code the same.
3443+ */
34423444 xpathobj = xmlXPathCompiledEval (xpathcomp , xpathctx );
34433445 if (xpathobj == NULL ) /* TODO: reason? */
34443446 xml_ereport (ERROR , ERRCODE_INTERNAL_ERROR ,
34453447 "could not create XPath object" );
34463448
34473449 /* return empty array in cases when nothing is found */
34483450 if (xpathobj -> nodesetval == NULL )
3449- res_nitems = 0 ;
3451+ * res_nitems = 0 ;
34503452 else
3451- res_nitems = xpathobj -> nodesetval -> nodeNr ;
3453+ * res_nitems = xpathobj -> nodesetval -> nodeNr ;
34523454
3453- if (res_nitems )
3455+ if (* res_nitems && astate )
34543456 {
3457+ * astate = NULL ;
34553458 for (i = 0 ; i < xpathobj -> nodesetval -> nodeNr ; i ++ )
34563459 {
34573460 Datum elem ;
34583461 bool elemisnull = false;
34593462
34603463 elem = PointerGetDatum (xml_xmlnodetoxmltype (xpathobj -> nodesetval -> nodeTab [i ]));
3461- astate = accumArrayResult (astate , elem ,
3462- elemisnull , XMLOID ,
3463- CurrentMemoryContext );
3464+ * astate = accumArrayResult (* astate , elem ,
3465+ elemisnull , XMLOID ,
3466+ CurrentMemoryContext );
34643467 }
34653468 }
34663469 }
@@ -3485,6 +3488,28 @@ xpath(PG_FUNCTION_ARGS)
34853488 xmlXPathFreeContext (xpathctx );
34863489 xmlFreeDoc (doc );
34873490 xmlFreeParserCtxt (ctxt );
3491+ }
3492+ #endif /* USE_LIBXML */
3493+
3494+ /*
3495+ * Evaluate XPath expression and return array of XML values.
3496+ *
3497+ * As we have no support of XQuery sequences yet, this function seems
3498+ * to be the most useful one (array of XML functions plays a role of
3499+ * some kind of substitution for XQuery sequences).
3500+ */
3501+ Datum
3502+ xpath (PG_FUNCTION_ARGS )
3503+ {
3504+ #ifdef USE_LIBXML
3505+ text * xpath_expr_text = PG_GETARG_TEXT_P (0 );
3506+ xmltype * data = PG_GETARG_XML_P (1 );
3507+ ArrayType * namespaces = PG_GETARG_ARRAYTYPE_P (2 );
3508+ int res_nitems ;
3509+ ArrayBuildState * astate ;
3510+
3511+ xpath_internal (xpath_expr_text , data , namespaces ,
3512+ & res_nitems , & astate );
34883513
34893514 if (res_nitems == 0 )
34903515 PG_RETURN_ARRAYTYPE_P (construct_empty_array (XMLOID ));
@@ -3495,3 +3520,24 @@ xpath(PG_FUNCTION_ARGS)
34953520 return 0 ;
34963521#endif
34973522}
3523+
3524+ /*
3525+ * Determines if the node specified by the supplied XPath exists
3526+ * in a given XML document, returning a boolean.
3527+ */
3528+ Datum xmlexists (PG_FUNCTION_ARGS )
3529+ {
3530+ #ifdef USE_LIBXML
3531+ text * xpath_expr_text = PG_GETARG_TEXT_P (0 );
3532+ xmltype * data = PG_GETARG_XML_P (1 );
3533+ int res_nitems ;
3534+
3535+ xpath_internal (xpath_expr_text , data , NULL ,
3536+ & res_nitems , NULL );
3537+
3538+ PG_RETURN_BOOL (res_nitems > 0 );
3539+ #else
3540+ NO_XML_SUPPORT ();
3541+ return 0 ;
3542+ #endif
3543+ }
0 commit comments