Skip to content

Commit 9629b26

Browse files
jimjonesbrCommitfest Bot
authored and
Commitfest Bot
committed
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. 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. While this implementation is quite trivial, it follows the SQL/XML standard and facilitates the migration of SQL statements from other database systems that also support X030. Usage: WITH t(x) AS ( VALUES (xmlparse(DOCUMENT '<root><foo>bar</foo></root>')), (xmlforest(42 AS foo, 73 AS bar)), (NULL) ) SELECT xmldocument(x) FROM t; xmldocument ----------------------------- <root><foo>bar</foo></root> <foo>42</foo><bar>73</bar> (3 rows) This patch also adds documentation and tests.
1 parent eec3409 commit 9629b26

File tree

8 files changed

+258
-1
lines changed

8 files changed

+258
-1
lines changed

doc/src/sgml/func.sgml

+54
Original file line numberDiff line numberDiff line change
@@ -14655,6 +14655,60 @@ SELECT xmlcomment('hello');
1465514655
</para>
1465614656
</sect3>
1465714657

14658+
<sect3 id="functions-producing-xml-xmldocument">
14659+
<title><literal>xmldocument</literal></title>
14660+
14661+
<indexterm>
14662+
<primary>xmldocument</primary>
14663+
</indexterm>
14664+
14665+
<synopsis>
14666+
<function>xmldocument</function> ( <type>xml</type> ) <returnvalue>xml</returnvalue>
14667+
</synopsis>
14668+
14669+
<para>
14670+
The <function>xmldocument</function> function returns the input argument
14671+
unchanged, or <literal>NULL</literal> if the argument is <literal>NULL</literal>,
14672+
and is provided for compatibility.
14673+
14674+
The SQL-standard <replaceable>XMLDocument</replaceable> function applied to an
14675+
XML value <literal>$EXPR</literal>, has effects equivalent to the XML
14676+
Query expression <replaceable>document { $EXPR }</replaceable>. It replaces any
14677+
document nodes in the input with their children and wraps the whole result in a
14678+
single <replaceable>document node</replaceable>.
14679+
14680+
In the XML Query standard, a <replaceable>document node</replaceable> represents
14681+
a relaxed version of an XML document structure. This corresponds to what PostgreSQL's
14682+
single XML type allows, meaning that any valid non-null PostgreSQL XML value can be
14683+
returned unchanged. Other systems may support more permissive XML data types,
14684+
such as <literal>XML(SEQUENCE)</literal>, which allow values that do not conform to
14685+
this structure. In PostgreSQL, every valid non-null value of the XML type already has
14686+
that structure, making additional processing by this function unnecessary.
14687+
</para>
14688+
14689+
<para>
14690+
Example:
14691+
<screen><![CDATA[
14692+
WITH xmldata (val) AS (
14693+
VALUES
14694+
(xmlparse(DOCUMENT '<root><foo>bar</foo></root>')),
14695+
(xmltext('foo&bar')),
14696+
(xmlelement(NAME el)),
14697+
(xmlforest(42 AS foo, 73 AS bar))
14698+
)
14699+
SELECT xmldocument(val) FROM xmldata;
14700+
14701+
xmldocument
14702+
-----------------------------
14703+
<root><foo>bar</foo></root>
14704+
foo&amp;bar
14705+
<el/>
14706+
<foo>42</foo><bar>73</bar>
14707+
(4 rows)
14708+
]]></screen>
14709+
</para>
14710+
</sect3>
14711+
1465814712
<sect3 id="functions-producing-xml-xmlconcat">
1465914713
<title><literal>xmlconcat</literal></title>
1466014714

src/backend/catalog/sql_features.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ X015 Fields of XML type NO
625625
X016 Persistent XML values YES
626626
X020 XMLConcat YES
627627
X025 XMLCast NO
628-
X030 XMLDocument NO
628+
X030 XMLDocument YES
629629
X031 XMLElement YES
630630
X032 XMLForest YES
631631
X034 XMLAgg YES

src/backend/utils/adt/xml.c

+18
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,24 @@ xmlcomment(PG_FUNCTION_ARGS)
523523
}
524524

525525

