Skip to content

Commit 9712de4

Browse files
author
Commitfest Bot
committed
[CF 5456] v8 - Add XMLNamespaces option to XMLElement
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5456 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/1b63f25a-276a-41b7-9284-260826afd906@uni-muenster.de Author(s): Pavel Stehule, Jim Jones
2 parents ea06263 + 97177c6 commit 9712de4

File tree

12 files changed

+1202
-34
lines changed

12 files changed

+1202
-34
lines changed

doc/src/sgml/func.sgml

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14730,7 +14730,10 @@ SELECT xmlconcat('<?xml version="1.1"?><foo/>', '<?xml version="1.1" standalone=
1473014730
</indexterm>
1473114731

1473214732
<synopsis>
14733-
<function>xmlelement</function> ( <literal>NAME</literal> <replaceable>name</replaceable> <optional>, <literal>XMLATTRIBUTES</literal> ( <replaceable>attvalue</replaceable> <optional> <literal>AS</literal> <replaceable>attname</replaceable> </optional> <optional>, ...</optional> ) </optional> <optional>, <replaceable>content</replaceable> <optional>, ...</optional></optional> ) <returnvalue>xml</returnvalue>
14733+
<function>xmlelement</function> ( <literal>NAME</literal> <replaceable>name</replaceable>
14734+
<optional>, <literal>XMLATTRIBUTES</literal> ( <replaceable>attvalue</replaceable> <optional> <literal>AS</literal> <replaceable>attname</replaceable> </optional> <optional>, ...</optional> ) </optional>
14735+
<optional>, <literal>XMLNAMESPACES</literal> ( {<replaceable>regular-nsuri</replaceable> <literal>AS</literal> <replaceable>nsprefix</replaceable> | DEFAULT <replaceable>default-nsuri</replaceable> | NO DEFAULT} <optional>, ...</optional> ) </optional>
14736+
<optional>, <replaceable>content</replaceable> <optional>, ...</optional></optional> ) <returnvalue>xml</returnvalue>
1473414737
</synopsis>
1473514738

1473614739
<para>
@@ -14743,7 +14746,39 @@ SELECT xmlconcat('<?xml version="1.1"?><foo/>', '<?xml version="1.1" standalone=
1474314746
yield any <productname>PostgreSQL</productname> data type. The
1474414747
argument(s) within <literal>XMLATTRIBUTES</literal> generate attributes
1474514748
of the XML element; the <replaceable>content</replaceable> value(s) are
14746-
concatenated to form its content.
14749+
concatenated to form its content. The arguments within <literal>XMLNAMESPACES</literal>
14750+
constuct namespace declarations from values provided in <replaceable>nsuri</replaceable>
14751+
and <replaceable>nsprefix</replaceable>, which correspond to the URI of a namespace and
14752+
its prefix, respectively. The option <literal>DEFAULT</literal> can be used to set the
14753+
default namespace declaration (without a prefix) to the URI provided in <replaceable>default-nsuri</replaceable>.
14754+
The option <literal>NO DEFAULT</literal> states that a namespace scope has no default namespace. A valid
14755+
<literal>XMLNAMESPACES</literal> item must fulfill the following conditions:
14756+
14757+
<itemizedlist>
14758+
<listitem>
14759+
<para>
14760+
Only a single <literal>DEFAULT</literal> declaration item within the same scope.
14761+
</para>
14762+
</listitem>
14763+
<listitem>
14764+
<para>
14765+
No two <replaceable>nsuri</replaceable> can be equal within the same scope.
14766+
</para>
14767+
</listitem>
14768+
<listitem>
14769+
<para>
14770+
No <replaceable>nsprefix</replaceable> can be equal to <literal>xml</literal> or <literal>xmlns</literal>,
14771+
and no <replaceable>nsuri</replaceable> can be equal to <literal>http://www.w3.org/2000/xmlns/</literal>
14772+
or to <literal>http://www.w3.org/XML/1998/namespace</literal>, as they are already bouned to standard XML declarations.
14773+
</para>
14774+
</listitem>
14775+
<listitem>
14776+
<para>
14777+
The value of a <replaceable>regular-nsuri</replaceable> cannot be a zero-length string.
14778+
</para>
14779+
</listitem>
14780+
</itemizedlist>
14781+
1474714782
</para>
1474814783

1474914784
<para>
@@ -14766,6 +14801,24 @@ SELECT xmlelement(name foo, xmlattributes(current_date as bar), 'cont', 'ent');
1476614801
xmlelement
1476714802
-------------------------------------
1476814803
<foo bar="2007-01-26">content</foo>
14804+
14805+
SELECT xmlelement(NAME "foo:root", xmlnamespaces('http:/foo.bar/' AS foo), 'content');
14806+
14807+
xmlelement
14808+
---------------------------------------------------------
14809+
<foo:root xmlns:foo="http:/foo.bar/">content</foo:root>
14810+
14811+
SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/foo.bar/'), 'content');
14812+
14813+
xmlelement
14814+
---------------------------------------------
14815+
<root xmlns="http:/foo.bar/">content</root>
14816+
14817+
SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT), 'content');
14818+
14819+
xmlelement
14820+
-------------------------------
14821+
<root xmlns="">content</root>
1476914822
]]></screen>
1477014823
</para>
1477114824

