diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 09309ba0390b..5cc03daf0b9b 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -4520,7 +4520,7 @@ xml 'bar' xml, uses the function xmlserialize:xmlserialize -XMLSERIALIZE ( { DOCUMENT | CONTENT } value AS type [ [ NO ] INDENT ] ) +XMLSERIALIZE ( { DOCUMENT | CONTENT } value AS type [ [ NO ] INDENT ] [INCLUDING XMLDECLARATION | EXCLUDING XMLDECLARATION] ) type can be character, character varying, or @@ -4537,6 +4537,38 @@ XMLSERIALIZE ( { DOCUMENT | CONTENT } value AS + + The options INCLUDING XMLDECLARATION and EXCLUDING XMLDECLARATION specify + whether the XML declaration of an XML value is included in the serialized string or not, respectively. + If not specified, the output will only contain an XML delcaration if the XML value had one. + + + +Examples: + +42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + 42 + + + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + + + 42 + + + + + +SELECT xmlserialize(DOCUMENT '42'::xml AS text EXCLUDING XMLDECLARATION); + xmlserialize +-------------------------- + 42+ +]]> + When a character string value is cast to or from type xml without going through XMLPARSE or diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt index ebe85337c287..a1cfdd92f186 100644 --- a/src/backend/catalog/sql_features.txt +++ b/src/backend/catalog/sql_features.txt @@ -667,7 +667,7 @@ X074 XMLSerialize: binary string serialization and DOCUMENT option NO X075 XMLSerialize: binary string serialization NO X076 XMLSerialize: VERSION NO X077 XMLSerialize: explicit ENCODING option NO -X078 XMLSerialize: explicit XML declaration NO +X078 XMLSerialize: explicit XML declaration YES X080 Namespaces in XML publishing NO X081 Query-level XML namespace declarations NO X082 XML namespace declarations in DML NO diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 8a72b5e70a4e..8b38ee1e8f15 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -4621,7 +4621,8 @@ ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) *op->resvalue = PointerGetDatum(xmltotext_with_options(DatumGetXmlP(value), xexpr->xmloption, - xexpr->indent)); + xexpr->indent, + xexpr->xmldeclaration)); *op->resnull = false; } break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3c4268b271a4..73f8ae3ccdaf 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -620,6 +620,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type xmltable_column_option_el %type xml_namespace_list %type xml_namespace_el +%type opt_xml_declaration_option %type func_application func_expr_common_subexpr %type func_expr func_expr_windowless @@ -788,8 +789,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE - XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLEXISTS XMLFOREST XMLNAMESPACES - XMLPARSE XMLPI XMLROOT XMLSERIALIZE XMLTABLE + XML_P XMLATTRIBUTES XMLCONCAT XMLDECLARATION XMLELEMENT XMLEXISTS XMLFOREST + XMLNAMESPACES XMLPARSE XMLPI XMLROOT XMLSERIALIZE XMLTABLE YEAR_P YES_P @@ -16102,7 +16103,7 @@ func_expr_common_subexpr: $$ = makeXmlExpr(IS_XMLROOT, NULL, NIL, list_make3($3, $5, $6), @1); } - | XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename xml_indent_option ')' + | XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename xml_indent_option opt_xml_declaration_option ')' { XmlSerialize *n = makeNode(XmlSerialize); @@ -16110,6 +16111,7 @@ func_expr_common_subexpr: n->expr = $4; n->typeName = $6; n->indent = $7; + n->xmldeclaration = $8; n->location = @1; $$ = (Node *) n; } @@ -16334,6 +16336,11 @@ xml_indent_option: INDENT { $$ = true; } | /*EMPTY*/ { $$ = false; } ; +opt_xml_declaration_option: INCLUDING XMLDECLARATION { $$ = XMLSERIALIZE_INCLUDING_XMLDECLARATION; } + | EXCLUDING XMLDECLARATION { $$ = XMLSERIALIZE_EXCLUDING_XMLDECLARATION; } + | /*EMPTY*/ { $$ = XMLSERIALIZE_NO_XMLDECLARATION_OPTION; } + ; + xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = true; } | STRIP_P WHITESPACE_P { $$ = false; } | /*EMPTY*/ { $$ = false; } @@ -18030,6 +18037,7 @@ unreserved_keyword: | WRAPPER | WRITE | XML_P + | XMLDECLARATION | YEAR_P | YES_P | ZONE @@ -18688,6 +18696,7 @@ bare_label_keyword: | XML_P | XMLATTRIBUTES | XMLCONCAT + | XMLDECLARATION | XMLELEMENT | XMLEXISTS | XMLFOREST diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 1f8e2d54673d..76fc1c09a75d 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -2497,6 +2497,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs) xexpr->xmloption = xs->xmloption; xexpr->indent = xs->indent; + xexpr->xmldeclaration = xs->xmldeclaration; xexpr->location = xs->location; /* We actually only need these to be able to parse back the expression. */ xexpr->type = targetType; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9e90acedb919..735aec7eee94 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -10202,6 +10202,11 @@ get_rule_expr(Node *node, deparse_context *context, appendStringInfoString(buf, " INDENT"); else appendStringInfoString(buf, " NO INDENT"); + + if (xexpr->xmldeclaration == XMLSERIALIZE_INCLUDING_XMLDECLARATION) + appendStringInfoString(buf, " INCLUDING XMLDECLARATION"); + else if (xexpr->xmldeclaration == XMLSERIALIZE_EXCLUDING_XMLDECLARATION) + appendStringInfoString(buf, " EXCLUDING XMLDECLARATION"); } if (xexpr->op == IS_DOCUMENT) diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index db8d0d6a7e87..97ccd648026e 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -653,7 +653,8 @@ xmltotext(PG_FUNCTION_ARGS) text * -xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent) +xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent, + XmlSerializeDeclarationOption xmldeclaration) { #ifdef USE_LIBXML text *volatile result; @@ -666,7 +667,8 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent) PgXmlErrorContext *xmlerrcxt; #endif - if (xmloption_arg != XMLOPTION_DOCUMENT && !indent) + if (xmloption_arg != XMLOPTION_DOCUMENT && + xmldeclaration == XMLSERIALIZE_NO_XMLDECLARATION_OPTION && !indent) { /* * We don't actually need to do anything, so just return the @@ -697,8 +699,11 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent) errmsg("not an XML document"))); } - /* If we weren't asked to indent, we're done. */ - if (!indent) + /* + * If we weren't asked to indent or to explicitly hide or show the + * xml declaration, we're done. + */ + if (!indent && xmldeclaration == XMLSERIALIZE_NO_XMLDECLARATION_OPTION) { xmlFreeDoc(doc); return (text *) data; @@ -722,17 +727,22 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent) parse_xml_decl(xml_text2xmlChar(data), &decl_len, NULL, NULL, NULL); /* - * Emit declaration only if the input had one. Note: some versions of - * xmlSaveToBuffer leak memory if a non-null encoding argument is - * passed, so don't do that. We don't want any encoding conversion - * anyway. - */ - if (decl_len == 0) - ctxt = xmlSaveToBuffer(buf, NULL, - XML_SAVE_NO_DECL | XML_SAVE_FORMAT); - else - ctxt = xmlSaveToBuffer(buf, NULL, - XML_SAVE_FORMAT); + * Emit declaration if the input had one or if it was explicitly + * requested via INCLUDING XMLDECLARATION. Indent the buffer content + * if the flag INDENT was used. Note: some versions of xmlSaveToBuffer + * leak memory if a non-null encoding argument is passed, so don't do + * that. We don't want any encoding conversion anyway. + */ + ctxt = xmlSaveToBuffer(buf, NULL, + /* remove XML declaration if EXCLUDING XMLDECLARATION was used. */ + (xmldeclaration == XMLSERIALIZE_EXCLUDING_XMLDECLARATION ? XML_SAVE_NO_DECL : 0) | + /* + * remove XML declaration if the xml string didn't have one and + * INCLUDING XMLDECLARATION was not used + */ + ((decl_len == 0 && xmldeclaration == XMLSERIALIZE_NO_XMLDECLARATION_OPTION) ? XML_SAVE_NO_DECL : 0) | + /* indent the xml dump if INDENT was used */ + (indent ? XML_SAVE_FORMAT : 0)); if (ctxt == NULL || xmlerrcxt->err_occurred) xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, @@ -754,7 +764,7 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent) * content nodes, and then iterate over the nodes. */ xmlNodePtr root; - xmlNodePtr newline; + xmlNodePtr newline = NULL; root = xmlNewNode(NULL, (const xmlChar *) "content-root"); if (root == NULL || xmlerrcxt->err_occurred) @@ -772,15 +782,19 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent) * freeing of this node manually, and pass NULL here to make sure * there's not a dangling link. */ - newline = xmlNewDocText(NULL, (const xmlChar *) "\n"); - if (newline == NULL || xmlerrcxt->err_occurred) - xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, - "could not allocate xml node"); + if (indent) + { + newline = xmlNewDocText(NULL, (const xmlChar *)"\n"); + + if (newline == NULL || xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate xml node"); + } for (xmlNodePtr node = root->children; node; node = node->next) { /* insert newlines between nodes */ - if (node->type != XML_TEXT_NODE && node->prev != NULL) + if (node->type != XML_TEXT_NODE && node->prev != NULL && newline != NULL) { if (xmlSaveTree(ctxt, newline) == -1 || xmlerrcxt->err_occurred) { @@ -792,13 +806,44 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent) if (xmlSaveTree(ctxt, node) == -1 || xmlerrcxt->err_occurred) { - xmlFreeNode(newline); + if(newline != NULL) + xmlFreeNode(newline); xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, "could not save content to xmlBuffer"); } } - xmlFreeNode(newline); + /* + * If the flag INCLUDING XMLDECLARATION is specified, we have + * to manually add the XML declaration here. xmlSaveTree() does + * not include it. + */ + if (xmldeclaration == XMLSERIALIZE_INCLUDING_XMLDECLARATION) + { + StringInfoData xmldecl; + initStringInfo(&xmldecl); + appendStringInfoString(&xmldecl, "version) + appendStringInfo(&xmldecl, " version=\"%s\"", doc->version); + + if (doc->encoding) + appendStringInfo(&xmldecl, " encoding=\"%s\"", doc->encoding); + + /* We only add "standalone" if the input's XML declaration had one */ + if (doc->standalone == 1) + appendStringInfo(&xmldecl, " standalone=\"yes\""); + else if (doc->standalone == 0) + appendStringInfo(&xmldecl, " standalone=\"no\""); + + appendStringInfoString(&xmldecl, "?>\n"); + xmlBufferAddHead(buf, (const xmlChar *)xmldecl.data, xmldecl.len); + + pfree(xmldecl.data); + } + + if (newline != NULL) + xmlFreeNode(newline); } if (xmlSaveClose(ctxt) == -1 || xmlerrcxt->err_occurred) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 4610fc61293b..e7332e915e10 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -857,6 +857,7 @@ typedef struct XmlSerialize Node *expr; TypeName *typeName; bool indent; /* [NO] INDENT */ + XmlSerializeDeclarationOption xmldeclaration; /* INCLUDING or EXCLUDING XMLDECLARATION */ ParseLoc location; /* token location, or -1 if unknown */ } XmlSerialize; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 7d3b4198f266..86120b0cf3ba 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -1598,6 +1598,13 @@ typedef enum XmlOptionType XMLOPTION_CONTENT, } XmlOptionType; +typedef enum XmlSerializeDeclarationOption +{ + XMLSERIALIZE_INCLUDING_XMLDECLARATION, /* Add xml declaration in XMLSERIALIZE output */ + XMLSERIALIZE_EXCLUDING_XMLDECLARATION, /* Remove xml declaration in XMLSERIALIZE output */ + XMLSERIALIZE_NO_XMLDECLARATION_OPTION /* Add xml declaration only if XMLSERIALIZE input has one */ +} XmlSerializeDeclarationOption; + typedef struct XmlExpr { Expr xpr; @@ -1620,6 +1627,8 @@ typedef struct XmlExpr int32 typmod pg_node_attr(query_jumble_ignore); /* token location, or -1 if unknown */ ParseLoc location; + /* xmlserialize flags INCLUDING and EXCLUDING XMLDECLARATION */ + XmlSerializeDeclarationOption xmldeclaration pg_node_attr(query_jumble_ignore); } XmlExpr; /* diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index a4af3f717a11..cf2cf74838b1 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -507,6 +507,7 @@ PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmldeclaration", XMLDECLARATION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, BARE_LABEL) diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h index 0d7a816b9f93..748bf7bc1773 100644 --- a/src/include/utils/xml.h +++ b/src/include/utils/xml.h @@ -78,7 +78,7 @@ extern xmltype *xmlpi(const char *target, text *arg, bool arg_is_null, bool *res extern xmltype *xmlroot(xmltype *data, text *version, int standalone); extern bool xml_is_document(xmltype *arg); extern text *xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, - bool indent); + bool indent, XmlSerializeDeclarationOption xmldeclaration); extern char *escape_xml(const char *str); extern char *map_sql_identifier_to_xml_name(const char *ident, bool fully_escaped, bool escape_period); diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index bcc743f48518..812eebb3762e 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -676,6 +676,200 @@ SELECT xmlserialize(CONTENT 'text node ' AS text IN (1 row) +-- 'including xmldeclaration' and 'excluding xmldeclaration'(DOCUMENT) +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text EXCLUDING XMLDECLARATION); + xmlserialize +-------------------------- + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text EXCLUDING XMLDECLARATION); + xmlserialize +-------------------------- + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +-------------------------------------------------------- + + + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +--------------------------------------------------------- + + + 42 +(1 row) + +-- 'including xmldeclaration' and 'excluding xmldeclaration'(CONTENT) +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text EXCLUDING XMLDECLARATION); + xmlserialize +----------------------------- + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text EXCLUDING XMLDECLARATION); + xmlserialize +----------------------------- + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +-------------------------------------------------------- + + + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +--------------------------------------------------------- + + + txt42 +(1 row) + +-- 'indent' + 'including xmldeclaration' and 'excluding xmldeclaration' (DOCUMENT) +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + + + 42 + + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION); + xmlserialize +----------------- + + + 42+ + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + + + 42 + + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION); + xmlserialize +----------------- + + + 42+ + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +-------------------------------------------------------- + + + + + 42 + + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +--------------------------------------------------------- + + + + + 42 + + +(1 row) + +-- 'indent' + 'including xmldeclaration' and 'excluding xmldeclaration'(CONTENT) +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + txt + + + + 42 + + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT EXCLUDING XMLDECLARATION); + xmlserialize +----------------- + txt + + + + 42+ + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + txt + + + + 42 + + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT EXCLUDING XMLDECLARATION); + xmlserialize +----------------- + txt + + + + 42+ + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +-------------------------------------------------------- + + + txt + + + + 42 + + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +--------------------------------------------------------- + + + txt + + + + 42 + + +(1 row) + SELECT xml 'bar' IS DOCUMENT; ?column? ---------- @@ -824,6 +1018,12 @@ CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10)); CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text); CREATE VIEW xmlview10 AS SELECT xmlserialize(document '42' AS text indent); CREATE VIEW xmlview11 AS SELECT xmlserialize(document '42' AS character varying no indent); +CREATE VIEW xmlview12 AS SELECT xmlserialize(document '42' AS text including xmldeclaration); +CREATE VIEW xmlview13 AS SELECT xmlserialize(document '42' AS text excluding xmldeclaration); +CREATE VIEW xmlview14 AS SELECT xmlserialize(document '42' AS text indent including xmldeclaration); +CREATE VIEW xmlview15 AS SELECT xmlserialize(document '42' AS text indent excluding xmldeclaration); +CREATE VIEW xmlview16 AS SELECT xmlserialize(document '42' AS text no indent including xmldeclaration); +CREATE VIEW xmlview17 AS SELECT xmlserialize(document '42' AS text no indent excluding xmldeclaration); SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%' ORDER BY 1; table_name | view_definition @@ -831,6 +1031,12 @@ SELECT table_name, view_definition FROM information_schema.views xmlview1 | SELECT xmlcomment('test'::text) AS xmlcomment; xmlview10 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text INDENT) AS "xmlserialize"; xmlview11 | SELECT (XMLSERIALIZE(DOCUMENT '42'::xml AS character varying NO INDENT))::character varying AS "xmlserialize"; + xmlview12 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text NO INDENT INCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview13 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text NO INDENT EXCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview14 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview15 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview16 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text NO INDENT INCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview17 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text NO INDENT EXCLUDING XMLDECLARATION) AS "xmlserialize"; xmlview2 | SELECT XMLCONCAT('hello'::xml, 'you'::xml) AS "xmlconcat"; xmlview3 | SELECT XMLELEMENT(NAME element, XMLATTRIBUTES(1 AS ":one:", 'deuce' AS two), 'content&') AS "xmlelement"; xmlview4 | SELECT XMLELEMENT(NAME employee, XMLFOREST(name AS name, age AS age, salary AS pay)) AS "xmlelement" + @@ -840,7 +1046,7 @@ SELECT table_name, view_definition FROM information_schema.views xmlview7 | SELECT XMLROOT(''::xml, VERSION NO VALUE, STANDALONE YES) AS "xmlroot"; xmlview8 | SELECT (XMLSERIALIZE(CONTENT 'good'::xml AS character(10) NO INDENT))::character(10) AS "xmlserialize"; xmlview9 | SELECT XMLSERIALIZE(CONTENT 'good'::xml AS text NO INDENT) AS "xmlserialize"; -(11 rows) +(17 rows) -- Text XPath expressions evaluation SELECT xpath('/value', data) FROM xmltest; diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index a1c5d314171f..d8870111656e 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -454,6 +454,130 @@ ERROR: unsupported XML feature LINE 1: SELECT xmlserialize(CONTENT 'text node ... ^ DETAIL: This functionality requires the server to be built with libxml support. +-- 'including xmldeclaration' and 'excluding xmldeclaration'(DOCUMENT) +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmlserialize(DOCUMENT '42'::xml AS text EXCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml AS text EXCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::x... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmlserialize(CONTENT 'txt42'::xml AS text EXCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::x... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::xml AS text EXCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::x... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT EXCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::x... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT EXCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); +ERROR: unsupported XML feature +LINE 1: SELECT xmlserialize(CONTENT 'bar' IS DOCUMENT; ERROR: unsupported XML feature LINE 1: SELECT xml 'bar' IS DOCUMENT; @@ -593,6 +717,36 @@ ERROR: unsupported XML feature LINE 1: ...TE VIEW xmlview11 AS SELECT xmlserialize(document '42' AS text including xmldeclaration); +ERROR: unsupported XML feature +LINE 1: ...TE VIEW xmlview12 AS SELECT xmlserialize(document '42' AS text excluding xmldeclaration); +ERROR: unsupported XML feature +LINE 1: ...TE VIEW xmlview13 AS SELECT xmlserialize(document '42' AS text indent including xmldeclaration); +ERROR: unsupported XML feature +LINE 1: ...TE VIEW xmlview14 AS SELECT xmlserialize(document '42' AS text indent excluding xmldeclaration); +ERROR: unsupported XML feature +LINE 1: ...TE VIEW xmlview15 AS SELECT xmlserialize(document '42' AS text no indent including xmldeclaration); +ERROR: unsupported XML feature +LINE 1: ...TE VIEW xmlview16 AS SELECT xmlserialize(document '42' AS text no indent excluding xmldeclaration); +ERROR: unsupported XML feature +LINE 1: ...TE VIEW xmlview17 AS SELECT xmlserialize(document ' ' AS text IN (1 row) +-- 'including xmldeclaration' and 'excluding xmldeclaration'(DOCUMENT) +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text EXCLUDING XMLDECLARATION); + xmlserialize +-------------------------- + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text EXCLUDING XMLDECLARATION); + xmlserialize +-------------------------- + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +-------------------------------------------------------- + + + 42 +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +--------------------------------------------------------- + + + 42 +(1 row) + +-- 'including xmldeclaration' and 'excluding xmldeclaration'(CONTENT) +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text EXCLUDING XMLDECLARATION); + xmlserialize +----------------------------- + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text EXCLUDING XMLDECLARATION); + xmlserialize +----------------------------- + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +-------------------------------------------------------- + + + txt42 +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); + xmlserialize +--------------------------------------------------------- + + + txt42 +(1 row) + +-- 'indent' + 'including xmldeclaration' and 'excluding xmldeclaration' (DOCUMENT) +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + + + 42 + + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION); + xmlserialize +----------------- + + + 42+ + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + + + 42 + + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION); + xmlserialize +----------------- + + + 42+ + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +-------------------------------------------------------- + + + + + 42 + + +(1 row) + +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +--------------------------------------------------------- + + + + + 42 + + +(1 row) + +-- 'indent' + 'including xmldeclaration' and 'excluding xmldeclaration'(CONTENT) +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + txt + + + + 42 + + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT EXCLUDING XMLDECLARATION); + xmlserialize +----------------- + txt + + + + 42+ + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +---------------------------------------- + + + txt + + + + 42 + + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT EXCLUDING XMLDECLARATION); + xmlserialize +----------------- + txt + + + + 42+ + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +-------------------------------------------------------- + + + txt + + + + 42 + + +(1 row) + +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); + xmlserialize +--------------------------------------------------------- + + + txt + + + + 42 + + +(1 row) + SELECT xml 'bar' IS DOCUMENT; ?column? ---------- @@ -810,6 +1004,12 @@ CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10)); CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text); CREATE VIEW xmlview10 AS SELECT xmlserialize(document '42' AS text indent); CREATE VIEW xmlview11 AS SELECT xmlserialize(document '42' AS character varying no indent); +CREATE VIEW xmlview12 AS SELECT xmlserialize(document '42' AS text including xmldeclaration); +CREATE VIEW xmlview13 AS SELECT xmlserialize(document '42' AS text excluding xmldeclaration); +CREATE VIEW xmlview14 AS SELECT xmlserialize(document '42' AS text indent including xmldeclaration); +CREATE VIEW xmlview15 AS SELECT xmlserialize(document '42' AS text indent excluding xmldeclaration); +CREATE VIEW xmlview16 AS SELECT xmlserialize(document '42' AS text no indent including xmldeclaration); +CREATE VIEW xmlview17 AS SELECT xmlserialize(document '42' AS text no indent excluding xmldeclaration); SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%' ORDER BY 1; table_name | view_definition @@ -817,6 +1017,12 @@ SELECT table_name, view_definition FROM information_schema.views xmlview1 | SELECT xmlcomment('test'::text) AS xmlcomment; xmlview10 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text INDENT) AS "xmlserialize"; xmlview11 | SELECT (XMLSERIALIZE(DOCUMENT '42'::xml AS character varying NO INDENT))::character varying AS "xmlserialize"; + xmlview12 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text NO INDENT INCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview13 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text NO INDENT EXCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview14 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview15 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview16 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text NO INDENT INCLUDING XMLDECLARATION) AS "xmlserialize"; + xmlview17 | SELECT XMLSERIALIZE(DOCUMENT '42'::xml AS text NO INDENT EXCLUDING XMLDECLARATION) AS "xmlserialize"; xmlview2 | SELECT XMLCONCAT('hello'::xml, 'you'::xml) AS "xmlconcat"; xmlview3 | SELECT XMLELEMENT(NAME element, XMLATTRIBUTES(1 AS ":one:", 'deuce' AS two), 'content&') AS "xmlelement"; xmlview4 | SELECT XMLELEMENT(NAME employee, XMLFOREST(name AS name, age AS age, salary AS pay)) AS "xmlelement" + @@ -826,7 +1032,7 @@ SELECT table_name, view_definition FROM information_schema.views xmlview7 | SELECT XMLROOT(''::xml, VERSION NO VALUE, STANDALONE YES) AS "xmlroot"; xmlview8 | SELECT (XMLSERIALIZE(CONTENT 'good'::xml AS character(10) NO INDENT))::character(10) AS "xmlserialize"; xmlview9 | SELECT XMLSERIALIZE(CONTENT 'good'::xml AS text NO INDENT) AS "xmlserialize"; -(11 rows) +(17 rows) -- Text XPath expressions evaluation SELECT xpath('/value', data) FROM xmltest; diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index 4c3520ce8980..56aa4317a6da 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -172,6 +172,35 @@ SELECT xmlserialize(CONTENT '42' AS text SELECT xmlserialize(DOCUMENT ' ' AS text INDENT); SELECT xmlserialize(CONTENT 'text node ' AS text INDENT); +-- 'including xmldeclaration' and 'excluding xmldeclaration'(DOCUMENT) +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text EXCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text EXCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text INCLUDING XMLDECLARATION); +-- 'including xmldeclaration' and 'excluding xmldeclaration'(CONTENT) +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text EXCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text EXCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INCLUDING XMLDECLARATION); +-- 'indent' + 'including xmldeclaration' and 'excluding xmldeclaration' (DOCUMENT) +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT EXCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); +SELECT xmlserialize(DOCUMENT '42'::xml AS text INDENT INCLUDING XMLDECLARATION); +-- 'indent' + 'including xmldeclaration' and 'excluding xmldeclaration'(CONTENT) +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT EXCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT EXCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); +SELECT xmlserialize(CONTENT 'txt42'::xml AS text INDENT INCLUDING XMLDECLARATION); + SELECT xml 'bar' IS DOCUMENT; SELECT xml 'barfoo' IS DOCUMENT; SELECT xml '' IS NOT DOCUMENT; @@ -221,6 +250,13 @@ CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10)); CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text); CREATE VIEW xmlview10 AS SELECT xmlserialize(document '42' AS text indent); CREATE VIEW xmlview11 AS SELECT xmlserialize(document '42' AS character varying no indent); +CREATE VIEW xmlview12 AS SELECT xmlserialize(document '42' AS text including xmldeclaration); +CREATE VIEW xmlview13 AS SELECT xmlserialize(document '42' AS text excluding xmldeclaration); +CREATE VIEW xmlview14 AS SELECT xmlserialize(document '42' AS text indent including xmldeclaration); +CREATE VIEW xmlview15 AS SELECT xmlserialize(document '42' AS text indent excluding xmldeclaration); +CREATE VIEW xmlview16 AS SELECT xmlserialize(document '42' AS text no indent including xmldeclaration); +CREATE VIEW xmlview17 AS SELECT xmlserialize(document '42' AS text no indent excluding xmldeclaration); + SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%' ORDER BY 1;