xpath improvement suggestion - Mailing list pgsql-hackers

From Arie Bikker
Subject xpath improvement suggestion
Date
Msg-id 4B43C6AC.4020802@abikker.nl
Whole thread Raw
Responses Re: xpath improvement suggestion  (Scott Bailey <artacus@comcast.net>)
Re: xpath improvement suggestion  (Robert Haas <robertmhaas@gmail.com>)
List pgsql-hackers
Hi all,

Well I had  to burn some midnight oil trying to figure out why a
construct like
SELECT xpath('name()','<a/>');
doesn't give the expected result. Kept getting an empty array:
   xpath
-------------
{}
instead of the expected "{a}"
BugID 4294 and the TODO item "better handling of XPath data types"
pointed in the right direction.
whithin src/backend/utils/adt/xml.c in the function xpath the result of
the call to xmlXPathCompiledEval is not handled optimally. In fact, the
result is assumed to be a nodeset without consulting the ->type member
of the result. I've made some minor changes to xml.c to handle some
non-nodeset results of xmlXPathCompiledEval.
Essentially, the revised code makes an array of all the nodes in the
xpathobj result in case this is a nodeset, or an array with a single
element in case the reult is a number/string/boolean. The problem cases
mentioned in
http://archives.postgresql.org/pgsql-hackers/2008-06/msg00616.php now
work as expected.
Revision of the code involves:
- A switch statement to handle the result type of xmlXPathCompiledEval.
- an additional function xmlpathobjtoxmltype.

diff of the revisioned code with respect to original is in attached file.

kind regards, Arie Bikker
114d113
< static text *xml_xmlpathobjtoxmltype(xmlXPathObjectPtr cur);
3269,3309d3267
<
< /*
<  * Convert XML pathobject to text for non-nodeset objects
<  */
< static text *
< xml_xmlpathobjtoxmltype(xmlXPathObjectPtr cur)
< {
<     xmltype    *result;
<
<     if (cur->type == XPATH_BOOLEAN)
<     {
<         PG_TRY();
<         {
<             result = cstring_to_text((char *)(xmlXPathCastToBoolean(cur)?"t":"f"));
<         }
<         PG_CATCH();
<         {
<             PG_RE_THROW();
<         }
<         PG_END_TRY();
<     }
<     else
<     {
<         xmlChar    *str;
<
<         str = xmlXPathCastToString(cur);
<         PG_TRY();
<         {
<             result = (xmltype *) cstring_to_text((char *) str);
<         }
<         PG_CATCH();
<         {
<             xmlFree(str);
<             PG_RE_THROW();
<         }
<         PG_END_TRY();
<         xmlFree(str);
<     }
<
<     return result;
< }
3463,3471c3421,3429
<         switch (xpathobj->type) {
<         case XPATH_NODESET: {
<             /* return empty array in cases when nothing is found */
<             if (xpathobj->nodesetval == NULL)
<                 res_nitems = 0;
<             else
<                 res_nitems = xpathobj->nodesetval->nodeNr;
<
<             if (res_nitems)
---
>         /* return empty array in cases when nothing is found */
>         if (xpathobj->nodesetval == NULL)
>             res_nitems = 0;
>         else
>             res_nitems = xpathobj->nodesetval->nodeNr;
>
>         if (res_nitems)
>         {
>             for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
3473,3482c3431,3437
<                 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);
<                 }
---
>                 Datum        elem;
>                 bool        elemisnull = false;
>
>                 elem = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
>                 astate = accumArrayResult(astate, elem,
>                                           elemisnull, XMLOID,
>                                           CurrentMemoryContext);
3484d3438
<             break;
3486,3500d3439
<         case XPATH_BOOLEAN:
<         case XPATH_NUMBER:
<         case XPATH_STRING: {
<             Datum        elem;
<             bool        elemisnull = false;
<
<             elem = PointerGetDatum(xml_xmlpathobjtoxmltype(xpathobj));
<             astate = accumArrayResult(astate, elem,
<                               elemisnull, XMLOID,
<                               CurrentMemoryContext);
<             break;
<         }
<         default: {
<         }
<         }
3524c3463
<     if (astate== NULL)
---
>     if (res_nitems == 0)

pgsql-hackers by date:

Previous
From: Tim Bunce
Date:
Subject: Re: Status of plperl inter-sp calling
Next
From: Tom Lane
Date:
Subject: Re: Status of plperl inter-sp calling