Fix handling of namespace nodes in xpath() (xml)

xpath() attempted to call xmlCopyNode() and xmlNodeDump() on a
XML_NAMESPACE_DECL, finishing with a confusing error:
=# SELECT xpath('//namespace::foo', '<root xmlns:foo="http://127.0.0.1"/>');
ERROR:  53200: could not copy node
CONTEXT:  SQL function "xpath" statement 1

xpath() is changed so as it goes through xmlXPathCastNodeToString()
instead, that is able to handle namespace nodes.  xml2 uses the same
solution.  This issue has been discovered while digging into
9d33a5a804.

Author: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/aioT7ui_ZJ9RMlfM@paquier.xyz
Backpatch-through: 14
This commit is contained in:
Michael Paquier 2026-06-12 10:25:54 +09:00
parent b3aa2083a4
commit 1d8c72b2ef
4 changed files with 15 additions and 1 deletions

View file

@ -3854,7 +3854,9 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt)
{
xmltype *result = NULL;
if (cur->type != XML_ATTRIBUTE_NODE && cur->type != XML_TEXT_NODE)
if (cur->type != XML_ATTRIBUTE_NODE &&
cur->type != XML_TEXT_NODE &&
cur->type != XML_NAMESPACE_DECL)
{
void (*volatile nodefree) (xmlNodePtr) = NULL;
volatile xmlBufferPtr buf = NULL;

View file

@ -710,6 +710,12 @@ SELECT xpath('root', '<root/>');
{<root/>}
(1 row)
SELECT xpath('//namespace::foo', '<root xmlns:foo="http://127.0.0.1"/>');
xpath
--------------------
{http://127.0.0.1}
(1 row)
-- Round-trip non-ASCII data through xpath().
DO $$
DECLARE

View file

@ -516,6 +516,11 @@ ERROR: unsupported XML feature
LINE 1: SELECT xpath('root', '<root/>');
^
DETAIL: This functionality requires the server to be built with libxml support.
SELECT xpath('//namespace::foo', '<root xmlns:foo="http://127.0.0.1"/>');
ERROR: unsupported XML feature
LINE 1: SELECT xpath('//namespace::foo', '<root xmlns:foo="http://12...
^
DETAIL: This functionality requires the server to be built with libxml support.
-- Round-trip non-ASCII data through xpath().
DO $$
DECLARE

View file

@ -196,6 +196,7 @@ SELECT xpath('count(//*)=3', '<root><sub/><sub/></root>');
SELECT xpath('name(/*)', '<root><sub/><sub/></root>');
SELECT xpath('/nosuchtag', '<root/>');
SELECT xpath('root', '<root/>');
SELECT xpath('//namespace::foo', '<root xmlns:foo="http://127.0.0.1"/>');
-- Round-trip non-ASCII data through xpath().
DO $$