diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 574a544d9fa4..54f869a7cb3b 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -14655,6 +14655,60 @@ SELECT xmlcomment('hello'); + + <literal>xmldocument</literal> + + + xmldocument + + + +xmldocument ( xml ) xml + + + + The xmldocument function returns the input argument + unchanged, or NULL if the argument is NULL, + and is provided for compatibility. + + The SQL-standard XMLDocument function applied to an + XML value $EXPR, has effects equivalent to the XML + Query expression document { $EXPR }. It replaces any + document nodes in the input with their children and wraps the whole result in a + single document node. + + In the XML Query standard, a document node represents + a relaxed version of an XML document structure. This corresponds to what PostgreSQL's + single XML type allows, meaning that any valid non-null PostgreSQL XML value can be + returned unchanged. Other systems may support more permissive XML data types, + such as XML(SEQUENCE), which allow values that do not conform to + this structure. In PostgreSQL, every valid non-null value of the XML type already has + that structure, making additional processing by this function unnecessary. + + + + Example: +bar')), + (xmltext('foo&bar')), + (xmlelement(NAME el)), + (xmlforest(42 AS foo, 73 AS bar)) +) +SELECT xmldocument(val) FROM xmldata; + + xmldocument +----------------------------- + bar + foo&bar + + 4273 +(4 rows) +]]> + + + <literal>xmlconcat</literal> diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt index ebe85337c287..e17bad6ac2c0 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 db8d0d6a7e87..296ab5e444dd 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -523,6 +523,24 @@ xmlcomment(PG_FUNCTION_ARGS) } +/* + * xmldocument implements the SQL/XML function XMLDocument (X030). + * Since our XML data type corresponds to XML(CONTENT(ANY)), any + * expression already validated by the input function is considered + * valid output for XMLDocument. As a result, this function simply + * returns its input value. + */ +Datum +xmldocument(PG_FUNCTION_ARGS) +{ +#ifdef USE_LIBXML + PG_RETURN_DATUM(PG_GETARG_DATUM(0)); +#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 62beb71da288..96ac0edf84a3 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -9143,6 +9143,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 bcc743f48518..56db09dde993 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -1877,3 +1877,61 @@ SELECT xmltext('x'|| '

73

'::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,''), + xmlelement(NAME bar, xmlconcat('va', 'lue')), + xmlpi(name pi), + xmlelement(NAME txt, xmltext('<"&>')) + ) + ); + xmldocument +------------------------------------------------------------------------------------------------------------------------ + <foo&bar>value<"&> +(1 row) + +SELECT xmldocument(NULL); + xmldocument +------------- + +(1 row) + +SELECT xmldocument('bar'::xml); + xmldocument +---------------- + bar +(1 row) + +SELECT xmldocument('foo'::xml); + xmldocument +------------- + foo +(1 row) + +SELECT xmldocument('foo'); + xmldocument +------------- + foo +(1 row) + +SELECT xmldocument(''); + xmldocument +------------- + +(1 row) + +SELECT xmldocument(' '); + xmldocument +------------- + +(1 row) + +SELECT xmldocument(xmlcomment('comment')); + xmldocument +---------------- + +(1 row) + diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index a1c5d314171f..310e8c6411c2 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -1492,3 +1492,50 @@ ERROR: unsupported XML feature LINE 1: SELECT xmltext('x'|| '

73

'::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,''), + 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) + +SELECT xmldocument('bar'::xml); +ERROR: unsupported XML feature +LINE 1: SELECT xmldocument('bar'::xml); + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmldocument('foo'::xml); +ERROR: unsupported XML feature +LINE 1: SELECT xmldocument('foo'::xml); + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmldocument('foo'); +ERROR: unsupported XML feature +LINE 1: SELECT xmldocument('foo'); + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmldocument(''); +ERROR: unsupported XML feature +LINE 1: SELECT xmldocument(''); + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmldocument(' '); +ERROR: unsupported XML feature +LINE 1: SELECT xmldocument(' '); + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmldocument(xmlcomment('comment')); +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out index 045641dae649..48cb71bd793b 100644 --- a/src/test/regress/expected/xml_2.out +++ b/src/test/regress/expected/xml_2.out @@ -1863,3 +1863,61 @@ SELECT xmltext('x'|| '

73

'::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,''), + xmlelement(NAME bar, xmlconcat('va', 'lue')), + xmlpi(name pi), + xmlelement(NAME txt, xmltext('<"&>')) + ) + ); + xmldocument +------------------------------------------------------------------------------------------------------------------------ + <foo&bar>value<"&> +(1 row) + +SELECT xmldocument(NULL); + xmldocument +------------- + +(1 row) + +SELECT xmldocument('bar'::xml); + xmldocument +---------------- + bar +(1 row) + +SELECT xmldocument('foo'::xml); + xmldocument +------------- + foo +(1 row) + +SELECT xmldocument('foo'); + xmldocument +------------- + foo +(1 row) + +SELECT xmldocument(''); + xmldocument +------------- + +(1 row) + +SELECT xmldocument(' '); + xmldocument +------------- + +(1 row) + +SELECT xmldocument(xmlcomment('comment')); + xmldocument +---------------- + +(1 row) + diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index 4c3520ce8980..082926d8b847 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -677,3 +677,22 @@ SELECT xmltext(' '); SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}'); SELECT xmltext('foo & <"bar">'); SELECT xmltext('x'|| '

73

'::xml || .42 || true || 'j'::char); + +SELECT + xmldocument( + xmlelement(NAME root, + xmlattributes(42 AS att), + xmlcomment('comment'), + xmlelement(NAME foo,''), + xmlelement(NAME bar, xmlconcat('va', 'lue')), + xmlpi(name pi), + xmlelement(NAME txt, xmltext('<"&>')) + ) + ); +SELECT xmldocument(NULL); +SELECT xmldocument('bar'::xml); +SELECT xmldocument('foo'::xml); +SELECT xmldocument('foo'); +SELECT xmldocument(''); +SELECT xmldocument(' '); +SELECT xmldocument(xmlcomment('comment'));