Skip to content

Commit 526fe0d

Browse files
Add XMLText function (SQL/XML X038)
This function implements the standard XMLTest function, which converts text into xml text nodes. It uses the libxml2 function xmlEncodeSpecialChars to escape predefined entities (&"<>), so that those do not cause any conflict when concatenating the text node output with existing xml documents. This also adds a note in features.sgml about not supporting XML(SEQUENCE). The SQL specification defines a RETURNING clause to a set of XML functions, where RETURNING CONTENT or RETURNING SEQUENCE can be defined. Since PostgreSQL doesn't support XML(SEQUENCE) all of these functions operate with an implicit RETURNING CONTENT. Author: Jim Jones <jim.jones@uni-muenster.de> Reviewed-by: Vik Fearing <vik@postgresfriends.org> Discussion: https://postgr.es/m/86617a66-ec95-581f-8d54-08059cca8885@uni-muenster.de
1 parent 7b5275e commit 526fe0d

File tree

9 files changed

+167
-1
lines changed

9 files changed

+167
-1
lines changed

doc/src/sgml/features.sgml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@
199199
standard.
200200
</para>
201201
</listitem>
202+
203+
<listitem>
204+
<para>
205+
<productname>PostgreSQL</productname> does not support the
206+
<literal>RETURNING CONTENT</literal> or <literal>RETURNING SEQUENCE</literal>
207+
clauses, functions which are defined to have these in the specification
208+
are implicitly returning content.
209+
</para>
210+
</listitem>
202211
</itemizedlist>
203212
</para>
204213

doc/src/sgml/func.sgml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14180,6 +14180,36 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
1418014180
documents for processing in client applications.
1418114181
</para>
1418214182

14183+
<sect3 id="functions-producing-xml-xmltext">
14184+
<title><literal>xmltext</literal></title>
14185+
14186+
<indexterm>
14187+
<primary>xmltext</primary>
14188+
</indexterm>
14189+
14190+
<synopsis>
14191+
<function>xmltext</function> ( <type>text</type> ) <returnvalue>xml</returnvalue>
14192+
</synopsis>
14193+
14194+
<para>
14195+
The function <function>xmltext</function> returns an XML value with a single
14196+
text node containing the input argument as its content. Predefined entities
14197+
like ampersand (<literal><![CDATA[&]]></literal>), left and right angle brackets
14198+
(<literal><![CDATA[< >]]></literal>), and quotation marks (<literal><![CDATA[""]]></literal>)
14199+
are escaped.
14200+
</para>
14201+
14202+
<para>
14203+
Example:
14204+
<screen><![CDATA[
14205+
SELECT xmltext('< foo & bar >');
14206+
xmltext
14207+
-------------------------
14208+
&lt; foo &amp; bar &gt;
14209+
]]></screen>
14210+
</para>
14211+
</sect3>
14212+
1418314213
<sect3 id="functions-producing-xml-xmlcomment">
1418414214
<title><literal>xmlcomment</literal></title>
1418514215

src/backend/catalog/sql_features.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ X034 XMLAgg YES
633633
X035 XMLAgg: ORDER BY option YES
634634
X036 XMLComment YES
635635
X037 XMLPI YES
636-
X038 XMLText NO
636+
X038 XMLText YES supported except for RETURNING
637637
X040 Basic table mapping YES
638638
X041 Basic table mapping: null absent YES
639639
X042 Basic table mapping: null as nil YES

src/backend/utils/adt/xml.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747

4848
#ifdef USE_LIBXML
4949
#include <libxml/chvalid.h>
50+
#include <libxml/entities.h>
5051
#include <libxml/parser.h>
5152
#include <libxml/parserInternals.h>
5253
#include <libxml/tree.h>
@@ -513,6 +514,27 @@ xmlcomment(PG_FUNCTION_ARGS)
513514
}
514515

515516

517+
Datum
518+
xmltext(PG_FUNCTION_ARGS)
519+
{
520+
#ifdef USE_LIBXML
521+
text *arg = PG_GETARG_TEXT_PP(0);
522+
text *result;
523+
xmlChar *xmlbuf = NULL;
524+
525+
xmlbuf = xmlEncodeSpecialChars(NULL, xml_text2xmlChar(arg));
526+
527+
Assert(xmlbuf);
528+
529+
result = cstring_to_text_with_len((const char *) xmlbuf, xmlStrlen(xmlbuf));
530+
xmlFree(xmlbuf);
531+
PG_RETURN_XML_P(result);
532+
#else
533+
NO_XML_SUPPORT();
534+
return 0;
535+
#endif /* not USE_LIBXML */
536+
}
537+
516538

