]> granicus.if.org Git - postgresql/blobdiff - src/backend/optimizer/util/clauses.c
Change the planner-to-executor API so that the planner tells the executor
[postgresql] / src / backend / optimizer / util / clauses.c
index 4da9f47dec5ba6e2872fe317771d010b525128bc..4858f985cffe2eb0f1f061a866aba3d7a996c37a 100644 (file)
@@ -3,12 +3,12 @@
  * clauses.c
  *       routines to manipulate qualification clauses
  *
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.212 2006/06/16 18:42:22 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.229 2007/01/10 18:06:04 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -19,7 +19,6 @@
 
 #include "postgres.h"
 
-#include "access/heapam.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_operator.h"
@@ -398,17 +397,27 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
        if (IsA(node, Aggref))
        {
                Aggref     *aggref = (Aggref *) node;
-               Oid                     inputType;
+               Oid                *inputTypes;
+               int                     numArguments;
                HeapTuple       aggTuple;
                Form_pg_aggregate aggform;
                Oid                     aggtranstype;
+               int                     i;
+               ListCell   *l;
 
                Assert(aggref->agglevelsup == 0);
                counts->numAggs++;
                if (aggref->aggdistinct)
                        counts->numDistinctAggs++;
 
-               inputType = exprType((Node *) aggref->target);
+               /* extract argument types */
+               numArguments = list_length(aggref->args);
+               inputTypes = (Oid *) palloc(sizeof(Oid) * numArguments);
+               i = 0;
+               foreach(l, aggref->args)
+               {
+                       inputTypes[i++] = exprType((Node *) lfirst(l));
+               }
 
                /* fetch aggregate transition datatype from pg_aggregate */
                aggTuple = SearchSysCache(AGGFNOID,
@@ -424,17 +433,18 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
                /* resolve actual type of transition state, if polymorphic */
                if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
                {
-                       /* have to fetch the agg's declared input type... */
-                       Oid                *agg_arg_types;
+                       /* have to fetch the agg's declared input types... */
+                       Oid                *declaredArgTypes;
                        int                     agg_nargs;
 
                        (void) get_func_signature(aggref->aggfnoid,
-                                                                         &agg_arg_types, &agg_nargs);
-                       Assert(agg_nargs == 1);
-                       aggtranstype = resolve_generic_type(aggtranstype,
-                                                                                               inputType,
-                                                                                               agg_arg_types[0]);
-                       pfree(agg_arg_types);
+                                                                         &declaredArgTypes, &agg_nargs);
+                       Assert(agg_nargs == numArguments);
+                       aggtranstype = enforce_generic_type_consistency(inputTypes,
+                                                                                                                       declaredArgTypes,
+                                                                                                                       agg_nargs,
+                                                                                                                       aggtranstype);
+                       pfree(declaredArgTypes);
                }
 
                /*
@@ -449,12 +459,12 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
                        int32           avgwidth;
 
                        /*
-                        * If transition state is of same type as input, assume it's the
-                        * same typmod (same width) as well.  This works for cases like
-                        * MAX/MIN and is probably somewhat reasonable otherwise.
+                        * If transition state is of same type as first input, assume it's
+                        * the same typmod (same width) as well.  This works for cases
+                        * like MAX/MIN and is probably somewhat reasonable otherwise.
                         */
-                       if (aggtranstype == inputType)
-                               aggtranstypmod = exprTypmod((Node *) aggref->target);
+                       if (numArguments > 0 && aggtranstype == inputTypes[0])
+                               aggtranstypmod = exprTypmod((Node *) linitial(aggref->args));
                        else
                                aggtranstypmod = -1;
 
@@ -465,10 +475,10 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
                }
 
                /*
-                * Complain if the aggregate's argument contains any aggregates;
+                * Complain if the aggregate's arguments contain any aggregates;
                 * nested agg functions are semantically nonsensical.
                 */
-               if (contain_agg_clause((Node *) aggref->target))
+               if (contain_agg_clause((Node *) aggref->args))
                        ereport(ERROR,
                                        (errcode(ERRCODE_GROUPING_ERROR),
                                         errmsg("aggregate function calls may not be nested")));
