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
This commit is contained in:
Daniel Gustafsson 2023-11-06 09:38:29 +01:00
parent 7b5275eec3
commit 526fe0d799
9 changed files with 167 additions and 1 deletions

View File

@ -199,6 +199,15 @@
standard. standard.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<productname>PostgreSQL</productname> does not support the
<literal>RETURNING CONTENT</literal> or <literal>RETURNING SEQUENCE</literal>
clauses, functions which are defined to have these in the specification
are implicitly returning content.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</para> </para>

View File

@ -14180,6 +14180,36 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
documents for processing in client applications. documents for processing in client applications.
</para> </para>
<sect3 id="functions-producing-xml-xmltext">
<title><literal>xmltext</literal></title>
<indexterm>
<primary>xmltext</primary>
</indexterm>
<synopsis>
<function>xmltext</function> ( <type>text</type> ) <returnvalue>xml</returnvalue>
</synopsis>
<para>
The function <function>xmltext</function> returns an XML value with a single
text node containing the input argument as its content. Predefined entities
like ampersand (<literal><![CDATA[&]]></literal>), left and right angle brackets
(<literal><![CDATA[< >]]></literal>), and quotation marks (<literal><![CDATA[""]]></literal>)
are escaped.
</para>
<para>
Example:
<screen><![CDATA[
SELECT xmltext('< foo & bar >');
xmltext
-------------------------
&lt; foo &amp; bar &gt;
]]></screen>
</para>
</sect3>
<sect3 id="functions-producing-xml-xmlcomment"> <sect3 id="functions-producing-xml-xmlcomment">
<title><literal>xmlcomment</literal></title> <title><literal>xmlcomment</literal></title>

View File

@ -633,7 +633,7 @@ X034 XMLAgg YES
X035 XMLAgg: ORDER BY option YES X035 XMLAgg: ORDER BY option YES
X036 XMLComment YES X036 XMLComment YES
X037 XMLPI YES X037 XMLPI YES
X038 XMLText NO X038 XMLText YES supported except for RETURNING
X040 Basic table mapping YES X040 Basic table mapping YES
X041 Basic table mapping: null absent YES X041 Basic table mapping: null absent YES
X042 Basic table mapping: null as nil YES X042 Basic table mapping: null as nil YES

View File

@ -47,6 +47,7 @@
#ifdef USE_LIBXML #ifdef USE_LIBXML
#include <libxml/chvalid.h> #include <libxml/chvalid.h>
#include <libxml/entities.h>
#include <libxml/parser.h> #include <libxml/parser.h>
#include <libxml/parserInternals.h> #include <libxml/parserInternals.h>
#include <libxml/tree.h> #include <libxml/tree.h>
@ -513,6 +514,27 @@ xmlcomment(PG_FUNCTION_ARGS)
} }
Datum
xmltext(PG_FUNCTION_ARGS)
{
#ifdef USE_LIBXML
text *arg = PG_GETARG_TEXT_PP(0);
text *result;
xmlChar *xmlbuf = NULL;
xmlbuf = xmlEncodeSpecialChars(NULL, xml_text2xmlChar(arg));
Assert(xmlbuf);
result = cstring_to_text_with_len((const char *) xmlbuf, xmlStrlen(xmlbuf));
xmlFree(xmlbuf);
PG_RETURN_XML_P(result);
#else
NO_XML_SUPPORT();
return 0;
#endif /* not USE_LIBXML */
}
/* /*
* TODO: xmlconcat needs to merge the notations and unparsed entities * TODO: xmlconcat needs to merge the notations and unparsed entities

View File

@ -8793,6 +8793,9 @@
{ oid => '2922', descr => 'serialize an XML value to a character string', { oid => '2922', descr => 'serialize an XML value to a character string',
proname => 'text', prorettype => 'text', proargtypes => 'xml', proname => 'text', prorettype => 'text', proargtypes => 'xml',
prosrc => 'xmltotext' }, prosrc => 'xmltotext' },
{ oid => '3813', descr => 'generate XML text node',
proname => 'xmltext', proisstrict => 't', prorettype => 'xml',
proargtypes => 'text', prosrc => 'xmltext' },
{ oid => '2923', descr => 'map table contents to XML', { oid => '2923', descr => 'map table contents to XML',
proname => 'table_to_xml', procost => '100', provolatile => 's', proname => 'table_to_xml', procost => '100', provolatile => 's',

View File

@ -1785,3 +1785,39 @@ SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH
<foo/> | &lt;foo/&gt; <foo/> | &lt;foo/&gt;
(1 row) (1 row)
SELECT xmltext(NULL);
xmltext
---------
(1 row)
SELECT xmltext('');
xmltext
---------
(1 row)
SELECT xmltext(' ');
xmltext
---------
(1 row)
SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}');
xmltext
--------------------------
foo `$_-+?=*^%!|/\()[]{}
(1 row)
SELECT xmltext('foo & <"bar">');
xmltext
-----------------------------------
foo &amp; &lt;&quot;bar&quot;&gt;
(1 row)
SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);
xmltext
---------------------------------
x&lt;P&gt;73&lt;/P&gt;0.42truej
(1 row)

View File

@ -1402,3 +1402,26 @@ DETAIL: This functionality requires the server to be built with libxml support.
SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH '"<foo/>"', b xml PATH '"<foo/>"'); SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH '"<foo/>"', b xml PATH '"<foo/>"');
ERROR: unsupported XML feature ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support. DETAIL: This functionality requires the server to be built with libxml support.
SELECT xmltext(NULL);
xmltext
---------
(1 row)
SELECT xmltext('');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
SELECT xmltext(' ');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
SELECT xmltext('foo & <"bar">');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);
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.

View File

@ -1765,3 +1765,39 @@ SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH
<foo/> | &lt;foo/&gt; <foo/> | &lt;foo/&gt;
(1 row) (1 row)
SELECT xmltext(NULL);
xmltext
---------
(1 row)
SELECT xmltext('');
xmltext
---------
(1 row)
SELECT xmltext(' ');
xmltext
---------
(1 row)
SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}');
xmltext
--------------------------
foo `$_-+?=*^%!|/\()[]{}
(1 row)
SELECT xmltext('foo & <"bar">');
xmltext
-----------------------------------
foo &amp; &lt;&quot;bar&quot;&gt;
(1 row)
SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);
xmltext
---------------------------------
x&lt;P&gt;73&lt;/P&gt;0.42truej
(1 row)

View File

@ -660,3 +660,10 @@ SELECT * FROM XMLTABLE('*' PASSING '<e>pre<!--c1--><?pi arg?><![CDATA[&ent1]]><n
\x \x
SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH '"<foo/>"', b xml PATH '"<foo/>"'); SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH '"<foo/>"', b xml PATH '"<foo/>"');
SELECT xmltext(NULL);
SELECT xmltext('');
SELECT xmltext(' ');
SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}');
SELECT xmltext('foo & <"bar">');
SELECT xmltext('x'|| '<P>73</P>'::xml || .42 || true || 'j'::char);