mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Fix namespace handling in xpath function
Previously, the xml value resulting from an xpath query would not have namespace declarations if the namespace declarations were attached to an ancestor element in the input xml value. That means the output value was not correct XML. Fix that by running the result value through xmlCopyNode(), which produces the correct namespace declarations. Author: Ali Akbar <the.apaan@gmail.com>
This commit is contained in:
@ -141,9 +141,10 @@ 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 text *xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt);
|
||||
static int xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
|
||||
ArrayBuildState *astate);
|
||||
ArrayBuildState *astate,
|
||||
PgXmlErrorContext *xmlerrcxt);
|
||||
#endif /* USE_LIBXML */
|
||||
|
||||
static StringInfo query_to_xml_internal(const char *query, char *tablename,
|
||||
@ -3599,26 +3600,41 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename,
|
||||
* return value otherwise)
|
||||
*/
|
||||
static text *
|
||||
xml_xmlnodetoxmltype(xmlNodePtr cur)
|
||||
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 copy node");
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
xmlNodeDump(buf, NULL, cur, 0, 1);
|
||||
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,7 +3676,8 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
|
||||
*/
|
||||
static int
|
||||
xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
|
||||
ArrayBuildState *astate)
|
||||
ArrayBuildState *astate,
|
||||
PgXmlErrorContext *xmlerrcxt)
|
||||
{
|
||||
int result = 0;
|
||||
Datum datum;
|
||||
@ -3679,7 +3696,8 @@ xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
|
||||
|
||||
for (i = 0; i < result; i++)
|
||||
{
|
||||
datum = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
|
||||
datum = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
|
||||
xmlerrcxt));
|
||||
(void) accumArrayResult(astate, datum, false,
|
||||
XMLOID, CurrentMemoryContext);
|
||||
}
|
||||
@ -3881,9 +3899,9 @@ 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);
|
||||
*res_nitems = xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
|
||||
else
|
||||
(void) xml_xpathobjtoxmlarray(xpathobj, astate);
|
||||
(void) xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
|
Reference in New Issue
Block a user