@@ -547,6 +557,8 @@ expression_returns_set_walker(Node *node, void *context)
                return false;
        if (IsA(node, MinMaxExpr))
                return false;
+       if (IsA(node, XmlExpr))
+               return false;
        if (IsA(node, NullIfExpr))
                return false;
 
@@ -860,6 +872,8 @@ contain_nonstrict_functions_walker(Node *node, void *context)
                return true;
        if (IsA(node, MinMaxExpr))
                return true;
+       if (IsA(node, XmlExpr))
+               return true;
        if (IsA(node, NullIfExpr))
                return true;
        if (IsA(node, NullTest))
@@ -877,7 +891,7 @@ contain_nonstrict_functions_walker(Node *node, void *context)
  *
  * Returns the set of all Relids that are referenced in the clause in such
  * a way that the clause cannot possibly return TRUE if any of these Relids
- * is an all-NULL row.  (It is OK to err on the side of conservatism; hence
+ * is an all-NULL row. (It is OK to err on the side of conservatism; hence
  * the analysis here is simplistic.)
  *
  * The semantics here are subtly different from contain_nonstrict_functions:
@@ -1010,7 +1024,7 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
 static bool
 is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK)
 {
-       Node   *rightop;
+       Node       *rightop;
 
        /* The contained operator must be strict. */
        if (!op_strict(expr->opno))
@@ -1052,14 +1066,13 @@ is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK)
 
 /*
  * is_pseudo_constant_clause
- *       Detect whether a clause is "constant", ie, it contains no variables
- *       of the current query level and no uses of volatile functions.
- *       Such a clause is not necessarily a true constant: it can still contain
+ *       Detect whether an expression is "pseudo constant", ie, it contains no
+ *       variables of the current query level and no uses of volatile functions.
+ *       Such an expr is not necessarily a true constant: it can still contain
  *       Params and outer-level Vars, not to mention functions whose results
- *       may vary from one statement to the next.      However, the clause's value
+ *       may vary from one statement to the next.      However, the expr's value
  *       will be constant over any one scan of the current query, so it can be
- *       used as an indexscan key or (if a top-level qual) can be pushed up to
- *       become a gating qual.
+ *       used as, eg, an indexscan key.
  */
 bool
 is_pseudo_constant_clause(Node *clause)
@@ -1079,7 +1092,7 @@ is_pseudo_constant_clause(Node *clause)
 /*
  * is_pseudo_constant_clause_relids
  *       Same as above, except caller already has available the var membership
- *       of the clause; this lets us avoid the contain_var_clause() scan.
+ *       of the expression; this lets us avoid the contain_var_clause() scan.
  */
 bool
 is_pseudo_constant_clause_relids(Node *clause, Relids relids)
@@ -1090,34 +1103,6 @@ is_pseudo_constant_clause_relids(Node *clause, Relids relids)
        return false;
 }
 
-/*
- * pull_constant_clauses
- *             Scan through a list of qualifications and separate "constant" quals
- *             from those that are not.
- *
- * Returns a list of the pseudo-constant clauses in constantQual and the
- * remaining quals as the return value.
- */
-List *
-pull_constant_clauses(List *quals, List **constantQual)
-{
-       List       *constqual = NIL,
-                          *restqual = NIL;
-       ListCell   *q;
-
-       foreach(q, quals)
-       {
-               Node       *qual = (Node *) lfirst(q);
-
-               if (is_pseudo_constant_clause(qual))
-                       constqual = lappend(constqual, qual);
-               else
-                       restqual = lappend(restqual, qual);
-       }
-       *constantQual = constqual;
-       return restqual;
-}
-
 
 /*****************************************************************************
  *             Tests on clauses of queries
@@ -1162,7 +1147,7 @@ has_distinct_on_clause(Query *query)
                                continue;               /* we can ignore unsorted junk cols */
                        return true;            /* definitely not in DISTINCT list */
                }
