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.
</para>
</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>
</para>

View File

@ -14180,6 +14180,36 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
documents for processing in client applications.
</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">
<title><literal>xmlcomment</literal></title>

View File

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

View File

@ -47,6 +47,7 @@
#ifdef USE_LIBXML
#include <libxml/chvalid.h>
#include <libxml/entities.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.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

View File

@ -8793,6 +8793,9 @@
{ oid => '2922', descr => 'serialize an XML value to a character string',
proname => 'text', prorettype => 'text', proargtypes => 'xml',
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',
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;
(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/>"');
ERROR: unsupported XML feature
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;
(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
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);