Set correct context for XPath evaluation
According to the SQL standard, the context of XMLTABLE's XPath row_expression is the document node of the XML input document, not the root node. This becomes visible when a relative path rather than absolute is used as row expression. Absolute paths is what was used in original tests and docs (and the most common form used in examples throughout the interwebs), which explains why this wasn't noticed before. Other functions such as xpath() and xpath_exists() also have this problem. While not specified by the SQL standard, it would be pretty odd to leave those functions to behave differently than XMLTABLE, so change them too. However, this is a backwards-incompatible change. No backpatch, out of fear of breaking code depending on the original broken behavior. Author: Markus Winand Reported-By: Markus Winand Reviewed-by: Álvaro Herrera Discussion: https://postgr.es/m/0684A598-002C-42A2-AE12-F024A324EAE4@winand.at
This commit is contained in:
parent
425b4c082c
commit
e474c2b7e4
@ -3934,10 +3934,7 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
|
||||
if (xpathctx == NULL || xmlerrcxt->err_occurred)
|
||||
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
|
||||
"could not allocate XPath context");
|
||||
xpathctx->node = xmlDocGetRootElement(doc);
|
||||
if (xpathctx->node == NULL || xmlerrcxt->err_occurred)
|
||||
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
|
||||
"could not find root XML element");
|
||||
xpathctx->node = (xmlNodePtr) doc;
|
||||
|
||||
/* register namespaces, if any */
|
||||
if (ns_count > 0)
|
||||
@ -4276,10 +4273,7 @@ XmlTableSetDocument(TableFuncScanState *state, Datum value)
|
||||
if (xpathcxt == NULL || xtCxt->xmlerrcxt->err_occurred)
|
||||
xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
|
||||
"could not allocate XPath context");
|
||||
xpathcxt->node = xmlDocGetRootElement(doc);
|
||||
if (xpathcxt->node == NULL || xtCxt->xmlerrcxt->err_occurred)
|
||||
xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
|
||||
"could not find root XML element");
|
||||
xpathcxt->node = (xmlNodePtr) doc;
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
|
@ -670,6 +670,12 @@ SELECT xpath('/nosuchtag', '<root/>');
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
SELECT xpath('root', '<root/>');
|
||||
xpath
|
||||
-----------
|
||||
{<root/>}
|
||||
(1 row)
|
||||
|
||||
-- Round-trip non-ASCII data through xpath().
|
||||
DO $$
|
||||
DECLARE
|
||||
@ -1212,7 +1218,7 @@ SELECT * FROM xmltable('/root' passing '<root><element>a1a<!-- aaaa -->a2a<?aaaa
|
||||
SELECT * FROM xmltable('/root' passing '<root><element>a1a<!-- aaaa -->a2a<?aaaaa?> <!--z--> bbbb<x>xxx</x>cccc</element></root>' COLUMNS element text PATH 'element/text()'); -- should fail
|
||||
ERROR: more than one value returned by column XPath expression
|
||||
-- CDATA test
|
||||
select * from xmltable('r' passing '<d><r><c><![CDATA[<hello> &"<>!<a>foo</a>]]></c></r><r><c>2</c></r></d>' columns c text);
|
||||
select * from xmltable('d/r' passing '<d><r><c><![CDATA[<hello> &"<>!<a>foo</a>]]></c></r><r><c>2</c></r></d>' columns c text);
|
||||
c
|
||||
-------------------------
|
||||
<hello> &"<>!<a>foo</a>
|
||||
|
@ -576,6 +576,12 @@ LINE 1: SELECT xpath('/nosuchtag', '<root/>');
|
||||
^
|
||||
DETAIL: This functionality requires the server to be built with libxml support.
|
||||
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||
SELECT xpath('root', '<root/>');
|
||||
ERROR: unsupported XML feature
|
||||
LINE 1: SELECT xpath('root', '<root/>');
|
||||
^
|
||||
DETAIL: This functionality requires the server to be built with libxml support.
|
||||
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||
-- Round-trip non-ASCII data through xpath().
|
||||
DO $$
|
||||
DECLARE
|
||||
@ -1067,10 +1073,10 @@ LINE 1: SELECT * FROM xmltable('/root' passing '<root><element>a1a<!...
|
||||
DETAIL: This functionality requires the server to be built with libxml support.
|
||||
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||
-- CDATA test
|
||||
select * from xmltable('r' passing '<d><r><c><![CDATA[<hello> &"<>!<a>foo</a>]]></c></r><r><c>2</c></r></d>' columns c text);
|
||||
select * from xmltable('d/r' passing '<d><r><c><![CDATA[<hello> &"<>!<a>foo</a>]]></c></r><r><c>2</c></r></d>' columns c text);
|
||||
ERROR: unsupported XML feature
|
||||
LINE 1: select * from xmltable('r' passing '<d><r><c><![CDATA[<hello...
|
||||
^
|
||||
LINE 1: select * from xmltable('d/r' passing '<d><r><c><![CDATA[<hel...
|
||||
^
|
||||
DETAIL: This functionality requires the server to be built with libxml support.
|
||||
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||
-- XML builtin entities
|
||||
|
@ -650,6 +650,12 @@ SELECT xpath('/nosuchtag', '<root/>');
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
SELECT xpath('root', '<root/>');
|
||||
xpath
|
||||
-----------
|
||||
{<root/>}
|
||||
(1 row)
|
||||
|
||||
-- Round-trip non-ASCII data through xpath().
|
||||
DO $$
|
||||
DECLARE
|
||||
@ -1192,7 +1198,7 @@ SELECT * FROM xmltable('/root' passing '<root><element>a1a<!-- aaaa -->a2a<?aaaa
|
||||
SELECT * FROM xmltable('/root' passing '<root><element>a1a<!-- aaaa -->a2a<?aaaaa?> <!--z--> bbbb<x>xxx</x>cccc</element></root>' COLUMNS element text PATH 'element/text()'); -- should fail
|
||||
ERROR: more than one value returned by column XPath expression
|
||||
-- CDATA test
|
||||
select * from xmltable('r' passing '<d><r><c><![CDATA[<hello> &"<>!<a>foo</a>]]></c></r><r><c>2</c></r></d>' columns c text);
|
||||
select * from xmltable('d/r' passing '<d><r><c><![CDATA[<hello> &"<>!<a>foo</a>]]></c></r><r><c>2</c></r></d>' columns c text);
|
||||
c
|
||||
-------------------------
|
||||
<hello> &"<>!<a>foo</a>
|
||||
|
@ -188,6 +188,7 @@ SELECT xpath('count(//*)=0', '<root><sub/><sub/></root>');
|
||||
SELECT xpath('count(//*)=3', '<root><sub/><sub/></root>');
|
||||
SELECT xpath('name(/*)', '<root><sub/><sub/></root>');
|
||||
SELECT xpath('/nosuchtag', '<root/>');
|
||||
SELECT xpath('root', '<root/>');
|
||||
|
||||
-- Round-trip non-ASCII data through xpath().
|
||||
DO $$
|
||||
@ -423,7 +424,7 @@ SELECT * FROM xmltable('/root' passing '<root><element>a1a<!-- aaaa -->a2a<?aaaa
|
||||
SELECT * FROM xmltable('/root' passing '<root><element>a1a<!-- aaaa -->a2a<?aaaaa?> <!--z--> bbbb<x>xxx</x>cccc</element></root>' COLUMNS element text PATH 'element/text()'); -- should fail
|
||||
|
||||
-- CDATA test
|
||||
select * from xmltable('r' passing '<d><r><c><![CDATA[<hello> &"<>!<a>foo</a>]]></c></r><r><c>2</c></r></d>' columns c text);
|
||||
select * from xmltable('d/r' passing '<d><r><c><![CDATA[<hello> &"<>!<a>foo</a>]]></c></r><r><c>2</c></r></d>' columns c text);
|
||||
|
||||
-- XML builtin entities
|
||||
SELECT * FROM xmltable('/x/a' PASSING '<x><a><ent>'</ent></a><a><ent>"</ent></a><a><ent>&</ent></a><a><ent><</ent></a><a><ent>></ent></a></x>' COLUMNS ent text);
|
||||
|
Loading…
x
Reference in New Issue
Block a user