517539
/*
518540
* TODO: xmlconcat needs to merge the notations and unparsed entities

src/include/catalog/pg_proc.dat

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8793,6 +8793,9 @@
87938793
{ oid => '2922', descr => 'serialize an XML value to a character string',
87948794
proname => 'text', prorettype => 'text', proargtypes => 'xml',
87958795
prosrc => 'xmltotext' },
8796+
{ oid => '3813', descr => 'generate XML text node',
8797+
proname => 'xmltext', proisstrict => 't', prorettype => 'xml',
8798+
proargtypes => 'text', prosrc => 'xmltext' },
87968799

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

src/test/regress/expected/xml.out

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,3 +1785,39 @@ SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH
17851785
<foo/> | &lt;foo/&gt;
17861786
(1 row)
17871787

1788+
SELECT xmltext(NULL);
1789+
xmltext
1790+
---------
1791+
1792+
(1 row)
1793+
1794+
SELECT xmltext('');
1795+
xmltext
1796+
---------
1797+
1798+
(1 row)
1799+
1800+
SELECT xmltext(' ');
1801+
xmltext
1802+
---------
1803+
1804+
(1 row)
1805+
1806+
SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}');
1807+
xmltext
1808+
--------------------------
1809+
foo `$_-+?=*^%!|/\()[]{}
1810+
(1 row)
1811+
1812+
SELECT xmltext('foo & <"bar">');
1813+
xmltext
1814+
-----------------------------------
1815+
foo &amp; &lt;&quot;bar&quot;&gt;
1816+
(1 row)
1817+
1818+
SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);
1819+
xmltext
1820+
---------------------------------
1821+
x&lt;P&gt;73&lt;/P&gt;0.42truej
1822+
(1 row)
1823+

src/test/regress/expected/xml_1.out

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,3 +1402,26 @@ DETAIL: This functionality requires the server to be built with libxml support.
14021402
SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH '"<foo/>"', b xml PATH '"<foo/>"');
14031403
ERROR: unsupported XML feature
14041404
DETAIL: This functionality requires the server to be built with libxml support.
1405+
SELECT xmltext(NULL);
1406+
xmltext
1407+
---------
1408+
1409+
(1 row)
1410+
1411+
SELECT xmltext('');
1412+
ERROR: unsupported XML feature
1413+
DETAIL: This functionality requires the server to be built with libxml support.
1414+
SELECT xmltext(' ');
1415+
ERROR: unsupported XML feature
1416+
DETAIL: This functionality requires the server to be built with libxml support.
1417+
SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}');
1418+
ERROR: unsupported XML feature
1419+
DETAIL: This functionality requires the server to be built with libxml support.
1420+
SELECT xmltext('foo & <"bar">');
1421+
ERROR: unsupported XML feature
1422+
DETAIL: This functionality requires the server to be built with libxml support.
1423+
SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);
1424+
ERROR: unsupported XML feature
1425+
LINE 1: SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j':...
1426+
^
1427+
DETAIL: This functionality requires the server to be built with libxml support.

src/test/regress/expected/xml_2.out

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,3 +1765,39 @@ SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH
17651765
<foo/> | &lt;foo/&gt;
17661766
(1 row)
17671767

1768+
SELECT xmltext(NULL);
1769+
xmltext
1770+
---------
1771+
1772+
(1 row)
1773+
1774+
SELECT xmltext('');
1775+
xmltext
1776+
---------
1777+
1778+
(1 row)
1779+
1780+
SELECT xmltext(' ');
1781+
xmltext
1782+
---------
1783+
1784+
(1 row)
1785+
1786+
SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}');
1787+
xmltext
1788+
--------------------------
1789+
foo `$_-+?=*^%!|/\()[]{}
1790+
(1 row)
1791+
1792+
SELECT xmltext('foo & <"bar">');
1793+
xmltext
1794+
-----------------------------------
1795+
foo &amp; &lt;&quot;bar&quot;&gt;
1796+
(1 row)
1797+
1798+
SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);
1799+
xmltext
1800+
---------------------------------
1801+
x&lt;P&gt;73&lt;/P&gt;0.42truej
1802+
(1 row)
1803+

src/test/regress/sql/xml.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,3 +660,10 @@ SELECT * FROM XMLTABLE('*' PASSING '<e>pre<!--c1--><?pi arg?><![CDATA[&ent1]]><n
660660
\x
661661

662662
SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH '"<foo/>"', b xml PATH '"<foo/>"');
663+
664+
SELECT xmltext(NULL);
665+
SELECT xmltext('');
666+
SELECT xmltext(' ');
667+
SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}');
668+
SELECT xmltext('foo & <"bar">');
669+
SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy