While reviewing the patch myself, i spotted some formatting problems in the
code. Fixed in this v5 patch.

Also, this patch uses context patch format (in first versions, because of
the small modification, context patch format obfucates the changes. After
reimplementation this isn't the case anymore)

Thanks,
Ali Akbar
*** a/src/backend/utils/adt/xml.c
--- b/src/backend/utils/adt/xml.c
***************
*** 141,149 **** static bool print_xml_decl(StringInfo buf, const xmlChar *version,
  			   pg_enc encoding, int standalone);
  static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg,
  		  bool preserve_whitespace, int encoding);
! static text *xml_xmlnodetoxmltype(xmlNodePtr cur);
  static int xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
! 					   ArrayBuildState **astate);
  #endif   /* USE_LIBXML */
  
  static StringInfo query_to_xml_internal(const char *query, char *tablename,
--- 141,151 ----
  			   pg_enc encoding, int standalone);
  static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg,
  		  bool preserve_whitespace, int encoding);
! static text *xml_xmlnodetoxmltype(xmlNodePtr cur,
! 					   PgXmlErrorContext *xmlerrcxt);
  static int xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
! 					   ArrayBuildState **astate,
! 					   PgXmlErrorContext *xmlerrcxt);
  #endif   /* USE_LIBXML */
  
  static StringInfo query_to_xml_internal(const char *query, char *tablename,
***************
*** 3594,3620 **** SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename,
  
  #ifdef USE_LIBXML
  
  /*
   * Convert XML node to text (dump subtree in case of element,
   * return value otherwise)
   */
  static text *
! xml_xmlnodetoxmltype(xmlNodePtr cur)
  {
  	xmltype    *result;
  
  	if (cur->type == XML_ELEMENT_NODE)
  	{
  		xmlBufferPtr buf;
  
  		buf = xmlBufferCreate();
  		PG_TRY();
  		{
  			xmlNodeDump(buf, NULL, cur, 0, 1);
  			result = xmlBuffer_to_xmltype(buf);
  		}
  		PG_CATCH();
  		{
  			xmlBufferFree(buf);
  			PG_RE_THROW();
  		}
--- 3596,3706 ----
  
  #ifdef USE_LIBXML
  
+ /* check ns definition of node and its childrens. If any one of ns is
+  * not defined in node and it's children, but in the node's parent,
+  * copy the definition to node.
+  */
+ static void
+ xml_checkandcopyns(xmlNodePtr root,
+ 				   PgXmlErrorContext *xmlerrcxt,
+ 				   xmlNodePtr node,
+ 				   xmlNsPtr lastns_before)
+ {
+ 	xmlNsPtr ns = NULL;
+ 	xmlNsPtr cur_ns;
+ 	xmlNodePtr cur;
+ 
+ 	if (node->ns != NULL)
+ 	{
+ 		/* check in new nses */
+ 		cur_ns = lastns_before == NULL ? node->nsDef : lastns_before->next;
+ 		while (cur_ns != NULL)
+ 		{
+ 			if (cur_ns->href != NULL)
+ 			{
+ 				if (((cur_ns->prefix == NULL) && (node->ns->prefix == NULL)) ||
+ 					((cur_ns->prefix != NULL) && (node->ns->prefix != NULL) &&
+ 					 xmlStrEqual(cur_ns->prefix, node->ns->prefix)))
+ 				{
+ 					ns = cur_ns;
+ 					break;
+ 				}
+ 			}
+ 			cur_ns = cur_ns->next;
+ 		}
+ 		if (ns == NULL) /* not in new nses */
+ 		{
+ 			ns = xmlSearchNs(NULL, node->parent, node->ns->prefix);
+ 
+ 			if (ns != NULL)
+ 			{
+ 				ns = xmlNewNs(root, ns->href, ns->prefix);
+ 
+ 				if (ns == NULL && xmlerrcxt->err_occurred)
+ 					xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
+ 						"could not allocate xmlNs");
+ 			}
+ 		}
+ 	}
+ 	/* check and copy ns for children recursively */
+ 	cur = node->children;
+ 	while (cur != NULL)
+ 	{
+ 		xml_checkandcopyns(root, xmlerrcxt, cur, lastns_before);
+ 		cur = cur->next;
+ 	}
+ }
+ 
  /*
   * Convert XML node to text (dump subtree in case of element,
   * return value otherwise)
   */
  static text *
! xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt)
  {
  	xmltype    *result;
  
  	if (cur->type == XML_ELEMENT_NODE)
  	{
  		xmlBufferPtr buf;
+ 		xmlNsPtr lastns_before;
+ 		xmlNsPtr ns;
+ 		xmlNsPtr next;
  
  		buf = xmlBufferCreate();
+ 
  		PG_TRY();
  		{
+ 			lastns_before = cur->nsDef;
+ 			if (lastns_before != NULL)
+ 			{
+ 				while (lastns_before->next != NULL)
+ 					lastns_before = lastns_before->next;
+ 			}
+ 			xml_checkandcopyns(cur, xmlerrcxt, cur, lastns_before);
+ 
  			xmlNodeDump(buf, NULL, cur, 0, 1);
  			result = xmlBuffer_to_xmltype(buf);
+ 
+ 			/* delete and free new nses */
+ 			ns = lastns_before == NULL ? cur->nsDef : lastns_before->next;
+ 			while (ns != NULL)
+ 			{
+ 				next = ns->next;
+ 				xmlFree(ns);
+ 				ns = next;
+ 			}
+ 
+ 			if (lastns_before == NULL)
+ 				cur->nsDef = NULL;
+ 			else
+ 				lastns_before->next = NULL;
  		}
  		PG_CATCH();
  		{
+ 			/* new namespaces will be freed while free-ing the node, so we
+ 			 * won't free it here
+ 			 */
  			xmlBufferFree(buf);
  			PG_RE_THROW();
  		}
***************
*** 3660,3666 **** xml_xmlnodetoxmltype(xmlNodePtr cur)
   */
  static int
  xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
! 					   ArrayBuildState **astate)
  {
  	int			result = 0;
  	Datum		datum;
--- 3746,3753 ----
   */
  static int
  xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
! 					   ArrayBuildState **astate,
! 					   PgXmlErrorContext *xmlerrcxt)
  {
  	int			result = 0;
  	Datum		datum;
***************
*** 3682,3688 **** xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
  
  					for (i = 0; i < result; i++)
  					{
! 						datum = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
  						*astate = accumArrayResult(*astate, datum,
  												   false, XMLOID,
  												   CurrentMemoryContext);
--- 3769,3776 ----
  
  					for (i = 0; i < result; i++)
  					{
! 						datum = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
! 																	 xmlerrcxt));
  						*astate = accumArrayResult(*astate, datum,
  												   false, XMLOID,
  												   CurrentMemoryContext);
***************
*** 3886,3894 **** xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
  		 * Extract the results as requested.
  		 */
  		if (res_nitems != NULL)
! 			*res_nitems = xml_xpathobjtoxmlarray(xpathobj, astate);
  		else
! 			(void) xml_xpathobjtoxmlarray(xpathobj, astate);
  	}
  	PG_CATCH();
  	{
--- 3974,3982 ----
  		 * Extract the results as requested.
  		 */
  		if (res_nitems != NULL)
! 			*res_nitems = xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
  		else
! 			(void) xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
  	}
  	PG_CATCH();
  	{
*** a/src/test/regress/expected/xml.out
--- b/src/test/regress/expected/xml.out
***************
*** 612,617 **** SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1";><loc
--- 612,632 ----
   {1,2}
  (1 row)
  
+ SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1";><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+                                                                      xpath                                                                      
+ ------------------------------------------------------------------------------------------------------------------------------------------------
+  {"<local:piece xmlns:local=\"http://127.0.0.1\"; id=\"1\">number one</local:piece>","<local:piece xmlns:local=\"http://127.0.0.1\"; id=\"2\"/>"}
+ (1 row)
+ 
+ SELECT xpath('//loc:*', '<local:data xmlns:local="http://127.0.0.1";><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+                                                                             xpath                                                                             
+ --------------------------------------------------------------------------------------------------------------------------------------------------------------
+  {"<local:data xmlns:local=\"http://127.0.0.1\";>                                                                                                             +
+    <local:piece id=\"1\">number one</local:piece>                                                                                                            +
+    <local:piece id=\"2\"/>                                                                                                                                   +
+  </local:data>","<local:piece xmlns:local=\"http://127.0.0.1\"; id=\"1\">number one</local:piece>","<local:piece xmlns:local=\"http://127.0.0.1\"; id=\"2\"/>"}
+ (1 row)
+ 
  SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
            xpath          
  -------------------------
*** a/src/test/regress/expected/xml_1.out
--- b/src/test/regress/expected/xml_1.out
***************
*** 514,519 **** LINE 1: SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="ht...
--- 514,531 ----
                                          ^
  DETAIL:  This functionality requires the server to be built with libxml support.
  HINT:  You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1";><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+ ERROR:  unsupported XML feature
+ LINE 1: SELECT xpath('//loc:piece', '<local:data xmlns:local="http:/...
+                                     ^
+ DETAIL:  This functionality requires the server to be built with libxml support.
+ HINT:  You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xpath('//loc:*', '<local:data xmlns:local="http://127.0.0.1";><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+ ERROR:  unsupported XML feature
+ LINE 1: SELECT xpath('//loc:*', '<local:data xmlns:local="http://127...
+                                 ^
+ DETAIL:  This functionality requires the server to be built with libxml support.
+ HINT:  You need to rebuild PostgreSQL using --with-libxml.
  SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
  ERROR:  unsupported XML feature
  LINE 1: SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'...
*** a/src/test/regress/sql/xml.sql
--- b/src/test/regress/sql/xml.sql
***************
*** 178,183 **** SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
--- 178,185 ----
  SELECT xpath('', '<!-- error -->');
  SELECT xpath('//text()', '<local:data xmlns:local="http://127.0.0.1";><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
  SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1";><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+ SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1";><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+ SELECT xpath('//loc:*', '<local:data xmlns:local="http://127.0.0.1";><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
  SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
  SELECT xpath('//text()', '<root>&lt;</root>');
  SELECT xpath('//@value', '<root value="&lt;"/>');
-- 
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