diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 1c5cfee25d12..aefca78a5baf 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -14720,7 +14720,10 @@ SELECT xmlconcat('', '
-xmlelement ( NAME name , XMLATTRIBUTES ( attvalue AS attname , ... ) , content , ... ) xml
+xmlelement ( NAME name
+ , XMLATTRIBUTES ( attvalue AS attname , ... )
+ , XMLNAMESPACES ( {regular-nsuri AS nsprefix | DEFAULT default-nsuri | NO DEFAULT} , ... )
+, content , ... ) xml
@@ -14733,7 +14736,39 @@ SELECT xmlconcat('', 'PostgreSQL data type. The
argument(s) within XMLATTRIBUTES generate attributes
of the XML element; the content value(s) are
- concatenated to form its content.
+ concatenated to form its content. The arguments within XMLNAMESPACES
+ constuct namespace declarations from values provided in nsuri
+ and nsprefix, which correspond to the URI of a namespace and
+ its prefix, respectively. The option DEFAULT can be used to set the
+ default namespace declaration (without a prefix) to the URI provided in default-nsuri.
+ The option NO DEFAULT states that a namespace scope has no default namespace. A valid
+ XMLNAMESPACES item must fulfill the following conditions:
+
+
+
+
+ Only a single DEFAULT declaration item within the same scope.
+
+
+
+
+ No two nsuri can be equal within the same scope.
+
+
+
+
+ No nsprefix can be equal to xml or xmlns,
+ and no nsuri can be equal to http://www.w3.org/2000/xmlns/
+ or to http://www.w3.org/XML/1998/namespace, as they are already bouned to standard XML declarations.
+
+
+
+
+ The value of a regular-nsuri cannot be a zero-length string.
+
+
+
+
@@ -14756,6 +14791,24 @@ SELECT xmlelement(name foo, xmlattributes(current_date as bar), 'cont', 'ent');
xmlelement
-------------------------------------
content
+
+SELECT xmlelement(NAME "foo:root", xmlnamespaces('http:/foo.bar/' AS foo), 'content');
+
+ xmlelement
+---------------------------------------------------------
+ content
+
+ SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/foo.bar/'), 'content');
+
+ xmlelement
+---------------------------------------------
+ content
+
+ SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT), 'content');
+
+ xmlelement
+-------------------------------
+ content
]]>
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 3c4268b271a4..738fd98021f9 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -136,6 +136,12 @@ typedef struct KeyActions
KeyAction *deleteAction;
} KeyActions;
+typedef struct XmlElementOpts
+{
+ List *xml_attributes;
+ List *xml_namespaces;
+} XmlElementOpts;
+
/* ConstraintAttributeSpec yields an integer bitmask of these flags: */
#define CAS_NOT_DEFERRABLE 0x01
#define CAS_DEFERRABLE 0x02
@@ -187,7 +193,7 @@ static Node *makeNotExpr(Node *expr, int location);
static Node *makeAArrayExpr(List *elements, int location);
static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod,
int location);
-static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
+static Node *makeXmlExpr(XmlExprOp op, char *name, XmlElementOpts *opts,
List *args, int location);
static List *mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner);
static TypeName *TableFuncTypeName(List *columns);
@@ -267,6 +273,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
MergeWhenClause *mergewhen;
struct KeyActions *keyactions;
struct KeyAction *keyaction;
+ struct XmlElementOpts *xmlelementopts;
ReturningClause *retclause;
ReturningOptionKind retoptionkind;
}
@@ -618,8 +625,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type xmltable_column_list xmltable_column_option_list
%type xmltable_column_el
%type xmltable_column_option_el
-%type xml_namespace_list
+%type xml_namespace_list xml_namespaces
%type xml_namespace_el
+%type xmlelement_opts
%type func_application func_expr_common_subexpr
%type func_expr func_expr_windowless
@@ -14308,6 +14316,15 @@ xml_namespace_el:
$$->val = $2;
$$->location = @1;
}
+ | NO DEFAULT
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = NULL;
+ $$->indirection = NIL;
+ $$->val = NULL;
+ $$->location = @1;
+ }
+
;
json_table:
@@ -15361,12 +15378,12 @@ a_expr: c_expr { $$ = $1; }
}
| a_expr IS DOCUMENT_P %prec IS
{
- $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NULL,
list_make1($1), @2);
}
| a_expr IS NOT DOCUMENT_P %prec IS
{
- $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NULL,
list_make1($1), @2),
@2);
}
@@ -15508,12 +15525,12 @@ b_expr: c_expr
}
| b_expr IS DOCUMENT_P %prec IS
{
- $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NULL,
list_make1($1), @2);
}
| b_expr IS NOT DOCUMENT_P %prec IS
{
- $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NULL,
list_make1($1), @2),
@2);
}
@@ -16048,21 +16065,21 @@ func_expr_common_subexpr:
}
| XMLCONCAT '(' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
+ $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NULL, $3, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, NIL, @1);
}
- | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
+ | XMLELEMENT '(' NAME_P ColLabel ',' xmlelement_opts ')'
{
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, $6, @1);
}
- | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
+ | XMLELEMENT '(' NAME_P ColLabel ',' xmlelement_opts ',' expr_list ')'
{
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
}
@@ -16077,12 +16094,17 @@ func_expr_common_subexpr:
}
| XMLFOREST '(' xml_attribute_list ')'
{
- $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
+ XmlElementOpts opts;
+
+ opts.xml_attributes = $3;
+ opts.xml_namespaces = NIL;
+
+ $$ = makeXmlExpr(IS_XMLFOREST, NULL, &opts, NIL, @1);
}
| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
{
XmlExpr *x = (XmlExpr *)
- makeXmlExpr(IS_XMLPARSE, NULL, NIL,
+ makeXmlExpr(IS_XMLPARSE, NULL, NULL,
list_make2($4, makeBoolAConst($5, -1)),
@1);
@@ -16099,7 +16121,7 @@ func_expr_common_subexpr:
}
| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
{
- $$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
+ $$ = makeXmlExpr(IS_XMLROOT, NULL, NULL,
list_make3($3, $5, $6), @1);
}
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename xml_indent_option ')'
@@ -16303,6 +16325,9 @@ opt_xml_root_standalone: ',' STANDALONE_P YES_P
xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
;
+xml_namespaces: XMLNAMESPACES '(' xml_namespace_list ')' { $$ = $3; }
+ ;
+
xml_attribute_list: xml_attribute_el { $$ = list_make1($1); }
| xml_attribute_list ',' xml_attribute_el { $$ = lappend($1, $3); }
;
@@ -16339,6 +16364,44 @@ xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = true; }
| /*EMPTY*/ { $$ = false; }
;
+xmlelement_opts: xml_attributes
+ {
+ XmlElementOpts *n = palloc(sizeof(XmlElementOpts));
+
+ n->xml_attributes = $1;
+ n->xml_namespaces = NIL;
+ $$ = n;
+ }
+ | xml_namespaces
+ {
+ XmlElementOpts *n = palloc(sizeof(XmlElementOpts));
+
+ n->xml_attributes = NIL;
+ n->xml_namespaces = $1;
+ $$ = n;
+ }
+ | xmlelement_opts ',' xml_attributes
+ {
+ if ($$->xml_attributes)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("duplicate XMLATTRIBUTES specified"),
+ parser_errposition(@3)));
+
+ $$->xml_attributes = $3;
+ }
+ | xmlelement_opts ',' xml_namespaces
+ {
+ if ($$->xml_namespaces)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("duplicate XMLNAMESACES specified"),
+ parser_errposition(@3)));
+
+ $$->xml_namespaces = $3;
+ }
+ ;
+
/* We allow several variants for SQL and other compatibility. */
xmlexists_argument:
PASSING c_expr
@@ -19315,7 +19378,7 @@ makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location)
}
static Node *
-makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
+makeXmlExpr(XmlExprOp op, char *name, XmlElementOpts *opts, List *args,
int location)
{
XmlExpr *x = makeNode(XmlExpr);
@@ -19327,7 +19390,12 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
* named_args is a list of ResTarget; it'll be split apart into separate
* expression and name lists in transformXmlExpr().
*/
- x->named_args = named_args;
+ if (opts)
+ {
+ x->named_args = opts->xml_attributes;
+ x->xmlnamespaces = opts->xml_namespaces;
+ }
+
x->arg_names = NIL;
x->args = args;
/* xmloption, if relevant, must be filled in by caller */
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 9f20a70ce13c..f6b512505c60 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -842,7 +842,12 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
Node *ns_uri;
Assert(IsA(r, ResTarget));
- ns_uri = transformExpr(pstate, r->val, EXPR_KIND_FROM_FUNCTION);
+ /* Create an empty String for NO DEFAULT namespaces */
+ if (!r->name && !r->val)
+ ns_uri = transformExpr(pstate, makeStringConst("", r->location), EXPR_KIND_FROM_FUNCTION);
+ else
+ ns_uri = transformExpr(pstate, r->val, EXPR_KIND_FROM_FUNCTION);
+
ns_uri = coerce_to_specific_type(pstate, ns_uri,
TEXTOID, constructName);
assign_expr_collations(pstate, ns_uri);
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 1f8e2d54673d..9f1afb21ed7b 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2355,6 +2355,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
XmlExpr *newx;
ListCell *lc;
int i;
+ bool has_default_xmlns = false;
newx = makeNode(XmlExpr);
newx->op = x->op;
@@ -2374,6 +2375,80 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
newx->named_args = NIL;
newx->arg_names = NIL;
+ /*
+ * this adds the xmlnamespaces into arg_names and named_args
+ */
+ foreach (lc, x->xmlnamespaces)
+ {
+ ResTarget *r = lfirst_node(ResTarget, lc);
+ Node *expr;
+ ListCell *lc2;
+ char *argname = NULL;
+
+ /*
+ * SQL/XML:2023 - 11.2
+ * Syntax Rule 2) shall contain at most one
+ * .
+ */
+ if (!r->name)
+ {
+ if (has_default_xmlns)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("XML elements can have only a single [NO] DEFAULT namespace"),
+ parser_errposition(pstate, r->location)));
+
+ has_default_xmlns = true;
+ }
+ /*
+ * SQL/XML:2023 - 11.2
+ * Syntax Rule 5) No shall be equivalent to
+ * "xml" or "xmlns".
+ */
+ else if (strcmp(r->name, NAMESPACE_XMLNS_DEFAULT_PREFIX) == 0 ||
+ strcmp(r->name, NAMESPACE_XML_DEFAULT_PREFIX) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid XML namespace prefix \"%s\"", r->name),
+ errdetail("this prefix is already bounded to a standard namespace URI"),
+ parser_errposition(pstate, r->location)));
+ else if (r->name)
+ argname = map_sql_identifier_to_xml_name(r->name, false, false);
+
+ else if (IsA(r->val, ColumnRef))
+ argname = map_sql_identifier_to_xml_name(FigureColname(r->val),
+ true, false);
+
+ /*
+ * SQL/XML:2023 - 11.2
+ * Syntax Rule 4) No two es shall be equivalent.
+ */
+ if (x->op == IS_XMLELEMENT && argname)
+ {
+ foreach(lc2, newx->arg_names)
+ {
+ if (!strVal(lfirst(lc2)))
+ continue;
+
+ if (strVal(lfirst(lc2)) && strcmp(argname, strVal(lfirst(lc2))) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("XML namespace name \"%s\" appears more than once",
+ argname),
+ parser_errposition(pstate, r->location)));
+ }
+ }
+
+ if(r->val)
+ expr = transformExprRecurse(pstate, r->val);
+ else
+ expr = transformExprRecurse(pstate, makeStringConst("", newx->location));
+
+ newx->named_args = lappend(newx->named_args, expr);
+ newx->arg_names = lappend(newx->arg_names, makeString(!argname ? "" : argname));
+ newx->xmlnamespaces = lappend(newx->xmlnamespaces, makeString(NAMESPACE_XMLNS_DEFAULT_PREFIX));
+ }
+
foreach(lc, x->named_args)
{
ResTarget *r = lfirst_node(ResTarget, lc);
@@ -2405,6 +2480,10 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
foreach(lc2, newx->arg_names)
{
+
+ if (!strVal(lfirst(lc2)))
+ continue;
+
if (strcmp(argname, strVal(lfirst(lc2))) == 0)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@@ -2416,6 +2495,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
newx->named_args = lappend(newx->named_args, expr);
newx->arg_names = lappend(newx->arg_names, makeString(argname));
+ newx->xmlnamespaces = lappend(newx->xmlnamespaces, makeString(""));
}
/* The other arguments are of varying types depending on the function */
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 9e90acedb919..f840b8471140 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -10056,6 +10056,7 @@ get_rule_expr(Node *node, deparse_context *context,
bool needcomma = false;
ListCell *arg;
ListCell *narg;
+ ListCell *nsarg;
Const *con;
switch (xexpr->op)
@@ -10099,26 +10100,84 @@ get_rule_expr(Node *node, deparse_context *context,
}
if (xexpr->named_args)
{
- if (xexpr->op != IS_XMLFOREST)
+ bool hasFunctCall = false;
+
+ forthree(arg, xexpr->named_args, narg, xexpr->arg_names, nsarg, xexpr->xmlnamespaces)
{
+ Node *e = (Node *)lfirst(arg);
+ char *argname = strVal(lfirst(narg));
+ char *prefix = strVal(lfirst(nsarg));
+
+ /* we skip this entry, as it is not a XMLATTRIBUTES argument */
+ if (strlen(prefix) != 0)
+ continue;
+
+ if (!hasFunctCall)
+ {
+ if (xexpr->op != IS_XMLFOREST)
+ {
+ if (needcomma)
+ appendStringInfoString(buf, ", ");
+ appendStringInfoString(buf, "XMLATTRIBUTES(");
+ needcomma = false;
+ }
+
+ hasFunctCall = true;
+ }
+
if (needcomma)
appendStringInfoString(buf, ", ");
- appendStringInfoString(buf, "XMLATTRIBUTES(");
- needcomma = false;
+
+ get_rule_expr((Node *)e, context, true);
+ appendStringInfo(buf, " AS %s",
+ quote_identifier(map_xml_name_to_sql_identifier(argname)));
+ needcomma = true;
}
- forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
+ if (xexpr->op != IS_XMLFOREST && hasFunctCall)
+ appendStringInfoChar(buf, ')');
+
+ hasFunctCall = false;
+
+ forthree(arg, xexpr->named_args, narg, xexpr->arg_names, nsarg, xexpr->xmlnamespaces)
{
- Node *e = (Node *) lfirst(arg);
- char *argname = strVal(lfirst(narg));
+ Node *e = (Node *)lfirst(arg);
+ char *argname = strVal(lfirst(narg));
+ char *prefix = strVal(lfirst(nsarg));
+
+ /* we skip this entry, as it is not a XMLNAMESPACES argument */
+ if (strlen(prefix) == 0)
+ continue;
+
+ if (!hasFunctCall)
+ {
+ if (xexpr->op != IS_XMLFOREST)
+ {
+ if (needcomma)
+ appendStringInfoString(buf, ", ");
+ appendStringInfoString(buf, "XMLNAMESPACES(");
+ needcomma = false;
+ }
+
+ hasFunctCall = true;
+ }
if (needcomma)
appendStringInfoString(buf, ", ");
- get_rule_expr((Node *) e, context, true);
- appendStringInfo(buf, " AS %s",
- quote_identifier(map_xml_name_to_sql_identifier(argname)));
+
+ if (strlen(argname) == 0)
+ {
+ appendStringInfo(buf, "DEFAULT ");
+ get_rule_expr((Node *)e, context, true);
+ }
+ else
+ {
+ get_rule_expr((Node *)e, context, true);
+ appendStringInfo(buf, " AS %s",
+ quote_identifier(map_xml_name_to_sql_identifier(argname)));
+ }
needcomma = true;
}
- if (xexpr->op != IS_XMLFOREST)
+ if (xexpr->op != IS_XMLFOREST && hasFunctCall)
appendStringInfoChar(buf, ')');
}
if (xexpr->args)
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index db8d0d6a7e87..2cdb85cce755 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -244,7 +244,6 @@ const TableFuncRoutine XmlTableRoutine =
#define NAMESPACE_XSI "http://www.w3.org/2001/XMLSchema-instance"
#define NAMESPACE_SQLXML "http://standards.iso.org/iso/9075/2003/sqlxml"
-
#ifdef USE_LIBXML
static int
@@ -865,6 +864,7 @@ xmlelement(XmlExpr *xexpr,
int i;
ListCell *arg;
ListCell *narg;
+ ListCell *nsarg;
PgXmlErrorContext *xmlerrcxt;
volatile xmlBufferPtr buf = NULL;
volatile xmlTextWriterPtr writer = NULL;
@@ -926,12 +926,53 @@ xmlelement(XmlExpr *xexpr,
xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name);
- forboth(arg, named_arg_strings, narg, xexpr->arg_names)
+ forthree(arg, named_arg_strings, narg, xexpr->arg_names, nsarg, xexpr->xmlnamespaces)
{
char *str = (char *) lfirst(arg);
char *argname = strVal(lfirst(narg));
+ char *prefix = strVal(lfirst(nsarg));
- if (str)
+ if (str && strlen(prefix) != 0)
+ {
+ /*
+ * SQL/XML:2023 - 11.2
+ * Syntax Rule 6) No shall be identical, as defined
+ * in XML Namespaces, to http://www.w3.org/2000/xmlns/ or to
+ * http://www.w3.org/XML/1998/namespace
+ */
+ if (strcmp(str, NAMESPACE_XMLNS) == 0 || strcmp(str, NAMESPACE_XML) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid XML namespace URI \"%s\"", str),
+ errdetail("this URI is already bounded to standard a namespace prefix")));
+
+ /*
+ * SQL/XML:2023 - 11.2
+ * Syntax Rule 7) The value of an contained in an
+ * shall not be a zero-length string.
+ */
+ if (strlen(argname) != 0 && strlen(str) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_ZERO_LENGTH_CHARACTER_STRING),
+ errmsg("invalid XML namespace URI for \"%s\"", argname),
+ errdetail("a regular XML namespace cannot be a zero-length string")));
+
+ /*
+ * xmlTextWriterWriteAttributeNS
+ * prefix - Namespace prefix for the attribute. Pass NULL for no prefix,
+ * which means DEFAULT namespace.
+ * name - Local name of the attribute (without prefix). This is the
+ * actual attribute name.
+ * namespaceURI - Namespace URI associated with the prefix (NULL for none).
+ * content - Value of the attribute.
+ */
+ xmlTextWriterWriteAttributeNS(writer,
+ strlen(argname) == 0 ? NULL : (const xmlChar *) prefix,
+ strlen(argname) != 0 ? (const xmlChar *) argname : (const xmlChar *) prefix,
+ NULL,
+ (const xmlChar *) str);
+ }
+ else if (str)
xmlTextWriterWriteAttribute(writer,
(xmlChar *) argname,
(xmlChar *) str);
@@ -4789,7 +4830,11 @@ XmlTableSetNamespace(TableFuncScanState *state, const char *name, const char *ur
#ifdef USE_LIBXML
XmlTableBuilderData *xtCxt;
- if (name == NULL)
+ if (name == NULL && strlen(uri) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("NO DEFAULT namespace is not supported")));
+ else if (name == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("DEFAULT namespace is not supported")));
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 7d3b4198f266..e4ab2b8cd3c2 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1583,7 +1583,7 @@ typedef struct SQLValueFunction
typedef enum XmlExprOp
{
IS_XMLCONCAT, /* XMLCONCAT(args) */
- IS_XMLELEMENT, /* XMLELEMENT(name, xml_attributes, args) */
+ IS_XMLELEMENT, /* XMLELEMENT(name, xml_attributes, xml_namespaces, args) */
IS_XMLFOREST, /* XMLFOREST(xml_attributes) */
IS_XMLPARSE, /* XMLPARSE(text, is_doc, preserve_ws) */
IS_XMLPI, /* XMLPI(name [, args]) */
@@ -1607,6 +1607,8 @@ typedef struct XmlExpr
char *name pg_node_attr(query_jumble_ignore);
/* non-XML expressions for xml_attributes */
List *named_args;
+ /* non-XML expressions for XMLNAMESPACES */
+ List *xmlnamespaces;
/* parallel list of String values */
List *arg_names pg_node_attr(query_jumble_ignore);
/* list of expressions */
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index 0d7a816b9f93..4a714dbca9f4 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -59,6 +59,12 @@ XmlPGetDatum(const xmltype *X)
return PointerGetDatum(X);
}
+/* reserved prefixes and URIs for XMLNamespace() from SQL/XML:2023, 11.2 */
+#define NAMESPACE_XMLNS "http://www.w3.org/2000/xmlns/"
+#define NAMESPACE_XML "http://www.w3.org/XML/1998/namespace"
+#define NAMESPACE_XMLNS_DEFAULT_PREFIX "xmlns"
+#define NAMESPACE_XML_DEFAULT_PREFIX "xml"
+
#define PG_GETARG_XML_P(n) DatumGetXmlP(PG_GETARG_DATUM(n))
#define PG_RETURN_XML_P(x) PG_RETURN_POINTER(x)
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index bcc743f48518..0be740611b0e 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -225,6 +225,260 @@ SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'br' as fun
(1 row)
+-- DEFAULT NULL xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT NULL));
+ xmlelement
+------------
+
+(1 row)
+
+-- DEFAULT xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1'));
+ xmlelement
+-------------------------------
+
+(1 row)
+
+-- DEFAULT numeric xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 42.73));
+ xmlelement
+-----------------------
+
+(1 row)
+
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT ''));
+ xmlelement
+------------------
+
+(1 row)
+
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT));
+ xmlelement
+------------------
+
+(1 row)
+
+-- Testing xmlnamespace with subqueries
+SELECT
+ xmlelement(NAME root, xmlnamespaces(DEFAULT 'ns'),
+ (SELECT xmlelement(NAME child1, xmlnamespaces(NO DEFAULT))));
+ xmlelement
+--------------------------------------------
+
+(1 row)
+
+-- Testing xmlnamespace url from ColumnRef
+CREATE TABLE xmlns (url text);
+INSERT INTO xmlns VALUES ('http:/x.y/ns1');
+SELECT
+ xmlserialize(DOCUMENT
+ xmlelement(NAME root, xmlnamespaces(DEFAULT 'foo', url AS ns),
+ xmlelement(NAME root,
+ xmlelement(NAME child2, xmlnamespaces(url AS ns, NO DEFAULT))))
+ AS text INDENT)
+FROM xmlns;
+ xmlserialize
+-------------------------------------------------
+ +
+ +
+ +
+ +
+
+(1 row)
+
+-- NULL xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces(NULL AS ns));
+ xmlelement
+------------
+
+(1 row)
+
+-- empty xmlelement containing one namespace
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1));
+ xmlelement
+-----------------------------------
+
+(1 row)
+
+-- empty xmlelement with DEFAULT and regular xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', 'http:/x.y/ns2' AS ns2));
+ xmlelement
+---------------------------------------------------------
+
+(1 row)
+
+-- xmlelement containing a namespace and a text node
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), 'text node');
+ xmlelement
+--------------------------------------------------
+ text node
+(1 row)
+
+-- empty xmlelement containing a) xmlnamespace and b) xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlattributes('val' AS att));
+ xmlelement
+---------------------------------------------
+
+(1 row)
+
+-- empty xmlelement containing a) xmlattribute and b) xmlnamespace
+SELECT xmlelement(NAME "root", xmlattributes('val' AS att), xmlnamespaces('http:/x.y/ns1' AS ns1));
+ xmlelement
+---------------------------------------------
+
+(1 row)
+
+-- empty xmlelement containing two xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2));
+ xmlelement
+-------------------------------------------------------------
+
+(1 row)
+
+-- empty xmlelement containing two xmlnamespaces and one xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att));
+ xmlelement
+-----------------------------------------------------------------------
+
+(1 row)
+
+-- xmlelement containing two xmlnamespaces, one xmlattribute,
+-- and a text node.
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att), 'text node');
+ xmlelement
+--------------------------------------------------------------------------------------
+ text node
+(1 row)
+
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- empty xmlelement child "ns1:foo" containing one xmlnamespace and one
+-- xmlelement child (ns2:bar).
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "ns1:foo",
+ xmlnamespaces('http:/x.y/ns2' AS ns2),
+ xmlelement(NAME "ns2:bar", 'text node'))
+ );
+ xmlelement
+----------------------------------------------------------------------------------------------------------------------------
+ text node
+(1 row)
+
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- xmlelement child "ns1:foo" containing one xmlnamespace, one xmlelement
+-- child (ns2:bar), and a text node.
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "ns1:foo",
+ xmlnamespaces('http:/x.y/ns2' AS ns2),
+ xmlelement(NAME "ns2:bar", 'text node'),
+ 'mixed content')
+ );
+ xmlelement
+-----------------------------------------------------------------------------------------------------------------------------------------
+ text nodemixed content
+(1 row)
+
+-- empty root xmlelement containing one DEFAULT xmlnamespace, one xmlattribute,
+-- and one xmlelement child (foo).
+-- xmlelement child "foo" containing one NO DEFAULT xmlnamespace and a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces(DEFAULT 'http:/x.y/ns1'),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "foo",
+ xmlnamespaces(NO DEFAULT),'bar')
+ );
+ xmlelement
+----------------------------------------------------------------------
+ bar
+(1 row)
+
+-- empty root xmlelement containing one xmlattribute, one xmlnamespace,
+-- three child nodes generated by xmlforest and xmltext, one xmlcomment,
+-- and a text node generated by xmlconcat.
+SELECT
+ xmlelement(NAME "root",
+ xmlattributes(73 AS att),
+ xmlnamespaces('http:/x.y/ns1' AS ns),
+ xmlforest(true AS "ns:x", 42 AS "ns:y", xmltext('<&>') AS "ns:z"),
+ xmlcomment(':)'),
+ xmlconcat('foo', 'bar')
+ );
+ xmlelement
+--------------------------------------------------------------------------------------------------------------------------
+ true42<&>foobar
+(1 row)
+
+-- test xmlnamespaces within views
+CREATE VIEW view_xmlnamespaces AS
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1, DEFAULT 'http:/x.y/def'), xmlattributes('val' AS att),
+ xmlelement(NAME "child1", xmlnamespaces('http:/x.y/ns2' AS ns2, NO DEFAULT)),
+ xmlcomment(':)'),
+ xmlconcat('foo', 'bar'),
+ xmlelement(NAME "child2", xmlnamespaces(DEFAULT NULL))) AS xmldoc;
+SELECT * FROM view_xmlnamespaces;
+ xmldoc
+---------------------------------------------------------------------------------------------------------------------------------------------
+ foobar
+(1 row)
+
+\sv view_xmlnamespaces
+CREATE OR REPLACE VIEW public.view_xmlnamespaces AS
+ SELECT XMLELEMENT(NAME root, XMLATTRIBUTES('val' AS att), XMLNAMESPACES('http:/x.y/ns1' AS ns1, DEFAULT 'http:/x.y/def'), XMLELEMENT(NAME child1, XMLNAMESPACES('http:/x.y/ns2' AS ns2, DEFAULT '')), xmlcomment(':)'::text), XMLCONCAT('foo'::xml, 'bar'::xml), XMLELEMENT(NAME child2, XMLNAMESPACES(DEFAULT NULL::unknown))) AS xmldoc
+\set VERBOSITY terse
+-- duplicate xmlnamespace entry (ns1)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns1' AS ns1));
+ERROR: XML namespace name "ns1" appears more than once at character 70
+-- invalid xmlnamespace syntax
+SELECT xmlelement(NAME "root", xmlnamespaces('invalid'));
+ERROR: syntax error at or near ")" at character 55
+-- multiple DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', DEFAULT 'http:/x.y/ns2'));
+ERROR: XML elements can have only a single [NO] DEFAULT namespace at character 71
+-- multiple NO DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT, NO DEFAULT));
+ERROR: XML elements can have only a single [NO] DEFAULT namespace at character 58
+-- invalid xmlnamespace prefix (xmlns)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xmlns));
+ERROR: invalid XML namespace prefix "xmlns" at character 46
+-- invalid xmlnamespace prefix (xml)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xml));
+ERROR: invalid XML namespace prefix "xml" at character 46
+-- duplicate xmlnamespace calls
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlnamespaces('http:/x.y/ns2' AS ns2));
+ERROR: duplicate XMLNAMESACES specified at character 71
+\set VERBOSITY default
+-- invalid xmlnamespaces URIs
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/2000/xmlns/' AS bar));
+ERROR: invalid XML namespace URI "http://www.w3.org/2000/xmlns/"
+DETAIL: this URI is already bounded to standard a namespace prefix
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/XML/1998/namespace' AS bar));
+ERROR: invalid XML namespace URI "http://www.w3.org/XML/1998/namespace"
+DETAIL: this URI is already bounded to standard a namespace prefix
+-- invalid DEFAULT xmlnamespace URIs
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/2000/xmlns/'));
+ERROR: invalid XML namespace URI "http://www.w3.org/2000/xmlns/"
+DETAIL: this URI is already bounded to standard a namespace prefix
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/XML/1998/namespace'));
+ERROR: invalid XML namespace URI "http://www.w3.org/XML/1998/namespace"
+DETAIL: this URI is already bounded to standard a namespace prefix
+-- empty xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces('' AS ns));
+ERROR: invalid XML namespace URI for "ns"
+DETAIL: a regular XML namespace cannot be a zero-length string
SELECT xmlparse(content '');
xmlparse
----------
@@ -1402,6 +1656,11 @@ SELECT * FROM XMLTABLE(XMLNAMESPACES(DEFAULT 'http://x.y'),
PASSING '10
'
COLUMNS a int PATH 'a');
ERROR: DEFAULT namespace is not supported
+SELECT * FROM XMLTABLE(XMLNAMESPACES(NO DEFAULT),
+ '/rows/row'
+ PASSING '10
'
+ COLUMNS a int PATH 'a');
+ERROR: NO DEFAULT namespace is not supported
SELECT * FROM XMLTABLE('.'
PASSING ''
COLUMNS a text PATH 'foo/namespace::node()');
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index a1c5d314171f..7ee88371db57 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -150,6 +150,195 @@ DETAIL: This functionality requires the server to be built with libxml support.
SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'br' as funnier));
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
+-- DEFAULT NULL xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT NULL));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- DEFAULT xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1'));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- DEFAULT numeric xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 42.73));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT ''));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- Testing xmlnamespace with subqueries
+SELECT
+ xmlelement(NAME root, xmlnamespaces(DEFAULT 'ns'),
+ (SELECT xmlelement(NAME child1, xmlnamespaces(NO DEFAULT))));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- Testing xmlnamespace url from ColumnRef
+CREATE TABLE xmlns (url text);
+INSERT INTO xmlns VALUES ('http:/x.y/ns1');
+SELECT
+ xmlserialize(DOCUMENT
+ xmlelement(NAME root, xmlnamespaces(DEFAULT 'foo', url AS ns),
+ xmlelement(NAME root,
+ xmlelement(NAME child2, xmlnamespaces(url AS ns, NO DEFAULT))))
+ AS text INDENT)
+FROM xmlns;
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- NULL xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces(NULL AS ns));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing one namespace
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty xmlelement with DEFAULT and regular xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', 'http:/x.y/ns2' AS ns2));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- xmlelement containing a namespace and a text node
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), 'text node');
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing a) xmlnamespace and b) xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlattributes('val' AS att));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing a) xmlattribute and b) xmlnamespace
+SELECT xmlelement(NAME "root", xmlattributes('val' AS att), xmlnamespaces('http:/x.y/ns1' AS ns1));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing two xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing two xmlnamespaces and one xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- xmlelement containing two xmlnamespaces, one xmlattribute,
+-- and a text node.
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att), 'text node');
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- empty xmlelement child "ns1:foo" containing one xmlnamespace and one
+-- xmlelement child (ns2:bar).
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "ns1:foo",
+ xmlnamespaces('http:/x.y/ns2' AS ns2),
+ xmlelement(NAME "ns2:bar", 'text node'))
+ );
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- xmlelement child "ns1:foo" containing one xmlnamespace, one xmlelement
+-- child (ns2:bar), and a text node.
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "ns1:foo",
+ xmlnamespaces('http:/x.y/ns2' AS ns2),
+ xmlelement(NAME "ns2:bar", 'text node'),
+ 'mixed content')
+ );
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty root xmlelement containing one DEFAULT xmlnamespace, one xmlattribute,
+-- and one xmlelement child (foo).
+-- xmlelement child "foo" containing one NO DEFAULT xmlnamespace and a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces(DEFAULT 'http:/x.y/ns1'),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "foo",
+ xmlnamespaces(NO DEFAULT),'bar')
+ );
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty root xmlelement containing one xmlattribute, one xmlnamespace,
+-- three child nodes generated by xmlforest and xmltext, one xmlcomment,
+-- and a text node generated by xmlconcat.
+SELECT
+ xmlelement(NAME "root",
+ xmlattributes(73 AS att),
+ xmlnamespaces('http:/x.y/ns1' AS ns),
+ xmlforest(true AS "ns:x", 42 AS "ns:y", xmltext('<&>') AS "ns:z"),
+ xmlcomment(':)'),
+ xmlconcat('foo', 'bar')
+ );
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- test xmlnamespaces within views
+CREATE VIEW view_xmlnamespaces AS
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1, DEFAULT 'http:/x.y/def'), xmlattributes('val' AS att),
+ xmlelement(NAME "child1", xmlnamespaces('http:/x.y/ns2' AS ns2, NO DEFAULT)),
+ xmlcomment(':)'),
+ xmlconcat('foo', 'bar'),
+ xmlelement(NAME "child2", xmlnamespaces(DEFAULT NULL))) AS xmldoc;
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+SELECT * FROM view_xmlnamespaces;
+ERROR: relation "view_xmlnamespaces" does not exist
+LINE 1: SELECT * FROM view_xmlnamespaces;
+ ^
+\sv view_xmlnamespaces
+ERROR: relation "view_xmlnamespaces" does not exist
+\set VERBOSITY terse
+-- duplicate xmlnamespace entry (ns1)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns1' AS ns1));
+ERROR: unsupported XML feature
+-- invalid xmlnamespace syntax
+SELECT xmlelement(NAME "root", xmlnamespaces('invalid'));
+ERROR: syntax error at or near ")" at character 55
+-- multiple DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', DEFAULT 'http:/x.y/ns2'));
+ERROR: unsupported XML feature
+-- multiple NO DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT, NO DEFAULT));
+ERROR: unsupported XML feature
+-- invalid xmlnamespace prefix (xmlns)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xmlns));
+ERROR: unsupported XML feature
+-- invalid xmlnamespace prefix (xml)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xml));
+ERROR: unsupported XML feature
+-- duplicate xmlnamespace calls
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlnamespaces('http:/x.y/ns2' AS ns2));
+ERROR: duplicate XMLNAMESACES specified at character 71
+\set VERBOSITY default
+-- invalid xmlnamespaces URIs
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/2000/xmlns/' AS bar));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/XML/1998/namespace' AS bar));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- invalid DEFAULT xmlnamespace URIs
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/2000/xmlns/'));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/XML/1998/namespace'));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
+-- empty xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces('' AS ns));
+ERROR: unsupported XML feature
+DETAIL: This functionality requires the server to be built with libxml support.
SELECT xmlparse(content '');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
@@ -1078,6 +1267,14 @@ ERROR: unsupported XML feature
LINE 3: PASSING '10
'
+ COLUMNS a int PATH 'a');
+ERROR: unsupported XML feature
+LINE 3: PASSING ''
COLUMNS a text PATH 'foo/namespace::node()');
diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out
index 045641dae649..279dc5999e5f 100644
--- a/src/test/regress/expected/xml_2.out
+++ b/src/test/regress/expected/xml_2.out
@@ -221,6 +221,260 @@ SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'br' as fun
(1 row)
+-- DEFAULT NULL xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT NULL));
+ xmlelement
+------------
+
+(1 row)
+
+-- DEFAULT xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1'));
+ xmlelement
+-------------------------------
+
+(1 row)
+
+-- DEFAULT numeric xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 42.73));
+ xmlelement
+-----------------------
+
+(1 row)
+
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT ''));
+ xmlelement
+------------------
+
+(1 row)
+
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT));
+ xmlelement
+------------------
+
+(1 row)
+
+-- Testing xmlnamespace with subqueries
+SELECT
+ xmlelement(NAME root, xmlnamespaces(DEFAULT 'ns'),
+ (SELECT xmlelement(NAME child1, xmlnamespaces(NO DEFAULT))));
+ xmlelement
+--------------------------------------------
+
+(1 row)
+
+-- Testing xmlnamespace url from ColumnRef
+CREATE TABLE xmlns (url text);
+INSERT INTO xmlns VALUES ('http:/x.y/ns1');
+SELECT
+ xmlserialize(DOCUMENT
+ xmlelement(NAME root, xmlnamespaces(DEFAULT 'foo', url AS ns),
+ xmlelement(NAME root,
+ xmlelement(NAME child2, xmlnamespaces(url AS ns, NO DEFAULT))))
+ AS text INDENT)
+FROM xmlns;
+ xmlserialize
+-------------------------------------------------
+ +
+ +
+ +
+ +
+
+(1 row)
+
+-- NULL xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces(NULL AS ns));
+ xmlelement
+------------
+
+(1 row)
+
+-- empty xmlelement containing one namespace
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1));
+ xmlelement
+-----------------------------------
+
+(1 row)
+
+-- empty xmlelement with DEFAULT and regular xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', 'http:/x.y/ns2' AS ns2));
+ xmlelement
+---------------------------------------------------------
+
+(1 row)
+
+-- xmlelement containing a namespace and a text node
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), 'text node');
+ xmlelement
+--------------------------------------------------
+ text node
+(1 row)
+
+-- empty xmlelement containing a) xmlnamespace and b) xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlattributes('val' AS att));
+ xmlelement
+---------------------------------------------
+
+(1 row)
+
+-- empty xmlelement containing a) xmlattribute and b) xmlnamespace
+SELECT xmlelement(NAME "root", xmlattributes('val' AS att), xmlnamespaces('http:/x.y/ns1' AS ns1));
+ xmlelement
+---------------------------------------------
+
+(1 row)
+
+-- empty xmlelement containing two xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2));
+ xmlelement
+-------------------------------------------------------------
+
+(1 row)
+
+-- empty xmlelement containing two xmlnamespaces and one xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att));
+ xmlelement
+-----------------------------------------------------------------------
+
+(1 row)
+
+-- xmlelement containing two xmlnamespaces, one xmlattribute,
+-- and a text node.
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att), 'text node');
+ xmlelement
+--------------------------------------------------------------------------------------
+ text node
+(1 row)
+
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- empty xmlelement child "ns1:foo" containing one xmlnamespace and one
+-- xmlelement child (ns2:bar).
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "ns1:foo",
+ xmlnamespaces('http:/x.y/ns2' AS ns2),
+ xmlelement(NAME "ns2:bar", 'text node'))
+ );
+ xmlelement
+----------------------------------------------------------------------------------------------------------------------------
+ text node
+(1 row)
+
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- xmlelement child "ns1:foo" containing one xmlnamespace, one xmlelement
+-- child (ns2:bar), and a text node.
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "ns1:foo",
+ xmlnamespaces('http:/x.y/ns2' AS ns2),
+ xmlelement(NAME "ns2:bar", 'text node'),
+ 'mixed content')
+ );
+ xmlelement
+-----------------------------------------------------------------------------------------------------------------------------------------
+ text nodemixed content
+(1 row)
+
+-- empty root xmlelement containing one DEFAULT xmlnamespace, one xmlattribute,
+-- and one xmlelement child (foo).
+-- xmlelement child "foo" containing one NO DEFAULT xmlnamespace and a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces(DEFAULT 'http:/x.y/ns1'),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "foo",
+ xmlnamespaces(NO DEFAULT),'bar')
+ );
+ xmlelement
+----------------------------------------------------------------------
+ bar
+(1 row)
+
+-- empty root xmlelement containing one xmlattribute, one xmlnamespace,
+-- three child nodes generated by xmlforest and xmltext, one xmlcomment,
+-- and a text node generated by xmlconcat.
+SELECT
+ xmlelement(NAME "root",
+ xmlattributes(73 AS att),
+ xmlnamespaces('http:/x.y/ns1' AS ns),
+ xmlforest(true AS "ns:x", 42 AS "ns:y", xmltext('<&>') AS "ns:z"),
+ xmlcomment(':)'),
+ xmlconcat('foo', 'bar')
+ );
+ xmlelement
+--------------------------------------------------------------------------------------------------------------------------
+ true42<&>foobar
+(1 row)
+
+-- test xmlnamespaces within views
+CREATE VIEW view_xmlnamespaces AS
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1, DEFAULT 'http:/x.y/def'), xmlattributes('val' AS att),
+ xmlelement(NAME "child1", xmlnamespaces('http:/x.y/ns2' AS ns2, NO DEFAULT)),
+ xmlcomment(':)'),
+ xmlconcat('foo', 'bar'),
+ xmlelement(NAME "child2", xmlnamespaces(DEFAULT NULL))) AS xmldoc;
+SELECT * FROM view_xmlnamespaces;
+ xmldoc
+---------------------------------------------------------------------------------------------------------------------------------------------
+ foobar
+(1 row)
+
+\sv view_xmlnamespaces
+CREATE OR REPLACE VIEW public.view_xmlnamespaces AS
+ SELECT XMLELEMENT(NAME root, XMLATTRIBUTES('val' AS att), XMLNAMESPACES('http:/x.y/ns1' AS ns1, DEFAULT 'http:/x.y/def'), XMLELEMENT(NAME child1, XMLNAMESPACES('http:/x.y/ns2' AS ns2, DEFAULT '')), xmlcomment(':)'::text), XMLCONCAT('foo'::xml, 'bar'::xml), XMLELEMENT(NAME child2, XMLNAMESPACES(DEFAULT NULL::unknown))) AS xmldoc
+\set VERBOSITY terse
+-- duplicate xmlnamespace entry (ns1)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns1' AS ns1));
+ERROR: XML namespace name "ns1" appears more than once at character 70
+-- invalid xmlnamespace syntax
+SELECT xmlelement(NAME "root", xmlnamespaces('invalid'));
+ERROR: syntax error at or near ")" at character 55
+-- multiple DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', DEFAULT 'http:/x.y/ns2'));
+ERROR: XML elements can have only a single [NO] DEFAULT namespace at character 71
+-- multiple NO DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT, NO DEFAULT));
+ERROR: XML elements can have only a single [NO] DEFAULT namespace at character 58
+-- invalid xmlnamespace prefix (xmlns)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xmlns));
+ERROR: invalid XML namespace prefix "xmlns" at character 46
+-- invalid xmlnamespace prefix (xml)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xml));
+ERROR: invalid XML namespace prefix "xml" at character 46
+-- duplicate xmlnamespace calls
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlnamespaces('http:/x.y/ns2' AS ns2));
+ERROR: duplicate XMLNAMESACES specified at character 71
+\set VERBOSITY default
+-- invalid xmlnamespaces URIs
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/2000/xmlns/' AS bar));
+ERROR: invalid XML namespace URI "http://www.w3.org/2000/xmlns/"
+DETAIL: this URI is already bounded to standard a namespace prefix
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/XML/1998/namespace' AS bar));
+ERROR: invalid XML namespace URI "http://www.w3.org/XML/1998/namespace"
+DETAIL: this URI is already bounded to standard a namespace prefix
+-- invalid DEFAULT xmlnamespace URIs
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/2000/xmlns/'));
+ERROR: invalid XML namespace URI "http://www.w3.org/2000/xmlns/"
+DETAIL: this URI is already bounded to standard a namespace prefix
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/XML/1998/namespace'));
+ERROR: invalid XML namespace URI "http://www.w3.org/XML/1998/namespace"
+DETAIL: this URI is already bounded to standard a namespace prefix
+-- empty xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces('' AS ns));
+ERROR: invalid XML namespace URI for "ns"
+DETAIL: a regular XML namespace cannot be a zero-length string
SELECT xmlparse(content '');
xmlparse
----------
@@ -1388,6 +1642,11 @@ SELECT * FROM XMLTABLE(XMLNAMESPACES(DEFAULT 'http://x.y'),
PASSING '10
'
COLUMNS a int PATH 'a');
ERROR: DEFAULT namespace is not supported
+SELECT * FROM XMLTABLE(XMLNAMESPACES(NO DEFAULT),
+ '/rows/row'
+ PASSING '10
'
+ COLUMNS a int PATH 'a');
+ERROR: NO DEFAULT namespace is not supported
SELECT * FROM XMLTABLE('.'
PASSING ''
COLUMNS a text PATH 'foo/namespace::node()');
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index 4c3520ce8980..4072bdff3d05 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -66,6 +66,134 @@ SELECT xmlelement(name foo, xmlattributes('2009-04-09 00:24:37'::timestamp as ba
SELECT xmlelement(name foo, xmlattributes('infinity'::timestamp as bar));
SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'br' as funnier));
+-- DEFAULT NULL xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT NULL));
+-- DEFAULT xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1'));
+-- DEFAULT numeric xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 42.73));
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT ''));
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT));
+-- Testing xmlnamespace with subqueries
+SELECT
+ xmlelement(NAME root, xmlnamespaces(DEFAULT 'ns'),
+ (SELECT xmlelement(NAME child1, xmlnamespaces(NO DEFAULT))));
+-- Testing xmlnamespace url from ColumnRef
+CREATE TABLE xmlns (url text);
+INSERT INTO xmlns VALUES ('http:/x.y/ns1');
+SELECT
+ xmlserialize(DOCUMENT
+ xmlelement(NAME root, xmlnamespaces(DEFAULT 'foo', url AS ns),
+ xmlelement(NAME root,
+ xmlelement(NAME child2, xmlnamespaces(url AS ns, NO DEFAULT))))
+ AS text INDENT)
+FROM xmlns;
+-- NULL xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces(NULL AS ns));
+-- empty xmlelement containing one namespace
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1));
+-- empty xmlelement with DEFAULT and regular xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', 'http:/x.y/ns2' AS ns2));
+-- xmlelement containing a namespace and a text node
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), 'text node');
+-- empty xmlelement containing a) xmlnamespace and b) xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlattributes('val' AS att));
+-- empty xmlelement containing a) xmlattribute and b) xmlnamespace
+SELECT xmlelement(NAME "root", xmlattributes('val' AS att), xmlnamespaces('http:/x.y/ns1' AS ns1));
+-- empty xmlelement containing two xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2));
+-- empty xmlelement containing two xmlnamespaces and one xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att));
+-- xmlelement containing two xmlnamespaces, one xmlattribute,
+-- and a text node.
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att), 'text node');
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- empty xmlelement child "ns1:foo" containing one xmlnamespace and one
+-- xmlelement child (ns2:bar).
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "ns1:foo",
+ xmlnamespaces('http:/x.y/ns2' AS ns2),
+ xmlelement(NAME "ns2:bar", 'text node'))
+ );
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- xmlelement child "ns1:foo" containing one xmlnamespace, one xmlelement
+-- child (ns2:bar), and a text node.
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "ns1:foo",
+ xmlnamespaces('http:/x.y/ns2' AS ns2),
+ xmlelement(NAME "ns2:bar", 'text node'),
+ 'mixed content')
+ );
+-- empty root xmlelement containing one DEFAULT xmlnamespace, one xmlattribute,
+-- and one xmlelement child (foo).
+-- xmlelement child "foo" containing one NO DEFAULT xmlnamespace and a text node.
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces(DEFAULT 'http:/x.y/ns1'),
+ xmlattributes('val' AS att),
+ xmlelement(NAME "foo",
+ xmlnamespaces(NO DEFAULT),'bar')
+ );
+-- empty root xmlelement containing one xmlattribute, one xmlnamespace,
+-- three child nodes generated by xmlforest and xmltext, one xmlcomment,
+-- and a text node generated by xmlconcat.
+SELECT
+ xmlelement(NAME "root",
+ xmlattributes(73 AS att),
+ xmlnamespaces('http:/x.y/ns1' AS ns),
+ xmlforest(true AS "ns:x", 42 AS "ns:y", xmltext('<&>') AS "ns:z"),
+ xmlcomment(':)'),
+ xmlconcat('foo', 'bar')
+ );
+-- test xmlnamespaces within views
+CREATE VIEW view_xmlnamespaces AS
+SELECT
+ xmlelement(NAME "root",
+ xmlnamespaces('http:/x.y/ns1' AS ns1, DEFAULT 'http:/x.y/def'), xmlattributes('val' AS att),
+ xmlelement(NAME "child1", xmlnamespaces('http:/x.y/ns2' AS ns2, NO DEFAULT)),
+ xmlcomment(':)'),
+ xmlconcat('foo', 'bar'),
+ xmlelement(NAME "child2", xmlnamespaces(DEFAULT NULL))) AS xmldoc;
+SELECT * FROM view_xmlnamespaces;
+\sv view_xmlnamespaces
+
+\set VERBOSITY terse
+-- duplicate xmlnamespace entry (ns1)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns1' AS ns1));
+-- invalid xmlnamespace syntax
+SELECT xmlelement(NAME "root", xmlnamespaces('invalid'));
+-- multiple DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', DEFAULT 'http:/x.y/ns2'));
+-- multiple NO DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT, NO DEFAULT));
+-- invalid xmlnamespace prefix (xmlns)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xmlns));
+-- invalid xmlnamespace prefix (xml)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xml));
+-- duplicate xmlnamespace calls
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlnamespaces('http:/x.y/ns2' AS ns2));
+\set VERBOSITY default
+-- invalid xmlnamespaces URIs
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/2000/xmlns/' AS bar));
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/XML/1998/namespace' AS bar));
+-- invalid DEFAULT xmlnamespace URIs
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/2000/xmlns/'));
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/XML/1998/namespace'));
+-- empty xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces('' AS ns));
+
SELECT xmlparse(content '');
SELECT xmlparse(content ' ');
@@ -455,6 +583,11 @@ SELECT * FROM XMLTABLE(XMLNAMESPACES(DEFAULT 'http://x.y'),
PASSING '10
'
COLUMNS a int PATH 'a');
+SELECT * FROM XMLTABLE(XMLNAMESPACES(NO DEFAULT),
+ '/rows/row'
+ PASSING '10
'
+ COLUMNS a int PATH 'a');
+
SELECT * FROM XMLTABLE('.'
PASSING ''
COLUMNS a text PATH 'foo/namespace::node()');