526+
/*
527+
* xmldocument implements the SQL/XML function XMLDocument (X030).
528+
* Since our XML data type corresponds to XML(CONTENT(ANY)), any
529+
* expression already validated by the input function is considered
530+
* valid output for XMLDocument. As a result, this function simply
531+
* returns its input value.
532+
*/
533+
Datum
534+
xmldocument(PG_FUNCTION_ARGS)
535+
{
536+
#ifdef USE_LIBXML
537+
PG_RETURN_DATUM(PG_GETARG_DATUM(0));
538+
#else
539+
NO_XML_SUPPORT();
540+
return 0;
541+
#endif /* not USE_LIBXML */
542+
}
543+
526544
Datum
527545
xmltext(PG_FUNCTION_ARGS)
528546
{

src/include/catalog/pg_proc.dat

+3
Original file line numberDiff line numberDiff line change
@@ -9143,6 +9143,9 @@
91439143
{ oid => '3813', descr => 'generate XML text node',
91449144
proname => 'xmltext', prorettype => 'xml', proargtypes => 'text',
91459145
prosrc => 'xmltext' },
9146+
{ oid => '3814', descr => 'generate XML document',
9147+
proname => 'xmldocument', prorettype => 'xml', proargtypes => 'xml',
9148+
prosrc => 'xmldocument'},
91469149

91479150
{ oid => '2923', descr => 'map table contents to XML',
91489151
proname => 'table_to_xml', procost => '100', provolatile => 's',

src/test/regress/expected/xml.out

+58
Original file line numberDiff line numberDiff line change
@@ -1877,3 +1877,61 @@ SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);
18771877
x&lt;P&gt;73&lt;/P&gt;0.42truej
18781878
(1 row)
18791879

1880+
SELECT
1881+
xmldocument(
1882+
xmlelement(NAME root,
1883+
xmlattributes(42 AS att),
1884+
xmlcomment('comment'),
1885+
xmlelement(NAME foo,'<foo&bar>'),
1886+
xmlelement(NAME bar, xmlconcat('va', 'lue')),
1887+
xmlpi(name pi),
1888+
xmlelement(NAME txt, xmltext('<"&>'))
1889+
)
1890+
);
1891+
xmldocument
1892+
------------------------------------------------------------------------------------------------------------------------
1893+
<root att="42"><!--comment--><foo>&lt;foo&amp;bar&gt;</foo><bar>value</bar><?pi?><txt>&lt;&quot;&amp;&gt;</txt></root>
1894+
(1 row)
1895+
1896+
SELECT xmldocument(NULL);
1897+
xmldocument
1898+
-------------
1899+
1900+
(1 row)
1901+
1902+
SELECT xmldocument('<foo>bar</foo>'::xml);
1903+
xmldocument
1904+
----------------
1905+
<foo>bar</foo>
1906+
(1 row)
1907+
1908+
SELECT xmldocument('foo'::xml);
1909+
xmldocument
1910+
-------------
1911+
foo
1912+
(1 row)
1913+
1914+
SELECT xmldocument('foo');
1915+
xmldocument
1916+
-------------
1917+
foo
1918+
(1 row)
1919+
1920+
SELECT xmldocument('');
1921+
xmldocument
1922+
-------------
1923+
1924+
(1 row)
1925+
1926+
SELECT xmldocument(' ');
1927+
xmldocument
1928+
-------------
1929+
1930+
(1 row)
1931+
1932+
SELECT xmldocument(xmlcomment('comment'));
1933+
xmldocument
1934+
----------------
1935+
<!--comment-->
1936+
(1 row)
1937+

src/test/regress/expected/xml_1.out

+47
Original file line numberDiff line numberDiff line change
@@ -1492,3 +1492,50 @@ ERROR: unsupported XML feature
14921492
LINE 1: SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j':...
14931493
^
14941494
DETAIL: This functionality requires the server to be built with libxml support.
1495+
SELECT
1496+
xmldocument(
1497+
xmlelement(NAME root,
1498+
xmlattributes(42 AS att),
1499+
xmlcomment('comment'),
1500+
xmlelement(NAME foo,'<foo&bar>'),
1501+
xmlelement(NAME bar, xmlconcat('va', 'lue')),
1502+
xmlpi(name pi),
1503+
xmlelement(NAME txt, xmltext('<"&>'))
1504+
)
1505+
);
1506+
ERROR: unsupported XML feature
1507+
DETAIL: This functionality requires the server to be built with libxml support.
1508+
SELECT xmldocument(NULL);
1509+
xmldocument
1510+
-------------
1511+
1512+
(1 row)
1513+
1514+
SELECT xmldocument('<foo>bar</foo>'::xml);
1515+
ERROR: unsupported XML feature
1516+
LINE 1: SELECT xmldocument('<foo>bar</foo>'::xml);
1517+
^
1518+
DETAIL: This functionality requires the server to be built with libxml support.
1519+
SELECT xmldocument('foo'::xml);
1520+
ERROR: unsupported XML feature
1521+
LINE 1: SELECT xmldocument('foo'::xml);
1522+
^
1523+
DETAIL: This functionality requires the server to be built with libxml support.
1524+
SELECT xmldocument('foo');
1525+
ERROR: unsupported XML feature
1526+
LINE 1: SELECT xmldocument('foo');
1527+
^
1528+
DETAIL: This functionality requires the server to be built with libxml support.
1529+
SELECT xmldocument('');
1530+
ERROR: unsupported XML feature
1531+
LINE 1: SELECT xmldocument('');
1532+
^
1533+
DETAIL: This functionality requires the server to be built with libxml support.
1534+
SELECT xmldocument(' ');
1535+
ERROR: unsupported XML feature
1536+
LINE 1: SELECT xmldocument(' ');
1537+
^
1538+
DETAIL: This functionality requires the server to be built with libxml support.
1539+
SELECT xmldocument(xmlcomment('comment'));
1540+
ERROR: unsupported XML feature
1541+
DETAIL: This functionality requires the server to be built with libxml support.

src/test/regress/expected/xml_2.out

+58
Original file line numberDiff line numberDiff line change
@@ -1863,3 +1863,61 @@ SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);
18631863
x&lt;P&gt;73&lt;/P&gt;0.42truej
18641864
(1 row)
18651865

