On 16.01.25 07:11, Pavel Stehule wrote: > It is better. v2 attached updates the documentation. > > My note was related to a very different description of this > functionality in DB2. So if you propose this function for better > compatibility (and this function is implemented only by db2), it is > surprising to see that this functionality is described (and probably > implemented) very differently. Because I do not have db2 and I miss > db2 knowledge, I don't know if differences in implementation and > description are based on different technology (XML like graph or XML > like string) or if it is something that is missing in this patch.
I suppose it's mostly because PostgreSQL and DB2 have different structures for the XML data type; DB2 stores it in its native hierarchical format rather than as text. Thanks for the review. Best, Jim
From edc39f499d8fda276df08739babe8360c0bee85c Mon Sep 17 00:00:00 2001 From: Jim Jones <jim.jo...@uni-muenster.de> Date: Thu, 16 Jan 2025 07:55:21 +0100 Subject: [PATCH v2] Add XMLDocument function (SQL/XML X030) This patch adds the SQL/XML X030 function XMLDocument. It returns an XML document from a given XML expression. An XML document node can have any number of children nodes. This patch also adds documentation and tests. --- doc/src/sgml/func.sgml | 38 ++++++++++++++++++++++++++++ src/backend/catalog/sql_features.txt | 2 +- src/backend/utils/adt/xml.c | 12 +++++++++ src/include/catalog/pg_proc.dat | 3 +++ src/test/regress/expected/xml.out | 36 ++++++++++++++++++++++++++ src/test/regress/expected/xml_1.out | 33 ++++++++++++++++++++++++ src/test/regress/expected/xml_2.out | 36 ++++++++++++++++++++++++++ src/test/regress/sql/xml.sql | 22 ++++++++++++++++ 8 files changed, 181 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 47370e581a..24a7d37815 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -14417,6 +14417,44 @@ SELECT xmlcomment('hello'); </para> </sect3> + <sect3 id="functions-producing-xml-xmldocument"> + <title><literal>xmldocument</literal></title> + + <indexterm> + <primary>xmldocument</primary> + </indexterm> + +<synopsis> +<function>xmldocument</function> ( <type>xml</type> ) <returnvalue>xml</returnvalue> +</synopsis> + + <para> + The <function>xmldocument</function> function encapsulates the XML expression + within a valid XML document structure. The expression passed as the argument + must be a valid, single-rooted XML fragment. If the XML expression is NULL, + the result will also be NULL. + </para> + + <para> + Example: +<screen><![CDATA[ +SELECT + xmldocument( + xmlelement(NAME foo, + xmlattributes(42 AS att), + xmlelement(NAME bar, + xmlconcat('va', 'lue')) + ) + ); + + xmldocument +-------------------------------------- + <foo att="42"><bar>value</bar></foo> +(1 row) +]]></screen> + </para> + </sect3> + <sect3 id="functions-producing-xml-xmlconcat"> <title><literal>xmlconcat</literal></title> diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt index 2f250d2c57..f621b6af1d 100644 --- a/src/backend/catalog/sql_features.txt +++ b/src/backend/catalog/sql_features.txt @@ -625,7 +625,7 @@ X015 Fields of XML type NO X016 Persistent XML values YES X020 XMLConcat YES X025 XMLCast NO -X030 XMLDocument NO +X030 XMLDocument YES X031 XMLElement YES X032 XMLForest YES X034 XMLAgg YES diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index db8d0d6a7e..49073b522b 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -522,6 +522,18 @@ xmlcomment(PG_FUNCTION_ARGS) #endif } +Datum +xmldocument(PG_FUNCTION_ARGS) +{ +#ifdef USE_LIBXML + xmltype *data = PG_GETARG_XML_P(0); + + PG_RETURN_XML_P(xmlparse((text *) data, XMLOPTION_DOCUMENT, true)); +#else + NO_XML_SUPPORT(); + return 0; +#endif /* not USE_LIBXML */ +} Datum xmltext(PG_FUNCTION_ARGS) diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index b37e8a6f88..8114d8d117 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -9011,6 +9011,9 @@ { oid => '3813', descr => 'generate XML text node', proname => 'xmltext', prorettype => 'xml', proargtypes => 'text', prosrc => 'xmltext' }, +{ oid => '3814', descr => 'generate XML document', + proname => 'xmldocument', prorettype => 'xml', proargtypes => 'xml', + prosrc => 'xmldocument'}, { oid => '2923', descr => 'map table contents to XML', proname => 'table_to_xml', procost => '100', provolatile => 's', diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index 2e9616acda..a33da4fd94 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -1873,3 +1873,39 @@ SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char); x<P>73</P>0.42truej (1 row) +SELECT + xmldocument( + xmlelement(NAME root, + xmlattributes(42 AS att), + xmlcomment('comment'), + xmlelement(NAME foo,'<foo&bar>'), + xmlelement(NAME bar, xmlconcat('va', 'lue')), + xmlpi(name pi), + xmlelement(NAME txt, xmltext('<"&>')) + ) + ); + xmldocument +------------------------------------------------------------------------------------------------------------------------ + <root att="42"><!--comment--><foo><foo&bar></foo><bar>value</bar><?pi?><txt><"&></txt></root> +(1 row) + +SELECT xmldocument(NULL); + xmldocument +------------- + +(1 row) + +SET xmloption TO CONTENT; +\set VERBOSITY terse +SELECT xmldocument('foo'::xml); +ERROR: invalid XML document +SELECT xmldocument('foo'); +ERROR: invalid XML document +SELECT xmldocument(''); +ERROR: invalid XML document +SELECT xmldocument(' '); +ERROR: invalid XML document +SELECT xmldocument(xmlcomment('comment')); +ERROR: invalid XML document +\set VERBOSITY default +SET xmloption TO DOCUMENT; diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index 7505a14077..f8d1fd7e6c 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -1482,3 +1482,36 @@ ERROR: unsupported XML feature LINE 1: SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j':... ^ DETAIL: This functionality requires the server to be built with libxml support. +SELECT + xmldocument( + xmlelement(NAME root, + xmlattributes(42 AS att), + xmlcomment('comment'), + xmlelement(NAME foo,'<foo&bar>'), + xmlelement(NAME bar, xmlconcat('va', 'lue')), + xmlpi(name pi), + xmlelement(NAME txt, xmltext('<"&>')) + ) + ); +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmldocument(NULL); + xmldocument +------------- + +(1 row) + +SET xmloption TO CONTENT; +\set VERBOSITY terse +SELECT xmldocument('foo'::xml); +ERROR: unsupported XML feature at character 20 +SELECT xmldocument('foo'); +ERROR: unsupported XML feature at character 20 +SELECT xmldocument(''); +ERROR: unsupported XML feature at character 20 +SELECT xmldocument(' '); +ERROR: unsupported XML feature at character 20 +SELECT xmldocument(xmlcomment('comment')); +ERROR: unsupported XML feature +\set VERBOSITY default +SET xmloption TO DOCUMENT; diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out index c07ed2b269..9234859740 100644 --- a/src/test/regress/expected/xml_2.out +++ b/src/test/regress/expected/xml_2.out @@ -1859,3 +1859,39 @@ SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char); x<P>73</P>0.42truej (1 row) +SELECT + xmldocument( + xmlelement(NAME root, + xmlattributes(42 AS att), + xmlcomment('comment'), + xmlelement(NAME foo,'<foo&bar>'), + xmlelement(NAME bar, xmlconcat('va', 'lue')), + xmlpi(name pi), + xmlelement(NAME txt, xmltext('<"&>')) + ) + ); + xmldocument +------------------------------------------------------------------------------------------------------------------------ + <root att="42"><!--comment--><foo><foo&bar></foo><bar>value</bar><?pi?><txt><"&></txt></root> +(1 row) + +SELECT xmldocument(NULL); + xmldocument +------------- + +(1 row) + +SET xmloption TO CONTENT; +\set VERBOSITY terse +SELECT xmldocument('foo'::xml); +ERROR: invalid XML document +SELECT xmldocument('foo'); +ERROR: invalid XML document +SELECT xmldocument(''); +ERROR: invalid XML document +SELECT xmldocument(' '); +ERROR: invalid XML document +SELECT xmldocument(xmlcomment('comment')); +ERROR: invalid XML document +\set VERBOSITY default +SET xmloption TO DOCUMENT; \ No newline at end of file diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index bac0388ac1..a4f09d1b9f 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -675,3 +675,25 @@ SELECT xmltext(' '); SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}'); SELECT xmltext('foo & <"bar">'); SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char); + +SELECT + xmldocument( + xmlelement(NAME root, + xmlattributes(42 AS att), + xmlcomment('comment'), + xmlelement(NAME foo,'<foo&bar>'), + xmlelement(NAME bar, xmlconcat('va', 'lue')), + xmlpi(name pi), + xmlelement(NAME txt, xmltext('<"&>')) + ) + ); +SELECT xmldocument(NULL); +SET xmloption TO CONTENT; +\set VERBOSITY terse +SELECT xmldocument('foo'::xml); +SELECT xmldocument('foo'); +SELECT xmldocument(''); +SELECT xmldocument(' '); +SELECT xmldocument(xmlcomment('comment')); +\set VERBOSITY default +SET xmloption TO DOCUMENT; -- 2.34.1