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 $$