1866+
SELECT
1867+
xmldocument(
1868+
xmlelement(NAME root,
1869+
xmlattributes(42 AS att),
1870+
xmlcomment('comment'),
1871+
xmlelement(NAME foo,'<foo&bar>'),
1872+
xmlelement(NAME bar, xmlconcat('va', 'lue')),
1873+
xmlpi(name pi),
1874+
xmlelement(NAME txt, xmltext('<"&>'))
1875+
)
1876+
);
1877+
xmldocument
1878+
------------------------------------------------------------------------------------------------------------------------
1879+
<root att="42"><!--comment--><foo>&lt;foo&amp;bar&gt;</foo><bar>value</bar><?pi?><txt>&lt;&quot;&amp;&gt;</txt></root>
1880+
(1 row)
1881+
1882+
SELECT xmldocument(NULL);
1883+
xmldocument
1884+
-------------
1885+
1886+
(1 row)
1887+
1888+
SELECT xmldocument('<foo>bar</foo>'::xml);
1889+
xmldocument
1890+
----------------
1891+
<foo>bar</foo>
1892+
(1 row)
1893+
1894+
SELECT xmldocument('foo'::xml);
1895+
xmldocument
1896+
-------------
1897+
foo
1898+
(1 row)
1899+
1900+
SELECT xmldocument('foo');
1901+
xmldocument
1902+
-------------
1903+
foo
1904+
(1 row)
1905+
1906+
SELECT xmldocument('');
1907+
xmldocument
1908+
-------------
1909+
1910+
(1 row)
1911+
1912+
SELECT xmldocument(' ');
1913+
xmldocument
1914+
-------------
1915+
1916+
(1 row)
1917+
1918+
SELECT xmldocument(xmlcomment('comment'));
1919+
xmldocument
1920+
----------------
1921+
<!--comment-->
1922+
(1 row)
1923+

src/test/regress/sql/xml.sql

+19
Original file line numberDiff line numberDiff line change
@@ -677,3 +677,22 @@ SELECT xmltext(' ');
677677
SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}');
678678
SELECT xmltext('foo & <"bar">');
679679
SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);
680+
681+
SELECT
682+
xmldocument(
683+
xmlelement(NAME root,
684+
xmlattributes(42 AS att),
685+
xmlcomment('comment'),
686+
xmlelement(NAME foo,'<foo&bar>'),
687+
xmlelement(NAME bar, xmlconcat('va', 'lue')),
688+
xmlpi(name pi),
689+
xmlelement(NAME txt, xmltext('<"&>'))
690+
)
691+
);
692+
SELECT xmldocument(NULL);
693+
SELECT xmldocument('<foo>bar</foo>'::xml);
694+
SELECT xmldocument('foo'::xml);
695+
SELECT xmldocument('foo');
696+
SELECT xmldocument('');
697+
SELECT xmldocument(' ');
698+
SELECT xmldocument(xmlcomment('comment'));

0 commit comments

Comments
 (0)