src/backend/parser/gram.y

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ typedef struct KeyActions
136136
KeyAction *deleteAction;
137137
} KeyActions;
138138

139+
typedef struct XmlElementOpts
140+
{
141+
List *xml_attributes;
142+
List *xml_namespaces;
143+
} XmlElementOpts;
144+
139145
/* ConstraintAttributeSpec yields an integer bitmask of these flags: */
140146
#define CAS_NOT_DEFERRABLE 0x01
141147
#define CAS_DEFERRABLE 0x02
@@ -186,7 +192,7 @@ static Node *makeNotExpr(Node *expr, int location);
186192
static Node *makeAArrayExpr(List *elements, int location, int end_location);
187193
static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod,
188194
int location);
189-
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
195+
static Node *makeXmlExpr(XmlExprOp op, char *name, XmlElementOpts *opts,
190196
List *args, int location);
191197
static List *mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner);
192198
static TypeName *TableFuncTypeName(List *columns);
@@ -266,6 +272,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
266272
MergeWhenClause *mergewhen;
267273
struct KeyActions *keyactions;
268274
struct KeyAction *keyaction;
275+
struct XmlElementOpts *xmlelementopts;
269276
ReturningClause *retclause;
270277
ReturningOptionKind retoptionkind;
271278
}
@@ -617,8 +624,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
617624
%type <list> xmltable_column_list xmltable_column_option_list
618625
%type <node> xmltable_column_el
619626
%type <defelt> xmltable_column_option_el
620-
%type <list> xml_namespace_list
627+
%type <list> xml_namespace_list xml_namespaces
621628
%type <target> xml_namespace_el
629+
%type <xmlelementopts> xmlelement_opts
622630

623631
%type <node> func_application func_expr_common_subexpr
624632
%type <node> func_expr func_expr_windowless
@@ -14292,6 +14300,15 @@ xml_namespace_el:
1429214300
$$->val = $2;
1429314301
$$->location = @1;
1429414302
}
14303+
| NO DEFAULT
14304+
{
14305+
$$ = makeNode(ResTarget);
14306+
$$->name = NULL;
14307+
$$->indirection = NIL;
14308+
$$->val = NULL;
14309+
$$->location = @1;
14310+
}
14311+
1429514312
;
1429614313

1429714314
json_table:
@@ -15346,12 +15363,12 @@ a_expr: c_expr { $$ = $1; }
1534615363
}
1534715364
| a_expr IS DOCUMENT_P %prec IS
1534815365
{
15349-
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
15366+
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NULL,
1535015367
list_make1($1), @2);
1535115368
}
1535215369
| a_expr IS NOT DOCUMENT_P %prec IS
1535315370
{
15354-
$$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL,
15371+
$$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NULL,
1535515372
list_make1($1), @2),
1535615373
@2);
1535715374
}
@@ -15493,12 +15510,12 @@ b_expr: c_expr
1549315510
}
1549415511
| b_expr IS DOCUMENT_P %prec IS
1549515512
{
15496-
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
15513+
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NULL,
1549715514
list_make1($1), @2);
1549815515
}
1549915516
| b_expr IS NOT DOCUMENT_P %prec IS
1550015517
{
15501-
$$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL,
15518+
$$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NULL,
1550215519
list_make1($1), @2),
1550315520
@2);
1550415521
}
@@ -16033,21 +16050,21 @@ func_expr_common_subexpr:
1603316050
}
1603416051
| XMLCONCAT '(' expr_list ')'
1603516052
{
16036-
$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
16053+
$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NULL, $3, @1);
1603716054
}
1603816055
| XMLELEMENT '(' NAME_P ColLabel ')'
1603916056
{
16040-
$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
16057+
$$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, NIL, @1);
1604116058
}
16042-
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
16059+
| XMLELEMENT '(' NAME_P ColLabel ',' xmlelement_opts ')'
1604316060
{
1604416061
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
1604516062
}
1604616063
| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
1604716064
{
16048-
$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
16065+
$$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, $6, @1);
1604916066
}
16050-
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
16067+
| XMLELEMENT '(' NAME_P ColLabel ',' xmlelement_opts ',' expr_list ')'
1605116068
{
1605216069
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
1605316070
}
@@ -16062,12 +16079,17 @@ func_expr_common_subexpr:
1606216079
}
1606316080
| XMLFOREST '(' xml_attribute_list ')'
1606416081
{
16065-
$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
16082+
XmlElementOpts opts;
16083+
16084+
opts.xml_attributes = $3;
16085+
opts.xml_namespaces = NIL;
16086+
16087+
$$ = makeXmlExpr(IS_XMLFOREST, NULL, &opts, NIL, @1);
1606616088
}
1606716089
| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
1606816090
{
1606916091
XmlExpr *x = (XmlExpr *)
16070-
makeXmlExpr(IS_XMLPARSE, NULL, NIL,
16092+
makeXmlExpr(IS_XMLPARSE, NULL, NULL,
1607116093
list_make2($4, makeBoolAConst($5, -1)),
1607216094
@1);
1607316095

@@ -16084,7 +16106,7 @@ func_expr_common_subexpr:
1608416106
}
1608516107
| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
1608616108
{
16087-
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
16109+
$$ = makeXmlExpr(IS_XMLROOT, NULL, NULL,
1608816110
list_make3($3, $5, $6), @1);
1608916111
}
1609016112
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename xml_indent_option ')'
@@ -16288,6 +16310,9 @@ opt_xml_root_standalone: ',' STANDALONE_P YES_P
1628816310
xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
1628916311
;
1629016312

16313+
xml_namespaces: XMLNAMESPACES '(' xml_namespace_list ')' { $$ = $3; }
16314+
;
16315+
1629116316
xml_attribute_list: xml_attribute_el { $$ = list_make1($1); }
1629216317
| xml_attribute_list ',' xml_attribute_el { $$ = lappend($1, $3); }
1629316318
;
@@ -16324,6 +16349,44 @@ xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = true; }
1632416349
| /*EMPTY*/ { $$ = false; }
1632516350
;
1632616351

