From 22bd156ff0b6727c1f5fb6069690f7e2a4cabcac Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 25 Jan 2007 11:53:52 +0000 Subject: [PATCH] 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. --- doc/src/sgml/config.sgml | 34 +++++- doc/src/sgml/datatype.sgml | 20 ++- src/backend/executor/execQual.c | 7 +- src/backend/parser/gram.y | 29 ++--- src/backend/parser/keywords.c | 3 +- src/backend/parser/parse_expr.c | 5 +- src/backend/utils/adt/xml.c | 169 ++++++++++++++------------ src/backend/utils/misc/guc.c | 32 ++++- src/backend/utils/misc/postgresql.conf.sample | 2 + src/include/utils/xml.h | 18 ++- src/test/regress/expected/xml.out | 87 ++++++++++--- src/test/regress/expected/xml_1.out | 26 +++- src/test/regress/sql/xml.sql | 18 +++ 13 files changed, 329 insertions(+), 121 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 94fc8fd79a..2a95d8fae7 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1,4 +1,4 @@ - + Server Configuration @@ -3558,6 +3558,38 @@ SELECT * FROM parent WHERE key = 2400; + + xmloption (string) + + xmloption configuration parameter + + + SET XML OPTION + + + XML option + + + + Sets whether DOCUMENT or + CONTENT is implicit when converting between + XML and character string values. See for a description of this. Valid + values are DOCUMENT and + CONTENT. The default is + CONTENT. + + + + According to the SQL standard, the command to set this option is + +SET XML OPTION { DOCUMENT | CONTENT }; + + This syntax is also available in PostgreSQL. + + + + diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 47c2e5c74a..f0ba6c32c7 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -1,4 +1,4 @@ - + Data Types @@ -3475,6 +3475,24 @@ XMLSERIALIZE ( { DOCUMENT | CONTENT } value AS + When character string values are cast to or from type + xml without going through XMLPARSE or + XMLSERIALIZE, respectively, the choice of + DOCUMENT versus CONTENT is + determined by the XML option session configuration + parameter, which can be set using the standard command + +SET XML OPTION { DOCUMENT | CONTENT }; + + or the more PostgreSQL-like syntax + +SET xmloption TO { DOCUMENT | CONTENT }; + + The default is CONTENT, so all forms of XML + data are allowed. + + + Care must be taken when dealing with multiple character encodings on the client, server, and in the XML data passed through them. When using the text mode to pass queries to the server and query diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 60f9d35f1f..75a9e42a24 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 217b1a0465..c256d73ead 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 b8607c7c00..368f3e0694 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 394a507f2e..a807ef12de 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 3b283d247f..d9a9ce5bc3 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 '' - * resulting in '', 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, ""); - } - 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, ""); + 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; @@ -972,6 +938,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 '' resulting in + * '', 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, ""); + + return true; + } + else + return false; +} + + +/* * Convert a C string to XML internal representation * * TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c) diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 9f2cdc43f7..dad2898333 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * 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; @@ -2293,6 +2295,16 @@ static struct config_string ConfigureNamesString[] = }, { + {"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."), NULL, @@ -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 3b9730c75b..b3c24fb2c5 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 b580fffd82..f5b33512cf 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 d91d765303..0c08667706 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', '', NULL, ''); + xmlconcat +-------------- + +(1 row) + +SELECT xmlconcat('', NULL, ''); xmlconcat ----------------------------------- @@ -205,23 +211,48 @@ SELECT xmlroot(xml '', version no value, standalone no value); xmlroot --------- - (1 row) SELECT xmlroot(xml '', version '2.0'); - xmlroot ------------------------ - - - + xmlroot +----------------------------- + +(1 row) + +SELECT xmlroot(xml '', version no value, standalone yes); + xmlroot +---------------------------------------------- + +(1 row) + +SELECT xmlroot(xml '', version no value, standalone yes); + xmlroot +---------------------------------------------- + (1 row) SELECT xmlroot(xmlroot(xml '', version '1.0'), version '1.1', standalone no); - xmlroot ---------------------------------------- - + xmlroot +--------------------------------------------- + +(1 row) + +SELECT xmlroot('', version no value, standalone no); + xmlroot +--------------------------------------------- + +(1 row) + +SELECT xmlroot('', version no value, standalone no value); + xmlroot +--------- - +(1 row) + +SELECT xmlroot('', version no value); + xmlroot +---------------------------------------------- + (1 row) SELECT xmlroot ( @@ -239,11 +270,9 @@ SELECT xmlroot ( version '1.0', standalone yes ); - xmlroot ----------------------------------------------------- - - foo - + xmlroot +------------------------------------------------------------------------------------------ + foo (1 row) SELECT xmlserialize(content data as character varying) FROM xmltest; @@ -313,3 +342,29 @@ SELECT xmlpi(name "123"); (1 row) +PREPARE foo (xml) AS SELECT xmlconcat('', $1); +SET XML OPTION DOCUMENT; +EXECUTE foo (''); + xmlconcat +-------------- + +(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 (''); + xmlconcat +-------------- + +(1 row) + +EXECUTE foo ('good'); + xmlconcat +------------ + good +(1 row) + diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index dd35f1bf4e..89124ebb98 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', '', NULL, ''); ERROR: no XML support in this installation +SELECT xmlconcat('', NULL, ''); +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 '', version no value, standalone no value); ERROR: no XML support in this installation SELECT xmlroot(xml '', version '2.0'); ERROR: no XML support in this installation +SELECT xmlroot(xml '', version no value, standalone yes); +ERROR: no XML support in this installation +SELECT xmlroot(xml '', version no value, standalone yes); +ERROR: no XML support in this installation SELECT xmlroot(xmlroot(xml '', version '1.0'), version '1.1', standalone no); ERROR: no XML support in this installation +SELECT xmlroot('', version no value, standalone no); +ERROR: no XML support in this installation +SELECT xmlroot('', version no value, standalone no value); +ERROR: no XML support in this installation +SELECT xmlroot('', 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('', $1); +ERROR: no XML support in this installation +SET XML OPTION DOCUMENT; +EXECUTE foo (''); +ERROR: prepared statement "foo" does not exist +EXECUTE foo ('bad'); +ERROR: prepared statement "foo" does not exist +SET XML OPTION CONTENT; +EXECUTE foo (''); +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 8e32183159..b3117c2424 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', '', NULL, ''); +SELECT xmlconcat('', NULL, ''); SELECT xmlelement(name element, @@ -69,7 +70,13 @@ SELECT xmlpi(name foo, ' bar'); SELECT xmlroot(xml '', version no value, standalone no value); SELECT xmlroot(xml '', version '2.0'); +SELECT xmlroot(xml '', version no value, standalone yes); +SELECT xmlroot(xml '', version no value, standalone yes); SELECT xmlroot(xmlroot(xml '', version '1.0'), version '1.1', standalone no); +SELECT xmlroot('', version no value, standalone no); +SELECT xmlroot('', version no value, standalone no value); +SELECT xmlroot('', 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('', $1); + +SET XML OPTION DOCUMENT; +EXECUTE foo (''); +EXECUTE foo ('bad'); + +SET XML OPTION CONTENT; +EXECUTE foo (''); +EXECUTE foo ('good'); -- 2.11.0