Various fixes in the logic of XML functions:

- Add new SQL command SET XML OPTION (also available via regular GUC) to
  control the DOCUMENT vs. CONTENT option in implicit parsing and
  serialization operations.

- Subtle corrections in the handling of the standalone property in
  xmlroot().

- Allow xmlroot() to work on content fragments.

- Subtle corrections in the handling of the version property in
  xmlconcat().

- Code refactoring for producing XML declarations.
This commit is contained in:
Peter Eisentraut 2007-01-25 11:53:52 +00:00
parent 9597446d11
commit 22bd156ff0
13 changed files with 329 additions and 121 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.105 2007/01/25 04:35:10 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.106 2007/01/25 11:53:50 petere Exp $ -->
<chapter Id="runtime-config">
<title>Server Configuration</title>
@ -3558,6 +3558,38 @@ SELECT * FROM parent WHERE key = 2400;
</listitem>
</varlistentry>
<varlistentry id="guc-xmloption" xreflabel="xmloption">
<term><varname>xmloption</varname> (<type>string</type>)</term>
<indexterm>
<primary><varname>xmloption</> configuration parameter</primary>
</indexterm>
<indexterm>
<primary><varname>SET XML OPTION</></primary>
</indexterm>
<indexterm>
<primary><varname>XML option</></primary>
</indexterm>
<listitem>
<para>
Sets whether <literal>DOCUMENT</literal> or
<literal>CONTENT</literal> is implicit when converting between
XML and character string values. See <xref
linkend="datatype-xml"> for a description of this. Valid
values are <literal>DOCUMENT</literal> and
<literal>CONTENT</literal>. The default is
<literal>CONTENT</literal>.
</para>
<para>
According to the SQL standard, the command to set this option is
<synopsis>
SET XML OPTION { DOCUMENT | CONTENT };
</synopsis>
This syntax is also available in PostgreSQL.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="runtime-config-client-format">

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.185 2007/01/18 13:59:11 petere Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.186 2007/01/25 11:53:50 petere Exp $ -->
<chapter id="datatype">
<title id="datatype-title">Data Types</title>
@ -3474,6 +3474,24 @@ XMLSERIALIZE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable> AS <repla
you to simply cast the value.
</para>
<para>
When character string values are cast to or from type
<type>xml</type> without going through <type>XMLPARSE</type> or
<type>XMLSERIALIZE</type>, respectively, the choice of
<literal>DOCUMENT</literal> versus <literal>CONTENT</literal> is
determined by the <quote>XML option</quote> session configuration
parameter, which can be set using the standard command
<synopsis>
SET XML OPTION { DOCUMENT | CONTENT };
</synopsis>
or the more PostgreSQL-like syntax
<synopsis>
SET xmloption TO { DOCUMENT | CONTENT };
</synopsis>
The default is <literal>CONTENT</literal>, so all forms of XML
data are allowed.
</para>
<para>
Care must be taken when dealing with multiple character encodings
on the client, server, and in the XML data passed through them.

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.208 2007/01/20 09:27:19 petere Exp $
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.209 2007/01/25 11:53:50 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -2797,10 +2797,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
e = (ExprState *) lthird(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL);
if (isnull)
standalone = 0;
else
standalone = (DatumGetBool(value) ? 1 : -1);
standalone = DatumGetInt32(value);
*isNull = false;

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.576 2007/01/23 05:07:17 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.577 2007/01/25 11:53:51 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -60,6 +60,7 @@
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/numeric.h"
#include "utils/xml.h"
/* Location tracking support --- simpler than bison's default */
@ -439,7 +440,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
XMLPI XMLROOT XMLSERIALIZE
YEAR_P YES_P
@ -1112,6 +1113,13 @@ set_rest: var_name TO var_list_or_default
n->args = NIL;
$$ = n;
}
| XML_P OPTION document_or_content
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "xmloption";
n->args = list_make1(makeStringConst($3 ? "DOCUMENT" : "CONTENT", NULL));
$$ = n;
}
;
var_name:
@ -7938,21 +7946,13 @@ xml_root_version: VERSION_P a_expr
;
opt_xml_root_standalone: ',' STANDALONE_P YES_P
{ $$ = (Node *) makeBoolAConst(true); }
{ $$ = (Node *) makeIntConst(XML_STANDALONE_YES); }
| ',' STANDALONE_P NO
{ $$ = (Node *) makeBoolAConst(false); }
{ $$ = (Node *) makeIntConst(XML_STANDALONE_NO); }
| ',' STANDALONE_P NO VALUE_P
{
A_Const *val = makeNode(A_Const);
val->val.type = T_Null;
$$ = (Node *) val;
}
{ $$ = (Node *) makeIntConst(XML_STANDALONE_NO_VALUE); }
| /*EMPTY*/
{
A_Const *val = makeNode(A_Const);
val->val.type = T_Null;
$$ = (Node *) val;
}
{ $$ = (Node *) makeIntConst(XML_STANDALONE_OMITTED); }
;
xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
@ -8864,6 +8864,7 @@ unreserved_keyword:
| WITHOUT
| WORK
| WRITE
| XML_P
| YEAR_P
| YES_P
| ZONE

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.183 2007/01/23 05:07:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.184 2007/01/25 11:53:51 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -380,6 +380,7 @@ static const ScanKeyword ScanKeywords[] = {
{"without", WITHOUT},
{"work", WORK},
{"write", WRITE},
{"xml", XML_P},
{"xmlattributes", XMLATTRIBUTES},
{"xmlconcat", XMLCONCAT},
{"xmlelement", XMLELEMENT},

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.208 2007/01/14 13:11:53 petere Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.209 2007/01/25 11:53:51 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -1481,7 +1481,8 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
newe = coerce_to_specific_type(pstate, newe, TEXTOID,
"XMLROOT");
else
newe = coerce_to_boolean(pstate, newe, "XMLROOT");
newe = coerce_to_specific_type(pstate, newe, INT4OID,
"XMLROOT");
break;
case IS_DOCUMENT:
newe = coerce_to_specific_type(pstate, newe, XMLOID,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.21 2007/01/23 23:39:16 petere Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.22 2007/01/25 11:53:51 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -67,11 +67,14 @@ static void xml_ereport_by_code(int level, int sqlcode,
const char *msg, int errcode);
static xmlChar *xml_text2xmlChar(text *in);
static int parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone);
static bool print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone);
static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encoding);
#endif /* USE_LIBXML */
XmlBinaryType xmlbinary;
XmlOptionType xmloption;
#define NO_XML_SUPPORT() \
ereport(ERROR, \
@ -97,7 +100,7 @@ xml_in(PG_FUNCTION_ARGS)
* Parse the data to check if it is well-formed XML data. Assume
* that ERROR occurred if parsing failed.
*/
doc = xml_parse(vardata, false, true, NULL);
doc = xml_parse(vardata, (xmloption == XMLOPTION_DOCUMENT), true, NULL);
xmlFreeDoc(doc);
PG_RETURN_XML_P(vardata);
@ -129,48 +132,13 @@ xml_out_internal(xmltype *x, pg_enc target_encoding)
str[len] = '\0';
#ifdef USE_LIBXML
/*
* On output, we adjust the XML declaration as follows. (These
* rules are the moral equivalent of the clause "Serialization of
* an XML value" in the SQL standard.)
*
* We try to avoid generating an XML declaration if possible.
* This is so that you don't get trivial things like xml '<foo/>'
* resulting in '<?xml version="1.0"?><foo/>', which would surely
* be annoying. We must provide a declaration if the standalone
* property is specified or if we include an encoding
* specification. If we have a declaration, we must specify a
* version (XML requires this). Otherwise we only make a
* declaration if the version is not "1.0", which is the default
* version specified in SQL:2003.
*/
if ((res_code = parse_xml_decl((xmlChar *) str, &len, &version, &encoding, &standalone)) == 0)
{
StringInfoData buf;
initStringInfo(&buf);
if ((version && strcmp((char *) version, PG_XML_DEFAULT_VERSION) != 0)
|| (target_encoding && target_encoding != PG_UTF8)
|| standalone != -1)
{
appendStringInfoString(&buf, "<?xml");
if (version)
appendStringInfo(&buf, " version=\"%s\"", version);
else
appendStringInfo(&buf, " version=\"%s\"", PG_XML_DEFAULT_VERSION);
if (target_encoding && target_encoding != PG_UTF8)
/* XXX might be useful to convert this to IANA names
* (ISO-8859-1 instead of LATIN1 etc.); needs field
* experience */
appendStringInfo(&buf, " encoding=\"%s\"", pg_encoding_to_char(target_encoding));
if (standalone == 1)
appendStringInfoString(&buf, " standalone=\"yes\"");
else if (standalone == 0)
appendStringInfoString(&buf, " standalone=\"no\"");
appendStringInfoString(&buf, "?>");
}
else
if (!print_xml_decl(&buf, version, target_encoding, standalone))
{
/*
* If we are not going to produce an XML declaration, eat
@ -231,7 +199,7 @@ xml_recv(PG_FUNCTION_ARGS)
* Parse the data to check if it is well-formed XML data. Assume
* that ERROR occurred if parsing failed.
*/
doc = xml_parse(result, false, true, encoding);
doc = xml_parse(result, (xmloption == XMLOPTION_DOCUMENT), true, encoding);
xmlFreeDoc(doc);
newstr = (char *) pg_do_encoding_conversion((unsigned char *) str,
@ -296,6 +264,7 @@ stringinfo_to_xmltype(StringInfo buf)
}
#ifdef NOT_USED
static xmltype *
cstring_to_xmltype(const char *string)
{
@ -309,6 +278,7 @@ cstring_to_xmltype(const char *string)
return result;
}
#endif
static xmltype *
@ -394,9 +364,11 @@ xmlconcat(List *args)
if (standalone < 0)
global_standalone = -1;
if (!global_version)
if (!version)
global_version_no_value = true;
else if (!global_version)
global_version = xmlStrdup(version);
else if (version && xmlStrcmp(version, global_version) != 0)
else if (xmlStrcmp(version, global_version) != 0)
global_version_no_value = true;
appendStringInfoString(&buf, str + len);
@ -409,17 +381,10 @@ xmlconcat(List *args)
initStringInfo(&buf2);
if (!global_version_no_value && global_version)
appendStringInfo(&buf2, "<?xml version=\"%s\"", global_version);
else
appendStringInfo(&buf2, "<?xml version=\"%s\"", PG_XML_DEFAULT_VERSION);
if (global_standalone == 1)
appendStringInfoString(&buf2, " standalone=\"yes\"");
else if (global_standalone == 0)
appendStringInfoString(&buf2, " standalone=\"no\"");
appendStringInfoString(&buf2, "?>");
print_xml_decl(&buf2,
(!global_version_no_value && global_version) ? global_version : NULL,
0,
global_standalone);
appendStringInfoString(&buf2, buf.data);
buf = buf2;
@ -458,7 +423,7 @@ texttoxml(PG_FUNCTION_ARGS)
{
text *data = PG_GETARG_TEXT_P(0);
PG_RETURN_XML_P(xmlparse(data, false, true));
PG_RETURN_XML_P(xmlparse(data, (xmloption == XMLOPTION_DOCUMENT), true));
}
@ -595,44 +560,45 @@ xmltype *
xmlroot(xmltype *data, text *version, int standalone)
{
#ifdef USE_LIBXML
xmltype *result;
xmlDocPtr doc;
xmlBufferPtr buffer;
xmlSaveCtxtPtr save;
char *str;
size_t len;
xmlChar *orig_version;
int orig_standalone;
StringInfoData buf;
doc = xml_parse((text *) data, true, true, NULL);
len = VARSIZE(data) - VARHDRSZ;
str = palloc(len + 1);
memcpy(str, VARDATA(data), len);
str[len] = '\0';
parse_xml_decl((xmlChar *) str, &len, &orig_version, NULL, &orig_standalone);
if (version)
doc->version = xmlStrdup(xml_text2xmlChar(version));
orig_version = xml_text2xmlChar(version);
else
doc->version = NULL;
orig_version = NULL;
switch (standalone)
{
case 1:
doc->standalone = 1;
case XML_STANDALONE_YES:
orig_standalone = 1;
break;
case -1:
doc->standalone = 0;
case XML_STANDALONE_NO:
orig_standalone = 0;
break;
default:
doc->standalone = -1;
case XML_STANDALONE_NO_VALUE:
orig_standalone = -1;
break;
case XML_STANDALONE_OMITTED:
/* leave original value */
break;
}
buffer = xmlBufferCreate();
save = xmlSaveToBuffer(buffer, "UTF-8", 0);
xmlSaveDoc(save, doc);
xmlSaveClose(save);
initStringInfo(&buf);
print_xml_decl(&buf, orig_version, 0, orig_standalone);
appendStringInfoString(&buf, str + len);
xmlFreeDoc(doc);
result = cstring_to_xmltype((char *) pg_do_encoding_conversion((unsigned char *) xmlBufferContent(buffer),
xmlBufferLength(buffer),
PG_UTF8,
GetDatabaseEncoding()));
xmlBufferFree(buffer);
return result;
return stringinfo_to_xmltype(&buf);
#else
NO_XML_SUPPORT();
return NULL;
@ -971,6 +937,53 @@ finished:
}
/*
* Write an XML declaration. On output, we adjust the XML declaration
* as follows. (These rules are the moral equivalent of the clause
* "Serialization of an XML value" in the SQL standard.)
*
* We try to avoid generating an XML declaration if possible. This is
* so that you don't get trivial things like xml '<foo/>' resulting in
* '<?xml version="1.0"?><foo/>', which would surely be annoying. We
* must provide a declaration if the standalone property is specified
* or if we include an encoding declaration. If we have a
* declaration, we must specify a version (XML requires this).
* Otherwise we only make a declaration if the version is not "1.0",
* which is the default version specified in SQL:2003.
*/
static bool
print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone)
{
if ((version && strcmp((char *) version, PG_XML_DEFAULT_VERSION) != 0)
|| (encoding && encoding != PG_UTF8)
|| standalone != -1)
{
appendStringInfoString(buf, "<?xml");
if (version)
appendStringInfo(buf, " version=\"%s\"", version);
else
appendStringInfo(buf, " version=\"%s\"", PG_XML_DEFAULT_VERSION);
if (encoding && encoding != PG_UTF8)
/* XXX might be useful to convert this to IANA names
* (ISO-8859-1 instead of LATIN1 etc.); needs field
* experience */
appendStringInfo(buf, " encoding=\"%s\"", pg_encoding_to_char(encoding));
if (standalone == 1)
appendStringInfoString(buf, " standalone=\"yes\"");
else if (standalone == 0)
appendStringInfoString(buf, " standalone=\"no\"");
appendStringInfoString(buf, "?>");
return true;
}
else
return false;
}
/*
* Convert a C string to XML internal representation
*

View File

@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.370 2007/01/25 04:35:11 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.371 2007/01/25 11:53:51 petere Exp $
*
*--------------------------------------------------------------------
*/
@ -145,6 +145,7 @@ static const char *assign_canonical_path(const char *newval, bool doit, GucSourc
static const char *assign_backslash_quote(const char *newval, bool doit, GucSource source);
static const char *assign_timezone_abbreviations(const char *newval, bool doit, GucSource source);
static const char *assign_xmlbinary(const char *newval, bool doit, GucSource source);
static const char *assign_xmloption(const char *newval, bool doit, GucSource source);
static bool assign_tcp_keepalives_idle(int newval, bool doit, GucSource source);
static bool assign_tcp_keepalives_interval(int newval, bool doit, GucSource source);
@ -233,6 +234,7 @@ static char *XactIsoLevel_string;
static char *data_directory;
static char *custom_variable_classes;
static char *xmlbinary_string;
static char *xmloption_string;
static int max_function_args;
static int max_index_keys;
static int max_identifier_length;
@ -2292,6 +2294,16 @@ static struct config_string ConfigureNamesString[] =
"base64", assign_xmlbinary, NULL
},
{
{"xmloption", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets whether XML data in implicit parsing and serialization "
"operations is to be considered as documents or content fragments."),
gettext_noop("Valid values are DOCUMENT and CONTENT.")
},
&xmloption_string,
"content", assign_xmloption, NULL
},
{
{"temp_tablespaces", PGC_USERSET, PGC_S_FILE,
gettext_noop("Sets the tablespaces suitable for creating new objects and sort files."),
@ -6516,6 +6528,24 @@ assign_xmlbinary(const char *newval, bool doit, GucSource source)
return newval;
}
static const char *
assign_xmloption(const char *newval, bool doit, GucSource source)
{
XmlOptionType xo;
if (pg_strcasecmp(newval, "document") == 0)
xo = XMLOPTION_DOCUMENT;
else if (pg_strcasecmp(newval, "content") == 0)
xo = XMLOPTION_CONTENT;
else
return NULL; /* reject */
if (doit)
xmloption = xo;
return newval;
}
static bool
assign_tcp_keepalives_idle(int newval, bool doit, GucSource source)
{

View File

@ -406,6 +406,8 @@
#default_transaction_read_only = off
#statement_timeout = 0 # 0 is disabled
#vacuum_freeze_min_age = 100000000
#xmlbinary = 'base64'
#xmloption = 'content'
# - Locale and Formatting -

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.12 2007/01/20 09:27:20 petere Exp $
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.13 2007/01/25 11:53:51 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -34,6 +34,14 @@ extern Datum xmlconcat2(PG_FUNCTION_ARGS);
extern Datum texttoxml(PG_FUNCTION_ARGS);
extern Datum xmlvalidate(PG_FUNCTION_ARGS);
typedef enum
{
XML_STANDALONE_YES,
XML_STANDALONE_NO,
XML_STANDALONE_NO_VALUE,
XML_STANDALONE_OMITTED
} XmlStandaloneType;
extern xmltype *xmlconcat(List *args);
extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
extern xmltype *xmlparse(text *data, bool is_doc, bool preserve_whitespace);
@ -53,4 +61,12 @@ typedef enum
extern XmlBinaryType xmlbinary;
typedef enum
{
XMLOPTION_DOCUMENT,
XMLOPTION_CONTENT
} XmlOptionType;
extern XmlOptionType xmloption;
#endif /* XML_H */

View File

@ -53,13 +53,19 @@ SELECT xmlconcat('hello', 'you');
(1 row)
SELECT xmlconcat(1, 2);
ERROR: argument of XMLCONCAT must be type xml, not type integer
ERROR: argument of XMLCONCAT must be type "xml", not type integer
SELECT xmlconcat('bad', '<syntax');
ERROR: invalid XML content
DETAIL: Entity: line 1: parser error : Couldn't find end of Start Tag syntax line 1
<syntax
^
SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
xmlconcat
--------------
<foo/><bar/>
(1 row)
SELECT xmlconcat('<?xml version="1.1"?><foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
xmlconcat
-----------------------------------
<?xml version="1.1"?><foo/><bar/>
@ -205,23 +211,48 @@ SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
xmlroot
---------
<foo/>
(1 row)
SELECT xmlroot(xml '<foo/>', version '2.0');
xmlroot
-----------------------
<?xml version="2.0"?>
<foo/>
xmlroot
-----------------------------
<?xml version="2.0"?><foo/>
(1 row)
SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
xmlroot
----------------------------------------------
<?xml version="1.0" standalone="yes"?><foo/>
(1 row)
SELECT xmlroot(xml '<?xml version="1.1"?><foo/>', version no value, standalone yes);
xmlroot
----------------------------------------------
<?xml version="1.0" standalone="yes"?><foo/>
(1 row)
SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no);
xmlroot
---------------------------------------
<?xml version="1.1" standalone="no"?>
xmlroot
---------------------------------------------
<?xml version="1.1" standalone="no"?><foo/>
(1 row)
SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no);
xmlroot
---------------------------------------------
<?xml version="1.0" standalone="no"?><foo/>
(1 row)
SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no value);
xmlroot
---------
<foo/>
(1 row)
SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value);
xmlroot
----------------------------------------------
<?xml version="1.0" standalone="yes"?><foo/>
(1 row)
SELECT xmlroot (
@ -239,11 +270,9 @@ SELECT xmlroot (
version '1.0',
standalone yes
);
xmlroot
----------------------------------------------------
<?xml version="1.0" standalone="yes"?>
<gazonk name="val" num="2"><qux>foo</qux></gazonk>
xmlroot
------------------------------------------------------------------------------------------
<?xml version="1.0" standalone="yes"?><gazonk name="val" num="2"><qux>foo</qux></gazonk>
(1 row)
SELECT xmlserialize(content data as character varying) FROM xmltest;
@ -313,3 +342,29 @@ SELECT xmlpi(name "123");
<?_x0031_23?>
(1 row)
PREPARE foo (xml) AS SELECT xmlconcat('<foo/>', $1);
SET XML OPTION DOCUMENT;
EXECUTE foo ('<bar/>');
xmlconcat
--------------
<foo/><bar/>
(1 row)
EXECUTE foo ('bad');
ERROR: invalid XML document
DETAIL: Entity: line 1: parser error : Start tag expected, '<' not found
bad
^
SET XML OPTION CONTENT;
EXECUTE foo ('<bar/>');
xmlconcat
--------------
<foo/><bar/>
(1 row)
EXECUTE foo ('good');
xmlconcat
------------
<foo/>good
(1 row)

View File

@ -30,11 +30,13 @@ ERROR: no XML support in this installation
SELECT xmlconcat('hello', 'you');
ERROR: no XML support in this installation
SELECT xmlconcat(1, 2);
ERROR: argument of XMLCONCAT must be type xml, not type integer
ERROR: argument of XMLCONCAT must be type "xml", not type integer
SELECT xmlconcat('bad', '<syntax');
ERROR: no XML support in this installation
SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
ERROR: no XML support in this installation
SELECT xmlconcat('<?xml version="1.1"?><foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
ERROR: no XML support in this installation
SELECT xmlelement(name element,
xmlattributes (1 as one, 'deuce' as two),
'content');
@ -92,8 +94,18 @@ SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
ERROR: no XML support in this installation
SELECT xmlroot(xml '<foo/>', version '2.0');
ERROR: no XML support in this installation
SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
ERROR: no XML support in this installation
SELECT xmlroot(xml '<?xml version="1.1"?><foo/>', version no value, standalone yes);
ERROR: no XML support in this installation
SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no);
ERROR: no XML support in this installation
SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no);
ERROR: no XML support in this installation
SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no value);
ERROR: no XML support in this installation
SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value);
ERROR: no XML support in this installation
SELECT xmlroot (
xmlelement (
name gazonk,
@ -144,3 +156,15 @@ SELECT xmlpi(name ":::_xml_abc135.%-&_");
ERROR: no XML support in this installation
SELECT xmlpi(name "123");
ERROR: no XML support in this installation
PREPARE foo (xml) AS SELECT xmlconcat('<foo/>', $1);
ERROR: no XML support in this installation
SET XML OPTION DOCUMENT;
EXECUTE foo ('<bar/>');
ERROR: prepared statement "foo" does not exist
EXECUTE foo ('bad');
ERROR: prepared statement "foo" does not exist
SET XML OPTION CONTENT;
EXECUTE foo ('<bar/>');
ERROR: prepared statement "foo" does not exist
EXECUTE foo ('good');
ERROR: prepared statement "foo" does not exist

View File

@ -25,6 +25,7 @@ SELECT xmlconcat('hello', 'you');
SELECT xmlconcat(1, 2);
SELECT xmlconcat('bad', '<syntax');
SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
SELECT xmlconcat('<?xml version="1.1"?><foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
SELECT xmlelement(name element,
@ -69,7 +70,13 @@ SELECT xmlpi(name foo, ' bar');
SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
SELECT xmlroot(xml '<foo/>', version '2.0');
SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
SELECT xmlroot(xml '<?xml version="1.1"?><foo/>', version no value, standalone yes);
SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no);
SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no);
SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no value);
SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value);
SELECT xmlroot (
xmlelement (
@ -107,3 +114,14 @@ SELECT xmlelement(name employees, xmlagg(xmlelement(name name, name))) FROM emp;
SELECT xmlpi(name ":::_xml_abc135.%-&_");
SELECT xmlpi(name "123");
PREPARE foo (xml) AS SELECT xmlconcat('<foo/>', $1);
SET XML OPTION DOCUMENT;
EXECUTE foo ('<bar/>');
EXECUTE foo ('bad');
SET XML OPTION CONTENT;
EXECUTE foo ('<bar/>');
EXECUTE foo ('good');