-               if (targetIsInSortList(tle, query->distinctClause))
+               if (targetIsInSortList(tle, InvalidOid, query->distinctClause))
                {
                        if (tle->resjunk)
                                return true;    /* junk TLE in DISTINCT means DISTINCT ON */
@@ -1173,7 +1158,7 @@ has_distinct_on_clause(Query *query)
                        /* This TLE is not in DISTINCT list */
                        if (!tle->resjunk)
                                return true;    /* non-junk, non-DISTINCT, so DISTINCT ON */
-                       if (targetIsInSortList(tle, query->sortClause))
+                       if (targetIsInSortList(tle, InvalidOid, query->sortClause))
                                return true;    /* sorted, non-distinct junk */
                        /* unsorted junk is okay, keep looking */
                }
@@ -1307,14 +1292,11 @@ CommuteRowCompareExpr(RowCompareExpr *clause)
        }
 
        clause->opnos = newops;
+
        /*
-        * Note: we don't bother to update the opclasses list, but just set
-        * it to empty.  This is OK since this routine is currently only used
-        * for index quals, and the index machinery won't use the opclass
-        * information.  The original opclass list is NOT valid if we have
-        * commuted any cross-type comparisons, so don't leave it in place.
+        * Note: we need not change the opfamilies list; we assume any btree
+        * opfamily containing an operator will also contain its commutator.
         */
-       clause->opclasses = NIL;        /* XXX */
 
        temp = clause->largs;
        clause->largs = clause->rargs;
@@ -1481,7 +1463,9 @@ eval_const_expressions(Node *node)
  *
  * Currently the extra steps that are taken in this mode are:
  * 1. Substitute values for Params, where a bound Param value has been made
- *       available by the caller of planner().
+ *       available by the caller of planner(), even if the Param isn't marked
+ *       constant.  This effectively means that we plan using the first supplied
+ *       value of the Param.
  * 2. Fold stable, as well as immutable, functions to constants.
  *--------------------
  */