16352+
xmlelement_opts: xml_attributes
16353+
{
16354+
XmlElementOpts *n = palloc(sizeof(XmlElementOpts));
16355+
16356+
n->xml_attributes = $1;
16357+
n->xml_namespaces = NIL;
16358+
$$ = n;
16359+
}
16360+
| xml_namespaces
16361+
{
16362+
XmlElementOpts *n = palloc(sizeof(XmlElementOpts));
16363+
16364+
n->xml_attributes = NIL;
16365+
n->xml_namespaces = $1;
16366+
$$ = n;
16367+
}
16368+
| xmlelement_opts ',' xml_attributes
16369+
{
16370+
if ($$->xml_attributes)
16371+
ereport(ERROR,
16372+
(errcode(ERRCODE_DUPLICATE_OBJECT),
16373+
errmsg("duplicate XMLATTRIBUTES specified"),
16374+
parser_errposition(@3)));
16375+
16376+
$$->xml_attributes = $3;
16377+
}
16378+
| xmlelement_opts ',' xml_namespaces
16379+
{
16380+
if ($$->xml_namespaces)
16381+
ereport(ERROR,
16382+
(errcode(ERRCODE_DUPLICATE_OBJECT),
16383+
errmsg("duplicate XMLNAMESACES specified"),
16384+
parser_errposition(@3)));
16385+
16386+
$$->xml_namespaces = $3;
16387+
}
16388+
;
16389+
1632716390
/* We allow several variants for SQL and other compatibility. */
1632816391
xmlexists_argument:
1632916392
PASSING c_expr
@@ -19246,7 +19309,7 @@ makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location)
1924619309
}
1924719310

1924819311
static Node *
19249-
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
19312+
makeXmlExpr(XmlExprOp op, char *name, XmlElementOpts *opts, List *args,
1925019313
int location)
1925119314
{
1925219315
XmlExpr *x = makeNode(XmlExpr);
@@ -19258,7 +19321,12 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
1925819321
* named_args is a list of ResTarget; it'll be split apart into separate
1925919322
* expression and name lists in transformXmlExpr().
1926019323
*/
19261-
x->named_args = named_args;
19324+
if (opts)
19325+
{
19326+
x->named_args = opts->xml_attributes;
19327+
x->xmlnamespaces = opts->xml_namespaces;
19328+
}
19329+
1926219330
x->arg_names = NIL;
1926319331
x->args = args;
1926419332
/* xmloption, if relevant, must be filled in by caller */

src/backend/parser/parse_clause.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,12 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
842842
Node *ns_uri;
843843

844844
Assert(IsA(r, ResTarget));
845-
ns_uri = transformExpr(pstate, r->val, EXPR_KIND_FROM_FUNCTION);
845+
/* Create an empty String for NO DEFAULT namespaces */
846+
if (!r->name && !r->val)
847+
ns_uri = transformExpr(pstate, makeStringConst("", r->location), EXPR_KIND_FROM_FUNCTION);
848+
else
849+
ns_uri = transformExpr(pstate, r->val, EXPR_KIND_FROM_FUNCTION);
850+
846851
ns_uri = coerce_to_specific_type(pstate, ns_uri,
847852
TEXTOID, constructName);
848853
assign_expr_collations(pstate, ns_uri);

0 commit comments

Comments
 (0)