aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2018-09-17 13:16:32 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2018-09-17 13:16:32 -0400
commita552e3bc502ee679b0b8ff19e69b7b69890c0613 (patch)
tree5245c36facf5d07cb286f7fb1dcbd8e9d63c7900
parent3ea7e015f37afd615234d94181840b8e6e44e6ed (diff)
downloadpostgresql-a552e3bc502ee679b0b8ff19e69b7b69890c0613.tar.gz
postgresql-a552e3bc502ee679b0b8ff19e69b7b69890c0613.zip
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
-rw-r--r--src/backend/executor/nodeTableFuncscan.c6
-rw-r--r--src/backend/parser/parse_clause.c15
-rw-r--r--src/backend/utils/adt/ruleutils.c6
-rw-r--r--src/include/nodes/execnodes.h4
-rw-r--r--src/include/nodes/primnodes.h7
5 files changed, 23 insertions, 15 deletions
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index 7b749f6e927..5bbbc20b1cc 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -370,8 +370,9 @@ tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
forboth(lc1, tstate->ns_uris, lc2, tstate->ns_names)
{
ExprState *expr = (ExprState *) lfirst(lc1);
- char *ns_name = strVal(lfirst(lc2));
+ Value *ns_node = (Value *) lfirst(lc2);
char *ns_uri;
+ char *ns_name;
value = ExecEvalExpr((ExprState *) expr, econtext, &isnull);
if (isnull)
@@ -380,6 +381,9 @@ tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
errmsg("namespace URI must not be null")));
ns_uri = TextDatumGetCString(value);
+ /* DEFAULT is passed down to SetNamespace as NULL */
+ ns_name = ns_node ? strVal(ns_node) : NULL;
+
routine->SetNamespace(tstate, ns_name, ns_uri);
}
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index ed26517c266..14ba4270dab 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -772,7 +772,7 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
/* undef ordinality column number */
tf->ordinalitycol = -1;
-
+ /* Process column specs */
names = palloc(sizeof(char *) * list_length(rtf->columns));
colno = 0;
@@ -893,15 +893,15 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
{
foreach(lc2, ns_names)
{
- char *name = strVal(lfirst(lc2));
+ Value *ns_node = (Value *) lfirst(lc2);
- if (name == NULL)
+ if (ns_node == NULL)
continue;
- if (strcmp(name, r->name) == 0)
+ if (strcmp(strVal(ns_node), r->name) == 0)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("namespace name \"%s\" is not unique",
- name),
+ r->name),
parser_errposition(pstate, r->location)));
}
}
@@ -915,8 +915,9 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
default_ns_seen = true;
}
- /* Note the string may be NULL */
- ns_names = lappend(ns_names, makeString(r->name));
+ /* We represent DEFAULT by a null pointer */
+ ns_names = lappend(ns_names,
+ r->name ? makeString(r->name) : NULL);
}
tf->ns_uris = ns_uris;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 4c9a49cd6d8..da07fbd7251 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9618,17 +9618,17 @@ get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
{
Node *expr = (Node *) lfirst(lc1);
- char *name = strVal(lfirst(lc2));
+ Value *ns_node = (Value *) lfirst(lc2);
if (!first)
appendStringInfoString(buf, ", ");
else
first = false;
- if (name != NULL)
+ if (ns_node != NULL)
{
get_rule_expr(expr, context, showimplicit);
- appendStringInfo(buf, " AS %s", name);
+ appendStringInfo(buf, " AS %s", strVal(ns_node));
}
else
{
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 78d276bf884..b2490779c21 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1476,8 +1476,8 @@ typedef struct TableFuncScanState
ExprState *rowexpr; /* state for row-generating expression */
List *colexprs; /* state for column-generating expression */
List *coldefexprs; /* state for column default expressions */
- List *ns_names; /* list of str nodes with namespace names */
- List *ns_uris; /* list of states of namespace uri exprs */
+ List *ns_names; /* same as TableFunc.ns_names */
+ List *ns_uris; /* list of states of namespace URI exprs */
Bitmapset *notnulls; /* nullability flag for each output column */
void *opaque; /* table builder private space */
const struct TableFuncRoutine *routine; /* table builder methods */
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 8c536a8d38d..02288c84124 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -75,12 +75,15 @@ typedef struct RangeVar
/*
* TableFunc - node for a table function, such as XMLTABLE.
+ *
+ * Entries in the ns_names list are either string Value nodes containing
+ * literal namespace names, or NULL pointers to represent DEFAULT.
*/
typedef struct TableFunc
{
NodeTag type;
- List *ns_uris; /* list of namespace uri */
- List *ns_names; /* list of namespace names */
+ List *ns_uris; /* list of namespace URI expressions */
+ List *ns_names; /* list of namespace names or NULL */
Node *docexpr; /* input document expression */
Node *rowexpr; /* row filter expression */
List *colnames; /* column names (list of String) */