@@ -1506,33 +1490,38 @@ eval_const_expressions_mutator(Node *node,
        {
                Param      *param = (Param *) node;
 
-               /* OK to try to substitute value? */
-               if (context->estimate && param->paramkind == PARAM_EXTERN &&
-                       PlannerBoundParamList != NULL)
+               /* Look to see if we've been given a value for this Param */
+               if (param->paramkind == PARAM_EXTERN &&
+                       PlannerBoundParamList != NULL &&
+                       param->paramid > 0 &&
+                       param->paramid <= PlannerBoundParamList->numParams)
                {
-                       /* Look to see if we've been given a value for this Param */
-                       if (param->paramid > 0 &&
-                               param->paramid <= PlannerBoundParamList->numParams)
-                       {
-                               ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1];
+                       ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1];
 
-                               if (OidIsValid(prm->ptype))
+                       if (OidIsValid(prm->ptype))
+                       {
+                               /* OK to substitute parameter value? */
+                               if (context->estimate || (prm->pflags & PARAM_FLAG_CONST))
                                {
                                        /*
-                                        * Found it, so return a Const representing the param
-                                        * value.  Note that we don't copy pass-by-ref datatypes,
-                                        * so the Const will only be valid as long as the bound
-                                        * parameter list exists.  This is okay for intended uses
-                                        * of estimate_expression_value().
+                                        * Return a Const representing the param value.  Must copy
+                                        * pass-by-ref datatypes, since the Param might be in a
+                                        * memory context shorter-lived than our output plan
+                                        * should be.
                                         */
                                        int16           typLen;
                                        bool            typByVal;
+                                       Datum           pval;
 
                                        Assert(prm->ptype == param->paramtype);
                                        get_typlenbyval(param->paramtype, &typLen, &typByVal);
+                                       if (prm->isnull || typByVal)
+                                               pval = prm->value;
+                                       else
+                                               pval = datumCopy(prm->value, typByVal, typLen);
                                        return (Node *) makeConst(param->paramtype,
                                                                                          (int) typLen,
-                                                                                         prm->value,
+                                                                                         pval,
                                                                                          prm->isnull,
                                                                                          typByVal);
                                }
@@ -2111,6 +2100,137 @@ eval_const_expressions_mutator(Node *node,
                newfselect->resulttypmod = fselect->resulttypmod;
                return (Node *) newfselect;
        }
+       if (IsA(node, NullTest))
+       {
+               NullTest   *ntest = (NullTest *) node;
+               NullTest   *newntest;
+               Node       *arg;
+
+               arg = eval_const_expressions_mutator((Node *) ntest->arg,
+                                                                                        context);
+               if (arg && IsA(arg, RowExpr))
+               {
+                       RowExpr    *rarg = (RowExpr *) arg;
+                       List       *newargs = NIL;
+                       ListCell   *l;
+
+                       /*
+                        * We break ROW(...) IS [NOT] NULL into separate tests on its
+                        * component fields.  This form is usually more efficient to
+                        * evaluate, as well as being more amenable to optimization.
+                        */
+                       foreach(l, rarg->args)
+                       {
+                               Node       *relem = (Node *) lfirst(l);
+
+                               /*
+                                * A constant field refutes the whole NullTest if it's of the
+                                * wrong nullness; else we can discard it.
+                                */
+                               if (relem && IsA(relem, Const))
+                               {
+                                       Const      *carg = (Const *) relem;
+
+                                       if (carg->constisnull ?
+                                               (ntest->nulltesttype == IS_NOT_NULL) :
+                                               (ntest->nulltesttype == IS_NULL))
+                                               return makeBoolConst(false, false);
+                                       continue;
+                               }
+                               newntest = makeNode(NullTest);
+                               newntest->arg = (Expr *) relem;
+                               newntest->nulltesttype = ntest->nulltesttype;
+                               newargs = lappend(newargs, newntest);
+                       }
+                       /* If all the inputs were constants, result is TRUE */
+                       if (newargs == NIL)
+                               return makeBoolConst(true, false);
+                       /* If only one nonconst input, it's the result */
+                       if (list_length(newargs) == 1)
+                               return (Node *) linitial(newargs);
+                       /* Else we need an AND node */
+                       return (Node *) make_andclause(newargs);
+               }
+               if (arg && IsA(arg, Const))
+               {
+                       Const      *carg = (Const *) arg;
+                       bool            result;
+
+                       switch (ntest->nulltesttype)
+                       {
+                               case IS_NULL:
+                                       result = carg->constisnull;
+                                       break;
+                               case IS_NOT_NULL:
+                                       result = !carg->constisnull;
+                                       break;
+                               default:
+                                       elog(ERROR, "unrecognized nulltesttype: %d",
+                                                (int) ntest->nulltesttype);
+                                       result = false;         /* keep compiler quiet */
+                                       break;
+                       }
+
+                       return makeBoolConst(result, false);
+               }
+
+               newntest = makeNode(NullTest);
+               newntest->arg = (Expr *) arg;
+               newntest->nulltesttype = ntest->nulltesttype;
+               return (Node *) newntest;
+       }
+       if (IsA(node, BooleanTest))
+       {
+               BooleanTest *btest = (BooleanTest *) node;
+               BooleanTest *newbtest;
+               Node       *arg;
+
+               arg = eval_const_expressions_mutator((Node *) btest->arg,
+                                                                                        context);
+               if (arg && IsA(arg, Const))
+               {
+                       Const      *carg = (Const *) arg;
+                       bool            result;
+
+                       switch (btest->booltesttype)
+                       {
+                               case IS_TRUE:
+                                       result = (!carg->constisnull &&
+                                                         DatumGetBool(carg->constvalue));
+                                       break;
+                               case IS_NOT_TRUE:
+                                       result = (carg->constisnull ||
+                                                         !DatumGetBool(carg->constvalue));
+                                       break;
+                               case IS_FALSE:
+                                       result = (!carg->constisnull &&
+                                                         !DatumGetBool(carg->constvalue));
+                                       break;
+                               case IS_NOT_FALSE:
+                                       result = (carg->constisnull ||
+                                                         DatumGetBool(carg->constvalue));
+                                       break;
+                               case IS_UNKNOWN:
+                                       result = carg->constisnull;
+                                       break;
+                               case IS_NOT_UNKNOWN:
+                                       result = !carg->constisnull;
+                                       break;
+                               default:
+                                       elog(ERROR, "unrecognized booltesttype: %d",
+                                                (int) btest->booltesttype);
+                                       result = false;         /* keep compiler quiet */
+                                       break;
+                       }
+
+                       return makeBoolConst(result, false);
+               }
+
+               newbtest = makeNode(BooleanTest);
+               newbtest->arg = (Expr *) arg;
+               newbtest->booltesttype = btest->booltesttype;
+               return (Node *) newbtest;
+       }
 
        /*
         * For any node type not handled above, we recurse using
@@ -2656,7 +2776,6 @@ inline_function(Oid funcid, Oid result_type, List *args,
         */
        if (!IsA(querytree, Query) ||
                querytree->commandType != CMD_SELECT ||
-               querytree->resultRelation != 0 ||
                querytree->into ||
                querytree->hasAggs ||
                querytree->hasSubLinks ||
@@ -2984,10 +3103,9 @@ evaluate_expr(Expr *expr, Oid result_type)
  * stage.  In particular, it handles List nodes since a cnf-ified qual clause
  * will have List structure at the top level, and it handles TargetEntry nodes
  * so that a scan of a target list can be handled without additional code.
- * (But only the "expr" part of a TargetEntry is examined, unless the walker
- * chooses to process TargetEntry nodes specially.)  Also, RangeTblRef,
- * FromExpr, JoinExpr, and SetOperationStmt nodes are handled, so that query
- * jointrees and setOperation trees can be processed without additional code.
+ * Also, RangeTblRef, FromExpr, JoinExpr, and SetOperationStmt nodes are
+ * handled, so that query jointrees and setOperation trees can be processed
+ * without additional code.
  *
  * expression_tree_walker will handle SubLink nodes by recursing normally
  * into the "testexpr" subtree (which is an expression belonging to the outer
@@ -3056,7 +3174,15 @@ expression_tree_walker(Node *node,
                        /* primitive node types with no expression subnodes */
                        break;
                case T_Aggref:
-                       return walker(((Aggref *) node)->target, context);
+                       {
+                               Aggref     *expr = (Aggref *) node;
+
+                               /* recurse directly on List */
+                               if (expression_tree_walker((Node *) expr->args,
+                                                                                  walker, context))
+                                       return true;
+                       }
+                       break;
                case T_ArrayRef:
                        {
                                ArrayRef   *aref = (ArrayRef *) node;
@@ -3124,8 +3250,7 @@ expression_tree_walker(Node *node,
                        {
                                SubLink    *sublink = (SubLink *) node;
 
-                               if (expression_tree_walker(sublink->testexpr,
-                                                                                  walker, context))
+                               if (walker(sublink->testexpr, context))
                                        return true;
 
                                /*
@@ -3140,8 +3265,7 @@ expression_tree_walker(Node *node,
                                SubPlan    *subplan = (SubPlan *) node;
 
                                /* recurse into the testexpr, but not into the Plan */
-                               if (expression_tree_walker(subplan->testexpr,
-                                                                                  walker, context))
+                               if (walker(subplan->testexpr, context))
                                        return true;
                                /* also examine args list */
                                if (expression_tree_walker((Node *) subplan->args,
@@ -3204,6 +3328,17 @@ expression_tree_walker(Node *node,
                        return walker(((CoalesceExpr *) node)->args, context);
                case T_MinMaxExpr:
                        return walker(((MinMaxExpr *) node)->args, context);
+               case T_XmlExpr:
+                       {
+                               XmlExpr *xexpr = (XmlExpr *) node;
+                               
+                               if (walker(xexpr->named_args, context))
+                                       return true;
+                               /* we assume walker doesn't care about arg_names */
+                               if (walker(xexpr->args, context))
+                                       return true;
+                       }
+                       break;
                case T_NullIfExpr:
                        return walker(((NullIfExpr *) node)->args, context);
                case T_NullTest:
@@ -3311,6 +3446,8 @@ query_tree_walker(Query *query,
 
        if (walker((Node *) query->targetList, context))
                return true;
+       if (walker((Node *) query->returningList, context))
+               return true;
        if (walker((Node *) query->jointree, context))
                return true;
        if (walker(query->setOperations, context))
@@ -3323,6 +3460,38 @@ query_tree_walker(Query *query,
                return true;
        if (range_table_walker(query->rtable, walker, context, flags))
                return true;
+       if (query->utilityStmt)
+       {
+               /*
+                * Certain utility commands contain general-purpose Querys embedded in
+                * them --- if this is one, invoke the walker on the sub-Query.
+                */
+               if (IsA(query->utilityStmt, CopyStmt))
+               {
+                       if (walker(((CopyStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+               if (IsA(query->utilityStmt, DeclareCursorStmt))
+               {
+                       if (walker(((DeclareCursorStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+               if (IsA(query->utilityStmt, ExplainStmt))
+               {
+                       if (walker(((ExplainStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+               if (IsA(query->utilityStmt, PrepareStmt))
+               {
+                       if (walker(((PrepareStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+               if (IsA(query->utilityStmt, ViewStmt))
+               {
+                       if (walker(((ViewStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+       }
        return false;
 }
 
@@ -3363,6 +3532,10 @@ range_table_walker(List *rtable,
                                if (walker(rte->funcexpr, context))
                                        return true;
                                break;
+                       case RTE_VALUES:
+                               if (walker(rte->values_lists, context))
+                                       return true;
+                               break;
                }
        }
        return false;
@@ -3478,7 +3651,7 @@ expression_tree_mutator(Node *node,
                                Aggref     *newnode;
 
                                FLATCOPY(newnode, aggref, Aggref);
-                               MUTATE(newnode->target, aggref->target, Expr *);
+                               MUTATE(newnode->args, aggref->args, List *);
                                return (Node *) newnode;
                        }
                        break;
@@ -3666,8 +3839,8 @@ expression_tree_mutator(Node *node,
                        break;
                case T_RowCompareExpr:
                        {
-                               RowCompareExpr    *rcexpr = (RowCompareExpr *) node;
-                               RowCompareExpr    *newnode;
+                               RowCompareExpr *rcexpr = (RowCompareExpr *) node;
+                               RowCompareExpr *newnode;
 
                                FLATCOPY(newnode, rcexpr, RowCompareExpr);
                                MUTATE(newnode->largs, rcexpr->largs, List *);
@@ -3695,6 +3868,18 @@ expression_tree_mutator(Node *node,
                                return (Node *) newnode;
                        }
                        break;
+               case T_XmlExpr:
+                       {
+                               XmlExpr *xexpr = (XmlExpr *) node;
+                               XmlExpr *newnode;
+
+                               FLATCOPY(newnode, xexpr, XmlExpr);
+                               MUTATE(newnode->named_args, xexpr->named_args, List *);
+                               /* assume mutator does not care about arg_names */
+                               MUTATE(newnode->args, xexpr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
                case T_NullIfExpr:
                        {
                                NullIfExpr *expr = (NullIfExpr *) node;
@@ -3810,6 +3995,7 @@ expression_tree_mutator(Node *node,
 
                                FLATCOPY(newnode, ininfo, InClauseInfo);
                                MUTATE(newnode->sub_targetlist, ininfo->sub_targetlist, List *);
+                               /* Assume we need not make a copy of in_operators list */
                                return (Node *) newnode;
                        }
                        break;
@@ -3869,6 +4055,7 @@ query_tree_mutator(Query *query,
        }
 
        MUTATE(query->targetList, query->targetList, List *);
+       MUTATE(query->returningList, query->returningList, List *);
        MUTATE(query->jointree, query->jointree, FromExpr *);
        MUTATE(query->setOperations, query->setOperations, Node *);
        MUTATE(query->havingQual, query->havingQual, Node *);
@@ -3929,6 +4116,9 @@ range_table_mutator(List *rtable,
                        case RTE_FUNCTION:
                                MUTATE(newrte->funcexpr, rte->funcexpr, Node *);
                                break;
+                       case RTE_VALUES:
+                               MUTATE(newrte->values_lists, rte->values_lists, List *);
+                               break;
                }
                newrt = lappend(newrt, newrte);
        }