postgres.git / summary / log / commit / refs

commit    8bf257aebac12791dc78a599e4f7dc225893d45e
Author:   Michael Paquier <michael@paquier.xyz>
Date:     Fri Jun 12 01:25:45 2026 +0000

    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
    9d33a5a804db.
    
    Author: Michael Paquier <michael@paquier.xyz>
    Discussion: https://postgr.es/m/aioT7ui_ZJ9RMlfM@paquier.xyz
    Backpatch-through: 14


src/backend/utils/adt/xml.c | 4 +++- src/test/regress/expected/xml.out | 6 ++++++ src/test/regress/expected/xml_1.out | 5 +++++ src/test/regress/sql/xml.sql | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 2c7f778cfdb..0953ad2becb 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -4199,7 +4199,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; diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index 449733f8ae9..3e80a7ff465 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -944,6 +944,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 diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index a962fce36b9..2697c68a511 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -687,6 +687,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 diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index a771a441c36..2b8445e499e 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -244,6 +244,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 $$