diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 94fc8fd79aa45388f73215f3466dd0f4e894d1f3..2a95d8fae73e06379d592679cdc5f6e512f7caca 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -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"> diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 47c2e5c74af35c043b12982222d5dd03ba18e24f..f0ba6c32c715ee3351265b8310f7fbc9d040dadd 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -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. diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 60f9d35f1f762b908c72320b7e33a46e6a1cf15b..75a9e42a24df3ac1fb97a640990197c6173f73e9 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -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; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 217b1a0465961e14ea434e5d0d7eeb6c47f893b3..c256d73eadb084c5b1623ae842645b24a4158a2f 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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 diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index b8607c7c002a3dab01c139212df2a4b808d3ba18..368f3e06947972e98cc00c34508431f6b6b40b3f 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -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}, diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 394a507f2ef11949206debd9fe396919a44bf2d6..a807ef12de4d36fb29c64c2c01d0de133470a207 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -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, diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 3b283d247f0f1688e9fcdeafba15139a85ac3b21..d9a9ce5bc369cf0702eac945c0715d2db0647110 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -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 XML_STANDALONE_NO: + orig_standalone = 0; break; - case -1: - doc->standalone = 0; + case XML_STANDALONE_NO_VALUE: + orig_standalone = -1; break; - default: - doc->standalone = -1; + case XML_STANDALONE_OMITTED: + /* leave original value */ break; } - buffer = xmlBufferCreate(); - save = xmlSaveToBuffer(buffer, "UTF-8", 0); - xmlSaveDoc(save, doc); - xmlSaveClose(save); - - xmlFreeDoc(doc); + initStringInfo(&buf); + print_xml_decl(&buf, orig_version, 0, orig_standalone); + appendStringInfoString(&buf, str + len); - 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 * diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 9f2cdc43f77130bd28be296cd6105e6f1b7b5c3d..dad28983336307855599440d7f944ec38737b0cd 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -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) { diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 3b9730c75bbf07ab3b0fad7ce330fbf713624c87..b3c24fb2c5f538c412280b0cc75a1eabb97bfbfb 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -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 - diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h index b580fffd82c04494b8162ae754dff5d57112c154..f5b33512cfdfc0f1b720099a71050e5d4880509b 100644 --- a/src/include/utils/xml.h +++ b/src/include/utils/xml.h @@ -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 */ diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index d91d76530361db24f63442645ba977731f15b22d..0c08667706884fc334e90276c307b40fc9ca2ad6 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -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) + diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index dd35f1bf4e71a5405d3181a61e3f1c199be4ea86..89124ebb98e2874c738b2d2108e9f74896e33799 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -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 diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index 8e321831596b76c4369281afd690e0f9e605cbfb..b3117c2424f2f073451a6b0b9b3a72637b04c06f 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -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');