Skip to content

Commit 07a3af0

Browse files
committed
Fix parsetree representation of XMLTABLE(XMLNAMESPACES(DEFAULT ...)).
The original coding for XMLTABLE thought it could represent a default namespace by a T_String Value node with a null string pointer. That's not okay, though; in particular outfuncs.c/readfuncs.c are not on board with such a representation, meaning you'll get a null pointer crash if you try to store a view or rule containing this construct. To fix, change the parsetree representation so that we have a NULL list element, instead of a bogus Value node. This isn't really a functional limitation since default XML namespaces aren't yet implemented in the executor; you'd just get "DEFAULT namespace is not supported" anyway. But crashes are not nice, so back-patch to v10 where this syntax was added. Ordinarily we'd consider a parsetree representation change to be un-backpatchable; but since existing releases would crash on the way to storing such constructs, there can't be any existing views/rules to be incompatible with. Per report from Andrey Lepikhov. Discussion: https://postgr.es/m/3690074f-abd2-56a9-144a-aa5545d7a291@postgrespro.ru
1 parent 789ba50 commit 07a3af0

File tree

5 files changed

+23
-15
lines changed

5 files changed

+23
-15
lines changed

src/backend/executor/nodeTableFuncscan.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,9 @@ tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
364364
forboth(lc1, tstate->ns_uris, lc2, tstate->ns_names)
365365
{
366366
ExprState *expr = (ExprState *) lfirst(lc1);
367-
char *ns_name = strVal(lfirst(lc2));
367+
Value *ns_node = (Value *) lfirst(lc2);
368368
char *ns_uri;
369+
char *ns_name;
369370

370371
value = ExecEvalExpr((ExprState *) expr, econtext, &isnull);
371372
if (isnull)
@@ -374,6 +375,9 @@ tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
374375
errmsg("namespace URI must not be null")));
375376
ns_uri = TextDatumGetCString(value);
376377

378+
/* DEFAULT is passed down to SetNamespace as NULL */
379+
ns_name = ns_node ? strVal(ns_node) : NULL;
380+
377381
routine->SetNamespace(tstate, ns_name, ns_uri);
378382
}
379383

src/backend/parser/parse_clause.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,7 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
779779
/* undef ordinality column number */
780780
tf->ordinalitycol = -1;
781781

782-
782+
/* Process column specs */
783783
names = palloc(sizeof(char *) * list_length(rtf->columns));
784784

785785
colno = 0;
@@ -900,15 +900,15 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
900900
{
901901
foreach(lc2, ns_names)
902902
{
903-
char *name = strVal(lfirst(lc2));
903+
Value *ns_node = (Value *) lfirst(lc2);
904904

905-
if (name == NULL)
905+
if (ns_node == NULL)
906906
continue;
907-
if (strcmp(name, r->name) == 0)
907+
if (strcmp(strVal(ns_node), r->name) == 0)
908908
ereport(ERROR,
909909
(errcode(ERRCODE_SYNTAX_ERROR),
910910
errmsg("namespace name \"%s\" is not unique",
911-
name),
911+
r->name),
912912
parser_errposition(pstate, r->location)));
913913
}
914914
}
@@ -922,8 +922,9 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
922922
default_ns_seen = true;
923923
}
924924

925-
/* Note the string may be NULL */
926-
ns_names = lappend(ns_names, makeString(r->name));
925+
/* We represent DEFAULT by a null pointer */
926+
ns_names = lappend(ns_names,
927+
r->name ? makeString(r->name) : NULL);
927928
}
928929

929930
tf->ns_uris = ns_uris;

src/backend/utils/adt/ruleutils.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9739,17 +9739,17 @@ get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
97399739
forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
97409740
{
97419741
Node *expr = (Node *) lfirst(lc1);
9742-
char *name = strVal(lfirst(lc2));
9742+
Value *ns_node = (Value *) lfirst(lc2);
97439743

97449744
if (!first)
97459745
appendStringInfoString(buf, ", ");
97469746
else
97479747
first = false;
97489748

9749-
if (name != NULL)
9749+
if (ns_node != NULL)
97509750
{
97519751
get_rule_expr(expr, context, showimplicit);
9752-
appendStringInfo(buf, " AS %s", name);
9752+
appendStringInfo(buf, " AS %s", strVal(ns_node));
97539753
}
97549754
else
97559755
{

src/include/nodes/execnodes.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,8 +1573,8 @@ typedef struct TableFuncScanState
15731573
ExprState *rowexpr; /* state for row-generating expression */
15741574
List *colexprs; /* state for column-generating expression */
15751575
List *coldefexprs; /* state for column default expressions */
1576-
List *ns_names; /* list of str nodes with namespace names */
1577-
List *ns_uris; /* list of states of namespace uri exprs */
1576+
List *ns_names; /* same as TableFunc.ns_names */
1577+
List *ns_uris; /* list of states of namespace URI exprs */
15781578
Bitmapset *notnulls; /* nullability flag for each output column */
15791579
void *opaque; /* table builder private space */
15801580
const struct TableFuncRoutine *routine; /* table builder methods */

src/include/nodes/primnodes.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,15 @@ typedef struct RangeVar
7575

7676
/*
7777
* TableFunc - node for a table function, such as XMLTABLE.
78+
*
79+
* Entries in the ns_names list are either string Value nodes containing
80+
* literal namespace names, or NULL pointers to represent DEFAULT.
7881
*/
7982
typedef struct TableFunc
8083
{
8184
NodeTag type;
82-
List *ns_uris; /* list of namespace uri */
83-
List *ns_names; /* list of namespace names */
85+
List *ns_uris; /* list of namespace URI expressions */
86+
List *ns_names; /* list of namespace names or NULL */
8487
Node *docexpr; /* input document expression */
8588
Node *rowexpr; /* row filter expression */
8689
List *colnames; /* column names (list of String) */

0 commit comments

Comments
 (0)