2014-11-04 22:16 GMT+07:00 Peter Eisentraut <pete...@gmx.net>: > On 10/6/14 10:24 PM, Ali Akbar wrote: > > 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) > > I think the problem this patch is addressing is real, and your approach > is sound, but I'd ask you to go back to the xmlCopyNode() version, and > try to add a test case for why the second argument = 1 is necessary. I > don't see any other problems. >
OK. Because upstream code is fixed in current version, i'll revert to the previous version. Test case added to regression test. With =1 argument, the result is correct: <local:piece xmlns:local=\"http://127.0.0.1\" xmlns=\"http://127.0.0.2\" id=\"1\"> <internal>number one</internal> <internal2/> </local:piece> without the argument, the result is not correct, all children will be lost. Because of that, the other regression test will fail too because the children is not copied: *** 584,593 **** -- Text XPath expressions evaluation SELECT xpath('/value', data) FROM xmltest; ! xpath ! ---------------------- ! {<value>one</value>} ! {<value>two</value>} (2 rows) SELECT xpath(NULL, NULL) IS NULL FROM xmltest; --- 584,593 ---- -- Text XPath expressions evaluation SELECT xpath('/value', data) FROM xmltest; ! xpath ! ------------ ! {<value/>} ! {<value/>} (2 rows) SELECT xpath(NULL, NULL) IS NULL FROM xmltest; *************** ... <cut> updated patch attached. Regards, -- 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, *************** *** 3599,3624 **** SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, * 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(); } PG_END_TRY(); xmlBufferFree(buf); } else --- 3601,3640 ---- * return value otherwise) */ static text * ! xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt) { xmltype *result; if (cur->type == XML_ELEMENT_NODE) { xmlBufferPtr buf; + xmlNodePtr cur_copy; buf = xmlBufferCreate(); + + /* the result of xmlNodeDump won't contain namespace definitions + * from parent nodes, but xmlCopyNode duplicates a node along + * with its required namespace definitions. + */ + cur_copy = xmlCopyNode(cur, 1); + + if (cur_copy == NULL) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not serialize xml"); + PG_TRY(); { ! xmlNodeDump(buf, NULL, cur_copy, 0, 1); result = xmlBuffer_to_xmltype(buf); } PG_CATCH(); { + xmlFreeNode(cur_copy); xmlBufferFree(buf); PG_RE_THROW(); } PG_END_TRY(); + xmlFreeNode(cur_copy); xmlBufferFree(buf); } else *************** *** 3660,3666 **** xml_xmlnodetoxmltype(xmlNodePtr cur) */ static int xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj, ! ArrayBuildState **astate) { int result = 0; Datum datum; --- 3676,3683 ---- */ 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); --- 3699,3706 ---- 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(); { --- 3904,3912 ---- * 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,623 ---- {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('//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:piece', '<local:data xmlns:local="http://127.0.0.1" xmlns="http://127.0.0.2"><local:piece id="1"><internal>number one</internal><internal2/></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('//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:piece', '<local:data xmlns:local="http://127.0.0.1" xmlns="http://127.0.0.2"><local:piece id="1"><internal>number one</internal><internal2/></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><</root>'); SELECT xpath('//@value', '<root value="<"/>');
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers