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)
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to