mirror of https://github.com/postgres/postgres
Support [NO] INDENT option in XMLSERIALIZE().
This adds the ability to pretty-print XML documents ... according to libxml's somewhat idiosyncratic notions of what's pretty, anyway. One notable divergence from a strict reading of the spec is that libxml is willing to collapse empty nodes "<node></node>" to just "<node/>", whereas SQL and the underlying XML spec say that this option should only result in whitespace tweaks. Nonetheless, it seems close enough to justify using the SQL-standard syntax. Jim Jones, reviewed by Peter Smith and myself Discussion: https://postgr.es/m/2f5df461-dad8-6d7d-4568-08e10608a69b@uni-muenster.de
This commit is contained in:
parent
419a8dd814
commit
483bdb2afe
|
@ -4460,7 +4460,7 @@ xml '<foo>bar</foo>'
|
||||||
<type>xml</type>, uses the function
|
<type>xml</type>, uses the function
|
||||||
<function>xmlserialize</function>:<indexterm><primary>xmlserialize</primary></indexterm>
|
<function>xmlserialize</function>:<indexterm><primary>xmlserialize</primary></indexterm>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
XMLSERIALIZE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable> AS <replaceable>type</replaceable> )
|
XMLSERIALIZE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable> AS <replaceable>type</replaceable> [ [ NO ] INDENT ] )
|
||||||
</synopsis>
|
</synopsis>
|
||||||
<replaceable>type</replaceable> can be
|
<replaceable>type</replaceable> can be
|
||||||
<type>character</type>, <type>character varying</type>, or
|
<type>character</type>, <type>character varying</type>, or
|
||||||
|
@ -4470,6 +4470,13 @@ XMLSERIALIZE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable> AS <repla
|
||||||
you to simply cast the value.
|
you to simply cast the value.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <literal>INDENT</literal> option causes the result to be
|
||||||
|
pretty-printed, while <literal>NO INDENT</literal> (which is the
|
||||||
|
default) just emits the original input string. Casting to a character
|
||||||
|
type likewise produces the original string.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
When a character string value is cast to or from type
|
When a character string value is cast to or from type
|
||||||
<type>xml</type> without going through <type>XMLPARSE</type> or
|
<type>xml</type> without going through <type>XMLPARSE</type> or
|
||||||
|
|
|
@ -621,7 +621,7 @@ X061 XMLParse: character string input and DOCUMENT option YES
|
||||||
X065 XMLParse: binary string input and CONTENT option NO
|
X065 XMLParse: binary string input and CONTENT option NO
|
||||||
X066 XMLParse: binary string input and DOCUMENT option NO
|
X066 XMLParse: binary string input and DOCUMENT option NO
|
||||||
X068 XMLSerialize: BOM NO
|
X068 XMLSerialize: BOM NO
|
||||||
X069 XMLSerialize: INDENT NO
|
X069 XMLSerialize: INDENT YES
|
||||||
X070 XMLSerialize: character string serialization and CONTENT option YES
|
X070 XMLSerialize: character string serialization and CONTENT option YES
|
||||||
X071 XMLSerialize: character string serialization and DOCUMENT option YES
|
X071 XMLSerialize: character string serialization and DOCUMENT option YES
|
||||||
X072 XMLSerialize: character string serialization YES
|
X072 XMLSerialize: character string serialization YES
|
||||||
|
|
|
@ -3837,8 +3837,10 @@ ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
|
||||||
return;
|
return;
|
||||||
value = argvalue[0];
|
value = argvalue[0];
|
||||||
|
|
||||||
*op->resvalue = PointerGetDatum(xmltotext_with_xmloption(DatumGetXmlP(value),
|
*op->resvalue =
|
||||||
xexpr->xmloption));
|
PointerGetDatum(xmltotext_with_options(DatumGetXmlP(value),
|
||||||
|
xexpr->xmloption,
|
||||||
|
xexpr->indent));
|
||||||
*op->resnull = false;
|
*op->resnull = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -613,7 +613,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
||||||
%type <node> xml_root_version opt_xml_root_standalone
|
%type <node> xml_root_version opt_xml_root_standalone
|
||||||
%type <node> xmlexists_argument
|
%type <node> xmlexists_argument
|
||||||
%type <ival> document_or_content
|
%type <ival> document_or_content
|
||||||
%type <boolean> xml_whitespace_option
|
%type <boolean> xml_indent_option xml_whitespace_option
|
||||||
%type <list> xmltable_column_list xmltable_column_option_list
|
%type <list> xmltable_column_list xmltable_column_option_list
|
||||||
%type <node> xmltable_column_el
|
%type <node> xmltable_column_el
|
||||||
%type <defelt> xmltable_column_option_el
|
%type <defelt> xmltable_column_option_el
|
||||||
|
@ -702,7 +702,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
||||||
HANDLER HAVING HEADER_P HOLD HOUR_P
|
HANDLER HAVING HEADER_P HOLD HOUR_P
|
||||||
|
|
||||||
IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IMPORT_P IN_P INCLUDE
|
IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IMPORT_P IN_P INCLUDE
|
||||||
INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
|
INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
|
||||||
INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
|
INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
|
||||||
INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
|
INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
|
||||||
|
|
||||||
|
@ -15532,13 +15532,14 @@ func_expr_common_subexpr:
|
||||||
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
|
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
|
||||||
list_make3($3, $5, $6), @1);
|
list_make3($3, $5, $6), @1);
|
||||||
}
|
}
|
||||||
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
|
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename xml_indent_option ')'
|
||||||
{
|
{
|
||||||
XmlSerialize *n = makeNode(XmlSerialize);
|
XmlSerialize *n = makeNode(XmlSerialize);
|
||||||
|
|
||||||
n->xmloption = $3;
|
n->xmloption = $3;
|
||||||
n->expr = $4;
|
n->expr = $4;
|
||||||
n->typeName = $6;
|
n->typeName = $6;
|
||||||
|
n->indent = $7;
|
||||||
n->location = @1;
|
n->location = @1;
|
||||||
$$ = (Node *) n;
|
$$ = (Node *) n;
|
||||||
}
|
}
|
||||||
|
@ -15592,6 +15593,11 @@ document_or_content: DOCUMENT_P { $$ = XMLOPTION_DOCUMENT; }
|
||||||
| CONTENT_P { $$ = XMLOPTION_CONTENT; }
|
| CONTENT_P { $$ = XMLOPTION_CONTENT; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
xml_indent_option: INDENT { $$ = true; }
|
||||||
|
| NO INDENT { $$ = false; }
|
||||||
|
| /*EMPTY*/ { $$ = false; }
|
||||||
|
;
|
||||||
|
|
||||||
xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = true; }
|
xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = true; }
|
||||||
| STRIP_P WHITESPACE_P { $$ = false; }
|
| STRIP_P WHITESPACE_P { $$ = false; }
|
||||||
| /*EMPTY*/ { $$ = false; }
|
| /*EMPTY*/ { $$ = false; }
|
||||||
|
@ -16828,6 +16834,7 @@ unreserved_keyword:
|
||||||
| INCLUDE
|
| INCLUDE
|
||||||
| INCLUDING
|
| INCLUDING
|
||||||
| INCREMENT
|
| INCREMENT
|
||||||
|
| INDENT
|
||||||
| INDEX
|
| INDEX
|
||||||
| INDEXES
|
| INDEXES
|
||||||
| INHERIT
|
| INHERIT
|
||||||
|
@ -17384,6 +17391,7 @@ bare_label_keyword:
|
||||||
| INCLUDE
|
| INCLUDE
|
||||||
| INCLUDING
|
| INCLUDING
|
||||||
| INCREMENT
|
| INCREMENT
|
||||||
|
| INDENT
|
||||||
| INDEX
|
| INDEX
|
||||||
| INDEXES
|
| INDEXES
|
||||||
| INHERIT
|
| INHERIT
|
||||||
|
|
|
@ -2331,6 +2331,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
|
||||||
typenameTypeIdAndMod(pstate, xs->typeName, &targetType, &targetTypmod);
|
typenameTypeIdAndMod(pstate, xs->typeName, &targetType, &targetTypmod);
|
||||||
|
|
||||||
xexpr->xmloption = xs->xmloption;
|
xexpr->xmloption = xs->xmloption;
|
||||||
|
xexpr->indent = xs->indent;
|
||||||
xexpr->location = xs->location;
|
xexpr->location = xs->location;
|
||||||
/* We actually only need these to be able to parse back the expression. */
|
/* We actually only need these to be able to parse back the expression. */
|
||||||
xexpr->type = targetType;
|
xexpr->type = targetType;
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
#include <libxml/uri.h>
|
#include <libxml/uri.h>
|
||||||
#include <libxml/xmlerror.h>
|
#include <libxml/xmlerror.h>
|
||||||
|
#include <libxml/xmlsave.h>
|
||||||
#include <libxml/xmlversion.h>
|
#include <libxml/xmlversion.h>
|
||||||
#include <libxml/xmlwriter.h>
|
#include <libxml/xmlwriter.h>
|
||||||
#include <libxml/xpath.h>
|
#include <libxml/xpath.h>
|
||||||
|
@ -146,6 +147,8 @@ static bool print_xml_decl(StringInfo buf, const xmlChar *version,
|
||||||
static bool xml_doctype_in_content(const xmlChar *str);
|
static bool xml_doctype_in_content(const xmlChar *str);
|
||||||
static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg,
|
static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg,
|
||||||
bool preserve_whitespace, int encoding,
|
bool preserve_whitespace, int encoding,
|
||||||
|
XmlOptionType *parsed_xmloptiontype,
|
||||||
|
xmlNodePtr *parsed_nodes,
|
||||||
Node *escontext);
|
Node *escontext);
|
||||||
static text *xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt);
|
static text *xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt);
|
||||||
static int xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
|
static int xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
|
||||||
|
@ -273,7 +276,7 @@ xml_in(PG_FUNCTION_ARGS)
|
||||||
* Note: we don't need to worry about whether a soft error is detected.
|
* Note: we don't need to worry about whether a soft error is detected.
|
||||||
*/
|
*/
|
||||||
doc = xml_parse(vardata, xmloption, true, GetDatabaseEncoding(),
|
doc = xml_parse(vardata, xmloption, true, GetDatabaseEncoding(),
|
||||||
fcinfo->context);
|
NULL, NULL, fcinfo->context);
|
||||||
if (doc != NULL)
|
if (doc != NULL)
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
@ -400,7 +403,7 @@ xml_recv(PG_FUNCTION_ARGS)
|
||||||
* Parse the data to check if it is well-formed XML data. Assume that
|
* Parse the data to check if it is well-formed XML data. Assume that
|
||||||
* xml_parse will throw ERROR if not.
|
* xml_parse will throw ERROR if not.
|
||||||
*/
|
*/
|
||||||
doc = xml_parse(result, xmloption, true, encoding, NULL);
|
doc = xml_parse(result, xmloption, true, encoding, NULL, NULL, NULL);
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
/* Now that we know what we're dealing with, convert to server encoding */
|
/* Now that we know what we're dealing with, convert to server encoding */
|
||||||
|
@ -619,15 +622,182 @@ xmltotext(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
|
|
||||||
text *
|
text *
|
||||||
xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg)
|
xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
|
||||||
{
|
{
|
||||||
if (xmloption_arg == XMLOPTION_DOCUMENT && !xml_is_document(data))
|
#ifdef USE_LIBXML
|
||||||
|
text *volatile result;
|
||||||
|
xmlDocPtr doc;
|
||||||
|
XmlOptionType parsed_xmloptiontype;
|
||||||
|
xmlNodePtr content_nodes;
|
||||||
|
volatile xmlBufferPtr buf = NULL;
|
||||||
|
volatile xmlSaveCtxtPtr ctxt = NULL;
|
||||||
|
ErrorSaveContext escontext = {T_ErrorSaveContext};
|
||||||
|
PgXmlErrorContext *xmlerrcxt;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (xmloption_arg != XMLOPTION_DOCUMENT && !indent)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We don't actually need to do anything, so just return the
|
||||||
|
* binary-compatible input. For backwards-compatibility reasons,
|
||||||
|
* allow such cases to succeed even without USE_LIBXML.
|
||||||
|
*/
|
||||||
|
return (text *) data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_LIBXML
|
||||||
|
/* Parse the input according to the xmloption */
|
||||||
|
doc = xml_parse(data, xmloption_arg, true, GetDatabaseEncoding(),
|
||||||
|
&parsed_xmloptiontype, &content_nodes,
|
||||||
|
(Node *) &escontext);
|
||||||
|
if (doc == NULL || escontext.error_occurred)
|
||||||
|
{
|
||||||
|
if (doc)
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
/* A soft error must be failure to conform to XMLOPTION_DOCUMENT */
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_NOT_AN_XML_DOCUMENT),
|
(errcode(ERRCODE_NOT_AN_XML_DOCUMENT),
|
||||||
errmsg("not an XML document")));
|
errmsg("not an XML document")));
|
||||||
|
}
|
||||||
|
|
||||||
/* It's actually binary compatible, save for the above check. */
|
/* If we weren't asked to indent, we're done. */
|
||||||
return (text *) data;
|
if (!indent)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
return (text *) data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, we gotta spin up some error handling. */
|
||||||
|
xmlerrcxt = pg_xml_init(PG_XML_STRICTNESS_ALL);
|
||||||
|
|
||||||
|
PG_TRY();
|
||||||
|
{
|
||||||
|
size_t decl_len = 0;
|
||||||
|
|
||||||
|
/* The serialized data will go into this buffer. */
|
||||||
|
buf = xmlBufferCreate();
|
||||||
|
|
||||||
|
if (buf == NULL || xmlerrcxt->err_occurred)
|
||||||
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
|
||||||
|
"could not allocate xmlBuffer");
|
||||||
|
|
||||||
|
/* Detect whether there's an XML declaration */
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (ctxt == NULL || xmlerrcxt->err_occurred)
|
||||||
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
|
||||||
|
"could not allocate xmlSaveCtxt");
|
||||||
|
|
||||||
|
if (parsed_xmloptiontype == XMLOPTION_DOCUMENT)
|
||||||
|
{
|
||||||
|
/* If it's a document, saving is easy. */
|
||||||
|
if (xmlSaveDoc(ctxt, doc) == -1 || xmlerrcxt->err_occurred)
|
||||||
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
|
"could not save document to xmlBuffer");
|
||||||
|
}
|
||||||
|
else if (content_nodes != NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Deal with the case where we have non-singly-rooted XML.
|
||||||
|
* libxml's dump functions don't work well for that without help.
|
||||||
|
* We build a fake root node that serves as a container for the
|
||||||
|
* content nodes, and then iterate over the nodes.
|
||||||
|
*/
|
||||||
|
xmlNodePtr root;
|
||||||
|
xmlNodePtr newline;
|
||||||
|
|
||||||
|
root = xmlNewNode(NULL, (const xmlChar *) "content-root");
|
||||||
|
if (root == NULL || xmlerrcxt->err_occurred)
|
||||||
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
|
||||||
|
"could not allocate xml node");
|
||||||
|
|
||||||
|
/* This attaches root to doc, so we need not free it separately. */
|
||||||
|
xmlDocSetRootElement(doc, root);
|
||||||
|
xmlAddChild(root, content_nodes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use this node to insert newlines in the dump. Note: in at
|
||||||
|
* least some libxml versions, xmlNewDocText would not attach the
|
||||||
|
* node to the document even if we passed it. Therefore, manage
|
||||||
|
* 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");
|
||||||
|
|
||||||
|
for (xmlNodePtr node = root->children; node; node = node->next)
|
||||||
|
{
|
||||||
|
/* insert newlines between nodes */
|
||||||
|
if (node->type != XML_TEXT_NODE && node->prev != NULL)
|
||||||
|
{
|
||||||
|
if (xmlSaveTree(ctxt, newline) == -1 || xmlerrcxt->err_occurred)
|
||||||
|
{
|
||||||
|
xmlFreeNode(newline);
|
||||||
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
|
"could not save newline to xmlBuffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmlSaveTree(ctxt, node) == -1 || xmlerrcxt->err_occurred)
|
||||||
|
{
|
||||||
|
xmlFreeNode(newline);
|
||||||
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
|
"could not save content to xmlBuffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlFreeNode(newline);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmlSaveClose(ctxt) == -1 || xmlerrcxt->err_occurred)
|
||||||
|
{
|
||||||
|
ctxt = NULL; /* don't try to close it again */
|
||||||
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
|
"could not close xmlSaveCtxtPtr");
|
||||||
|
}
|
||||||
|
|
||||||
|
result = (text *) xmlBuffer_to_xmltype(buf);
|
||||||
|
}
|
||||||
|
PG_CATCH();
|
||||||
|
{
|
||||||
|
if (ctxt)
|
||||||
|
xmlSaveClose(ctxt);
|
||||||
|
if (buf)
|
||||||
|
xmlBufferFree(buf);
|
||||||
|
if (doc)
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
pg_xml_done(xmlerrcxt, true);
|
||||||
|
|
||||||
|
PG_RE_THROW();
|
||||||
|
}
|
||||||
|
PG_END_TRY();
|
||||||
|
|
||||||
|
xmlBufferFree(buf);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
pg_xml_done(xmlerrcxt, false);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
#else
|
||||||
|
NO_XML_SUPPORT();
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -762,7 +932,7 @@ xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace)
|
||||||
xmlDocPtr doc;
|
xmlDocPtr doc;
|
||||||
|
|
||||||
doc = xml_parse(data, xmloption_arg, preserve_whitespace,
|
doc = xml_parse(data, xmloption_arg, preserve_whitespace,
|
||||||
GetDatabaseEncoding(), NULL);
|
GetDatabaseEncoding(), NULL, NULL, NULL);
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
return (xmltype *) data;
|
return (xmltype *) data;
|
||||||
|
@ -902,7 +1072,7 @@ xml_is_document(xmltype *arg)
|
||||||
* We'll report "true" if no soft error is reported by xml_parse().
|
* We'll report "true" if no soft error is reported by xml_parse().
|
||||||
*/
|
*/
|
||||||
doc = xml_parse((text *) arg, XMLOPTION_DOCUMENT, true,
|
doc = xml_parse((text *) arg, XMLOPTION_DOCUMENT, true,
|
||||||
GetDatabaseEncoding(), (Node *) &escontext);
|
GetDatabaseEncoding(), NULL, NULL, (Node *) &escontext);
|
||||||
if (doc)
|
if (doc)
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
@ -1491,6 +1661,14 @@ xml_doctype_in_content(const xmlChar *str)
|
||||||
* and xmloption_arg and preserve_whitespace are options for the
|
* and xmloption_arg and preserve_whitespace are options for the
|
||||||
* transformation.
|
* transformation.
|
||||||
*
|
*
|
||||||
|
* If parsed_xmloptiontype isn't NULL, *parsed_xmloptiontype is set to the
|
||||||
|
* XmlOptionType actually used to parse the input (typically the same as
|
||||||
|
* xmloption_arg, but a DOCTYPE node in the input can force DOCUMENT mode).
|
||||||
|
*
|
||||||
|
* If parsed_nodes isn't NULL and the input is not an XML document, the list
|
||||||
|
* of parsed nodes from the xmlParseBalancedChunkMemory call will be returned
|
||||||
|
* to *parsed_nodes.
|
||||||
|
*
|
||||||
* Errors normally result in ereport(ERROR), but if escontext is an
|
* Errors normally result in ereport(ERROR), but if escontext is an
|
||||||
* ErrorSaveContext, then "safe" errors are reported there instead, and the
|
* ErrorSaveContext, then "safe" errors are reported there instead, and the
|
||||||
* caller must check SOFT_ERROR_OCCURRED() to see whether that happened.
|
* caller must check SOFT_ERROR_OCCURRED() to see whether that happened.
|
||||||
|
@ -1503,8 +1681,10 @@ xml_doctype_in_content(const xmlChar *str)
|
||||||
* yet do not use SAX - see xmlreader.c)
|
* yet do not use SAX - see xmlreader.c)
|
||||||
*/
|
*/
|
||||||
static xmlDocPtr
|
static xmlDocPtr
|
||||||
xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
|
xml_parse(text *data, XmlOptionType xmloption_arg,
|
||||||
int encoding, Node *escontext)
|
bool preserve_whitespace, int encoding,
|
||||||
|
XmlOptionType *parsed_xmloptiontype, xmlNodePtr *parsed_nodes,
|
||||||
|
Node *escontext)
|
||||||
{
|
{
|
||||||
int32 len;
|
int32 len;
|
||||||
xmlChar *string;
|
xmlChar *string;
|
||||||
|
@ -1574,6 +1754,13 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
|
||||||
parse_as_document = true;
|
parse_as_document = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* initialize output parameters */
|
||||||
|
if (parsed_xmloptiontype != NULL)
|
||||||
|
*parsed_xmloptiontype = parse_as_document ? XMLOPTION_DOCUMENT :
|
||||||
|
XMLOPTION_CONTENT;
|
||||||
|
if (parsed_nodes != NULL)
|
||||||
|
*parsed_nodes = NULL;
|
||||||
|
|
||||||
if (parse_as_document)
|
if (parse_as_document)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -1620,7 +1807,8 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
|
||||||
if (*(utf8string + count))
|
if (*(utf8string + count))
|
||||||
{
|
{
|
||||||
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
|
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
|
||||||
utf8string + count, NULL);
|
utf8string + count,
|
||||||
|
parsed_nodes);
|
||||||
if (res_code != 0 || xmlerrcxt->err_occurred)
|
if (res_code != 0 || xmlerrcxt->err_occurred)
|
||||||
{
|
{
|
||||||
xml_errsave(escontext, xmlerrcxt,
|
xml_errsave(escontext, xmlerrcxt,
|
||||||
|
@ -4305,7 +4493,7 @@ wellformed_xml(text *data, XmlOptionType xmloption_arg)
|
||||||
* We'll report "true" if no soft error is reported by xml_parse().
|
* We'll report "true" if no soft error is reported by xml_parse().
|
||||||
*/
|
*/
|
||||||
doc = xml_parse(data, xmloption_arg, true,
|
doc = xml_parse(data, xmloption_arg, true,
|
||||||
GetDatabaseEncoding(), (Node *) &escontext);
|
GetDatabaseEncoding(), NULL, NULL, (Node *) &escontext);
|
||||||
if (doc)
|
if (doc)
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 202303141
|
#define CATALOG_VERSION_NO 202303151
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -840,6 +840,7 @@ typedef struct XmlSerialize
|
||||||
XmlOptionType xmloption; /* DOCUMENT or CONTENT */
|
XmlOptionType xmloption; /* DOCUMENT or CONTENT */
|
||||||
Node *expr;
|
Node *expr;
|
||||||
TypeName *typeName;
|
TypeName *typeName;
|
||||||
|
bool indent; /* [NO] INDENT */
|
||||||
int location; /* token location, or -1 if unknown */
|
int location; /* token location, or -1 if unknown */
|
||||||
} XmlSerialize;
|
} XmlSerialize;
|
||||||
|
|
||||||
|
|
|
@ -1464,7 +1464,7 @@ typedef enum XmlExprOp
|
||||||
IS_XMLPARSE, /* XMLPARSE(text, is_doc, preserve_ws) */
|
IS_XMLPARSE, /* XMLPARSE(text, is_doc, preserve_ws) */
|
||||||
IS_XMLPI, /* XMLPI(name [, args]) */
|
IS_XMLPI, /* XMLPI(name [, args]) */
|
||||||
IS_XMLROOT, /* XMLROOT(xml, version, standalone) */
|
IS_XMLROOT, /* XMLROOT(xml, version, standalone) */
|
||||||
IS_XMLSERIALIZE, /* XMLSERIALIZE(is_document, xmlval) */
|
IS_XMLSERIALIZE, /* XMLSERIALIZE(is_document, xmlval, indent) */
|
||||||
IS_DOCUMENT /* xmlval IS DOCUMENT */
|
IS_DOCUMENT /* xmlval IS DOCUMENT */
|
||||||
} XmlExprOp;
|
} XmlExprOp;
|
||||||
|
|
||||||
|
@ -1489,6 +1489,8 @@ typedef struct XmlExpr
|
||||||
List *args;
|
List *args;
|
||||||
/* DOCUMENT or CONTENT */
|
/* DOCUMENT or CONTENT */
|
||||||
XmlOptionType xmloption pg_node_attr(query_jumble_ignore);
|
XmlOptionType xmloption pg_node_attr(query_jumble_ignore);
|
||||||
|
/* INDENT option for XMLSERIALIZE */
|
||||||
|
bool indent;
|
||||||
/* target type/typmod for XMLSERIALIZE */
|
/* target type/typmod for XMLSERIALIZE */
|
||||||
Oid type pg_node_attr(query_jumble_ignore);
|
Oid type pg_node_attr(query_jumble_ignore);
|
||||||
int32 typmod pg_node_attr(query_jumble_ignore);
|
int32 typmod pg_node_attr(query_jumble_ignore);
|
||||||
|
|
|
@ -205,6 +205,7 @@ PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, BARE_LABEL)
|
||||||
PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, BARE_LABEL)
|
PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||||
PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, BARE_LABEL)
|
PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||||
PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, BARE_LABEL)
|
PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||||
|
PG_KEYWORD("indent", INDENT, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||||
PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE_LABEL)
|
PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||||
PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE_LABEL)
|
PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||||
PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE_LABEL)
|
PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||||
|
|
|
@ -77,7 +77,8 @@ extern xmltype *xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_
|
||||||
extern xmltype *xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null);
|
extern xmltype *xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null);
|
||||||
extern xmltype *xmlroot(xmltype *data, text *version, int standalone);
|
extern xmltype *xmlroot(xmltype *data, text *version, int standalone);
|
||||||
extern bool xml_is_document(xmltype *arg);
|
extern bool xml_is_document(xmltype *arg);
|
||||||
extern text *xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg);
|
extern text *xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg,
|
||||||
|
bool indent);
|
||||||
extern char *escape_xml(const char *str);
|
extern char *escape_xml(const char *str);
|
||||||
|
|
||||||
extern char *map_sql_identifier_to_xml_name(const char *ident, bool fully_escaped, bool escape_period);
|
extern char *map_sql_identifier_to_xml_name(const char *ident, bool fully_escaped, bool escape_period);
|
||||||
|
|
|
@ -486,6 +486,192 @@ SELECT xmlserialize(content 'good' as char(10));
|
||||||
|
|
||||||
SELECT xmlserialize(document 'bad' as text);
|
SELECT xmlserialize(document 'bad' as text);
|
||||||
ERROR: not an XML document
|
ERROR: not an XML document
|
||||||
|
-- indent
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val>+
|
||||||
|
</bar> +
|
||||||
|
</foo> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val>+
|
||||||
|
</bar> +
|
||||||
|
</foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- no indent
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------------------------------
|
||||||
|
<foo><bar><val x="y">42</val></bar></foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------------------------------
|
||||||
|
<foo><bar><val x="y">42</val></bar></foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent non singly-rooted xml
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo>73</foo><bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
ERROR: not an XML document
|
||||||
|
SELECT xmlserialize(CONTENT '<foo>73</foo><bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-----------------------
|
||||||
|
<foo>73</foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val>+
|
||||||
|
</bar>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent non singly-rooted xml with mixed contents
|
||||||
|
SELECT xmlserialize(DOCUMENT 'text node<foo>73</foo>text node<bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
ERROR: not an XML document
|
||||||
|
SELECT xmlserialize(CONTENT 'text node<foo>73</foo>text node<bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
------------------------
|
||||||
|
text node +
|
||||||
|
<foo>73</foo>text node+
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val> +
|
||||||
|
</bar>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent singly-rooted xml with mixed contents
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val><val x="y">text node<val>73</val></val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
---------------------------------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val> +
|
||||||
|
<val x="y">text node<val>73</val></val>+
|
||||||
|
</bar> +
|
||||||
|
</foo> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val><val x="y">text node<val>73</val></val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
---------------------------------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val> +
|
||||||
|
<val x="y">text node<val>73</val></val>+
|
||||||
|
</bar> +
|
||||||
|
</foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent empty string
|
||||||
|
SELECT xmlserialize(DOCUMENT '' AS text INDENT);
|
||||||
|
ERROR: not an XML document
|
||||||
|
SELECT xmlserialize(CONTENT '' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- whitespaces
|
||||||
|
SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
|
||||||
|
ERROR: not an XML document
|
||||||
|
SELECT xmlserialize(CONTENT ' ' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent null
|
||||||
|
SELECT xmlserialize(DOCUMENT NULL AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT NULL AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent with XML declaration
|
||||||
|
SELECT xmlserialize(DOCUMENT '<?xml version="1.0" encoding="UTF-8"?><foo><bar><val>73</val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
----------------------------------------
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>+
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val>73</val> +
|
||||||
|
</bar> +
|
||||||
|
</foo> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<?xml version="1.0" encoding="UTF-8"?><foo><bar><val>73</val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val>73</val>+
|
||||||
|
</bar> +
|
||||||
|
</foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent containing DOCTYPE declaration
|
||||||
|
SELECT xmlserialize(DOCUMENT '<!DOCTYPE a><a/>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
<!DOCTYPE a>+
|
||||||
|
<a/> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<!DOCTYPE a><a/>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
<!DOCTYPE a>+
|
||||||
|
<a/> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent xml with empty element
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
<foo> +
|
||||||
|
<bar/> +
|
||||||
|
</foo> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
<foo> +
|
||||||
|
<bar/> +
|
||||||
|
</foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- 'no indent' = not using 'no indent'
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text) = xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text) = xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -309,6 +309,140 @@ ERROR: unsupported XML feature
|
||||||
LINE 1: SELECT xmlserialize(document 'bad' as text);
|
LINE 1: SELECT xmlserialize(document 'bad' as text);
|
||||||
^
|
^
|
||||||
DETAIL: This functionality requires the server to be built with libxml support.
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- indent
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val><...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val><...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- no indent
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val><...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val><...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- indent non singly-rooted xml
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo>73</foo><bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT '<foo>73</foo><bar><val x="y">4...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT '<foo>73</foo><bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT '<foo>73</foo><bar><val x="y">4...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- indent non singly-rooted xml with mixed contents
|
||||||
|
SELECT xmlserialize(DOCUMENT 'text node<foo>73</foo>text node<bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT 'text node<foo>73</foo>text nod...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT 'text node<foo>73</foo>text node<bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT 'text node<foo>73</foo>text nod...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- indent singly-rooted xml with mixed contents
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val><val x="y">text node<val>73</val></val></bar></foo>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val><...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val><val x="y">text node<val>73</val></val></bar></foo>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val><...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- indent empty string
|
||||||
|
SELECT xmlserialize(DOCUMENT '' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT '' AS text INDENT);
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT '' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT '' AS text INDENT);
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- whitespaces
|
||||||
|
SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT ' ' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT ' ' AS text INDENT);
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- indent null
|
||||||
|
SELECT xmlserialize(DOCUMENT NULL AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT NULL AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent with XML declaration
|
||||||
|
SELECT xmlserialize(DOCUMENT '<?xml version="1.0" encoding="UTF-8"?><foo><bar><val>73</val></bar></foo>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT '<?xml version="1.0" encoding="...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT '<?xml version="1.0" encoding="UTF-8"?><foo><bar><val>73</val></bar></foo>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT '<?xml version="1.0" encoding="...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- indent containing DOCTYPE declaration
|
||||||
|
SELECT xmlserialize(DOCUMENT '<!DOCTYPE a><a/>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT '<!DOCTYPE a><a/>' AS text INDE...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT '<!DOCTYPE a><a/>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT '<!DOCTYPE a><a/>' AS text INDE...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- indent xml with empty element
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar></bar></foo>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT '<foo><bar></bar></foo>' AS tex...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar></bar></foo>' AS text INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT '<foo><bar></bar></foo>' AS tex...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
-- 'no indent' = not using 'no indent'
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text) = xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val><...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text) = xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val><...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
||||||
ERROR: unsupported XML feature
|
ERROR: unsupported XML feature
|
||||||
LINE 1: SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
LINE 1: SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
||||||
|
|
|
@ -466,6 +466,192 @@ SELECT xmlserialize(content 'good' as char(10));
|
||||||
|
|
||||||
SELECT xmlserialize(document 'bad' as text);
|
SELECT xmlserialize(document 'bad' as text);
|
||||||
ERROR: not an XML document
|
ERROR: not an XML document
|
||||||
|
-- indent
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val>+
|
||||||
|
</bar> +
|
||||||
|
</foo> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val>+
|
||||||
|
</bar> +
|
||||||
|
</foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- no indent
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------------------------------
|
||||||
|
<foo><bar><val x="y">42</val></bar></foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------------------------------
|
||||||
|
<foo><bar><val x="y">42</val></bar></foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent non singly-rooted xml
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo>73</foo><bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
ERROR: not an XML document
|
||||||
|
SELECT xmlserialize(CONTENT '<foo>73</foo><bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-----------------------
|
||||||
|
<foo>73</foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val>+
|
||||||
|
</bar>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent non singly-rooted xml with mixed contents
|
||||||
|
SELECT xmlserialize(DOCUMENT 'text node<foo>73</foo>text node<bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
ERROR: not an XML document
|
||||||
|
SELECT xmlserialize(CONTENT 'text node<foo>73</foo>text node<bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
------------------------
|
||||||
|
text node +
|
||||||
|
<foo>73</foo>text node+
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val> +
|
||||||
|
</bar>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent singly-rooted xml with mixed contents
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val><val x="y">text node<val>73</val></val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
---------------------------------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val> +
|
||||||
|
<val x="y">text node<val>73</val></val>+
|
||||||
|
</bar> +
|
||||||
|
</foo> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val><val x="y">text node<val>73</val></val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
---------------------------------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val x="y">42</val> +
|
||||||
|
<val x="y">text node<val>73</val></val>+
|
||||||
|
</bar> +
|
||||||
|
</foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent empty string
|
||||||
|
SELECT xmlserialize(DOCUMENT '' AS text INDENT);
|
||||||
|
ERROR: not an XML document
|
||||||
|
SELECT xmlserialize(CONTENT '' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- whitespaces
|
||||||
|
SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
|
||||||
|
ERROR: not an XML document
|
||||||
|
SELECT xmlserialize(CONTENT ' ' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent null
|
||||||
|
SELECT xmlserialize(DOCUMENT NULL AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT NULL AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent with XML declaration
|
||||||
|
SELECT xmlserialize(DOCUMENT '<?xml version="1.0" encoding="UTF-8"?><foo><bar><val>73</val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
----------------------------------------
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>+
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val>73</val> +
|
||||||
|
</bar> +
|
||||||
|
</foo> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<?xml version="1.0" encoding="UTF-8"?><foo><bar><val>73</val></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
-------------------
|
||||||
|
<foo> +
|
||||||
|
<bar> +
|
||||||
|
<val>73</val>+
|
||||||
|
</bar> +
|
||||||
|
</foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent containing DOCTYPE declaration
|
||||||
|
SELECT xmlserialize(DOCUMENT '<!DOCTYPE a><a/>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
<!DOCTYPE a>+
|
||||||
|
<a/> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<!DOCTYPE a><a/>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
<!DOCTYPE a>+
|
||||||
|
<a/> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- indent xml with empty element
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
<foo> +
|
||||||
|
<bar/> +
|
||||||
|
</foo> +
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar></bar></foo>' AS text INDENT);
|
||||||
|
xmlserialize
|
||||||
|
--------------
|
||||||
|
<foo> +
|
||||||
|
<bar/> +
|
||||||
|
</foo>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- 'no indent' = not using 'no indent'
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text) = xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text) = xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -132,6 +132,42 @@ SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
|
||||||
SELECT xmlserialize(content 'good' as char(10));
|
SELECT xmlserialize(content 'good' as char(10));
|
||||||
SELECT xmlserialize(document 'bad' as text);
|
SELECT xmlserialize(document 'bad' as text);
|
||||||
|
|
||||||
|
-- indent
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text INDENT);
|
||||||
|
-- no indent
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
-- indent non singly-rooted xml
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo>73</foo><bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT '<foo>73</foo><bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
-- indent non singly-rooted xml with mixed contents
|
||||||
|
SELECT xmlserialize(DOCUMENT 'text node<foo>73</foo>text node<bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT 'text node<foo>73</foo>text node<bar><val x="y">42</val></bar>' AS text INDENT);
|
||||||
|
-- indent singly-rooted xml with mixed contents
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val><val x="y">text node<val>73</val></val></bar></foo>' AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val><val x="y">text node<val>73</val></val></bar></foo>' AS text INDENT);
|
||||||
|
-- indent empty string
|
||||||
|
SELECT xmlserialize(DOCUMENT '' AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT '' AS text INDENT);
|
||||||
|
-- whitespaces
|
||||||
|
SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT ' ' AS text INDENT);
|
||||||
|
-- indent null
|
||||||
|
SELECT xmlserialize(DOCUMENT NULL AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT NULL AS text INDENT);
|
||||||
|
-- indent with XML declaration
|
||||||
|
SELECT xmlserialize(DOCUMENT '<?xml version="1.0" encoding="UTF-8"?><foo><bar><val>73</val></bar></foo>' AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT '<?xml version="1.0" encoding="UTF-8"?><foo><bar><val>73</val></bar></foo>' AS text INDENT);
|
||||||
|
-- indent containing DOCTYPE declaration
|
||||||
|
SELECT xmlserialize(DOCUMENT '<!DOCTYPE a><a/>' AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT '<!DOCTYPE a><a/>' AS text INDENT);
|
||||||
|
-- indent xml with empty element
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar></bar></foo>' AS text INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar></bar></foo>' AS text INDENT);
|
||||||
|
-- 'no indent' = not using 'no indent'
|
||||||
|
SELECT xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text) = xmlserialize(DOCUMENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
SELECT xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text) = xmlserialize(CONTENT '<foo><bar><val x="y">42</val></bar></foo>' AS text NO INDENT);
|
||||||
|
|
||||||
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
|
||||||
SELECT xml '<foo>bar</foo><bar>foo</bar>' IS DOCUMENT;
|
SELECT xml '<foo>bar</foo><bar>foo</bar>' IS DOCUMENT;
|
||||||
|
|
Loading…
Reference in New Issue