]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix parsetree representation of XMLTABLE(XMLNAMESPACES(DEFAULT ...)).
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 Sep 2018 17:16:32 +0000 (13:16 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 Sep 2018 17:16:32 +0000 (13:16 -0400)
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

src/backend/executor/nodeTableFuncscan.c
src/backend/parser/parse_clause.c
src/backend/utils/adt/ruleutils.c
src/include/nodes/execnodes.h
src/include/nodes/primnodes.h

index 7b749f6e927f047b5a1befe8476d2dc1dd0ecbe5..5bbbc20b1cc71133509b33be3c0ac16c64aa9d53 100644 (file)
@@ -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);
        }
 
index ed26517c26631568ef484dadc607cf2884a37a6b..14ba4270dab3c9947d0740d3777fa796b58d0d96 100644 (file)
@@ -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;
index 4c9a49cd6d8b16f9b738d10c5d5762275f448d5d..da07fbd72519e95c65de0baa553ad6a9fba0f672 100644 (file)
@@ -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
                        {
index 78d276bf88423cbb893b4f39bcdf32b764d26cfd..b2490779c2166662e7a6b9553f1d1024061077f8 100644 (file)
@@ -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 */
index 8c536a8d38d8c2fb811b4d481125d6be4c522a33..02288c841246b3ba729fb4b29821a15fa92a2b3b 100644 (file)
@@ -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) */