]> granicus.if.org Git - postgresql/blobdiff - src/backend/optimizer/plan/planner.c
Fix PARAM_EXEC assignment mechanism to be safe in the presence of WITH.
[postgresql] / src / backend / optimizer / plan / planner.c
index 07301c77fbf4f2550367ea8ff58c685462835223..385e64647ea0dea00c15889064421a01ad2dab79 100644 (file)
@@ -3,7 +3,7 @@
  * planner.c
  *       The query optimizer external interface.
  *
- * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
 
 #include <limits.h>
 
-#include "catalog/pg_operator.h"
+#include "access/htup_details.h"
 #include "executor/executor.h"
 #include "executor/nodeAgg.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#ifdef OPTIMIZER_DEBUG
+#include "nodes/print.h"
+#endif
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/prep.h"
 #include "optimizer/subselect.h"
 #include "optimizer/tlist.h"
-#include "optimizer/var.h"
-#ifdef OPTIMIZER_DEBUG
-#include "nodes/print.h"
-#endif
 #include "parser/analyze.h"
-#include "parser/parse_expr.h"
-#include "parser/parse_oper.h"
 #include "parser/parsetree.h"
-#include "utils/lsyscache.h"
-#include "utils/syscache.h"
+#include "rewrite/rewriteManip.h"
+#include "utils/rel.h"
 
 
 /* GUC parameter */
@@ -52,19 +49,21 @@ planner_hook_type planner_hook = NULL;
 
 
 /* Expression kind codes for preprocess_expression */
-#define EXPRKIND_QUAL          0
-#define EXPRKIND_TARGET                1
-#define EXPRKIND_RTFUNC                2
-#define EXPRKIND_VALUES                3
-#define EXPRKIND_LIMIT         4
-#define EXPRKIND_APPINFO       5
+#define EXPRKIND_QUAL                  0
+#define EXPRKIND_TARGET                        1
+#define EXPRKIND_RTFUNC                        2
+#define EXPRKIND_RTFUNC_LATERAL        3
+#define EXPRKIND_VALUES                        4
+#define EXPRKIND_VALUES_LATERAL        5
+#define EXPRKIND_LIMIT                 6
+#define EXPRKIND_APPINFO               7
+#define EXPRKIND_PHV                   8
 
 
 static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
 static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode);
 static Plan *inheritance_planner(PlannerInfo *root);
 static Plan *grouping_planner(PlannerInfo *root, double tuple_fraction);
-static bool is_dummy_plan(Plan *plan);
 static void preprocess_rowmarks(PlannerInfo *root);
 static double preprocess_limit(PlannerInfo *root,
                                 double tuple_fraction,
@@ -74,7 +73,7 @@ static bool choose_hashed_grouping(PlannerInfo *root,
                                           double tuple_fraction, double limit_tuples,
                                           double path_rows, int path_width,
                                           Path *cheapest_path, Path *sorted_path,
-                                          double dNumGroups, AggClauseCounts *agg_counts);
+                                          double dNumGroups, AggClauseCosts *agg_costs);
 static bool choose_hashed_distinct(PlannerInfo *root,
                                           double tuple_fraction, double limit_tuples,
                                           double path_rows, int path_width,
@@ -84,6 +83,7 @@ static bool choose_hashed_distinct(PlannerInfo *root,
                                           double dNumDistinctRows);
 static List *make_subplanTargetList(PlannerInfo *root, List *tlist,
                                           AttrNumber **groupColIdx, bool *need_tlist_eval);
+static int     get_grouping_column_index(Query *parse, TargetEntry *tle);
 static void locate_grouping_columns(PlannerInfo *root,
                                                List *tlist,
                                                List *sub_tlist,
@@ -139,8 +139,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        PlannerInfo *root;
        Plan       *top_plan;
        ListCell   *lp,
-                          *lrt,
-                          *lrm;
+                          *lr;
 
        /* Cursor options may come from caller or from DECLARE CURSOR stmt */
        if (parse->utilityStmt &&
@@ -156,16 +155,17 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        glob = makeNode(PlannerGlobal);
 
        glob->boundParams = boundParams;
-       glob->paramlist = NIL;
        glob->subplans = NIL;
-       glob->subrtables = NIL;
-       glob->subrowmarks = NIL;
+       glob->subroots = NIL;
        glob->rewindPlanIDs = NULL;
        glob->finalrtable = NIL;
        glob->finalrowmarks = NIL;
+       glob->resultRelations = NIL;
        glob->relationOids = NIL;
        glob->invalItems = NIL;
+       glob->nParamExec = 0;
        glob->lastPHId = 0;
+       glob->lastRowMarkId = 0;
        glob->transientPlan = false;
 
        /* Determine what fraction of the plan is likely to be scanned */
@@ -213,44 +213,37 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        /* final cleanup of the plan */
        Assert(glob->finalrtable == NIL);
        Assert(glob->finalrowmarks == NIL);
-       top_plan = set_plan_references(glob, top_plan,
-                                                                  root->parse->rtable,
-                                                                  root->rowMarks);
+       Assert(glob->resultRelations == NIL);
+       top_plan = set_plan_references(root, top_plan);
        /* ... and the subplans (both regular subplans and initplans) */
-       Assert(list_length(glob->subplans) == list_length(glob->subrtables));
-       Assert(list_length(glob->subplans) == list_length(glob->subrowmarks));
-       lrt = list_head(glob->subrtables);
-       lrm = list_head(glob->subrowmarks);
-       foreach(lp, glob->subplans)
+       Assert(list_length(glob->subplans) == list_length(glob->subroots));
+       forboth(lp, glob->subplans, lr, glob->subroots)
        {
                Plan       *subplan = (Plan *) lfirst(lp);
-               List       *subrtable = (List *) lfirst(lrt);
-               List       *subrowmark = (List *) lfirst(lrm);
+               PlannerInfo *subroot = (PlannerInfo *) lfirst(lr);
 
-               lfirst(lp) = set_plan_references(glob, subplan,
-                                                                                subrtable, subrowmark);
-               lrt = lnext(lrt);
-               lrm = lnext(lrm);
+               lfirst(lp) = set_plan_references(subroot, subplan);
        }
 
        /* build the PlannedStmt result */
        result = makeNode(PlannedStmt);
 
        result->commandType = parse->commandType;
+       result->queryId = parse->queryId;
        result->hasReturning = (parse->returningList != NIL);
+       result->hasModifyingCTE = parse->hasModifyingCTE;
        result->canSetTag = parse->canSetTag;
        result->transientPlan = glob->transientPlan;
        result->planTree = top_plan;
        result->rtable = glob->finalrtable;
-       result->resultRelations = root->resultRelations;
+       result->resultRelations = glob->resultRelations;
        result->utilityStmt = parse->utilityStmt;
-       result->intoClause = parse->intoClause;
        result->subplans = glob->subplans;
        result->rewindPlanIDs = glob->rewindPlanIDs;
        result->rowMarks = glob->finalrowmarks;
        result->relationOids = glob->relationOids;
        result->invalItems = glob->invalItems;
-       result->nParamExec = list_length(glob->paramlist);
+       result->nParamExec = glob->nParamExec;
 
        return result;
 }
@@ -302,6 +295,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
        root->glob = glob;
        root->query_level = parent_root ? parent_root->query_level + 1 : 1;
        root->parent_root = parent_root;
+       root->plan_params = NIL;
        root->planner_cxt = CurrentMemoryContext;
        root->init_plans = NIL;
        root->cte_plan_ids = NIL;
@@ -341,19 +335,30 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
        inline_set_returning_functions(root);
 
        /*
-        * Check to see if any subqueries in the rangetable can be merged into
-        * this query.
+        * Check to see if any subqueries in the jointree can be merged into this
+        * query.
         */
        parse->jointree = (FromExpr *)
-               pull_up_subqueries(root, (Node *) parse->jointree, NULL, NULL);
+               pull_up_subqueries(root, (Node *) parse->jointree);
+
+       /*
+        * If this is a simple UNION ALL query, flatten it into an appendrel. We
+        * do this now because it requires applying pull_up_subqueries to the leaf
+        * queries of the UNION ALL, which weren't touched above because they
+        * weren't referenced by the jointree (they will be after we do this).
+        */
+       if (parse->setOperations)
+               flatten_simple_union_all(root);
 
        /*
         * Detect whether any rangetable entries are RTE_JOIN kind; if not, we can
         * avoid the expense of doing flatten_join_alias_vars().  Also check for
-        * outer joins --- if none, we can skip reduce_outer_joins(). This must be
-        * done after we have done pull_up_subqueries, of course.
+        * outer joins --- if none, we can skip reduce_outer_joins().  And check
+        * for LATERAL RTEs, too.  This must be done after we have done
+        * pull_up_subqueries(), of course.
         */
        root->hasJoinRTEs = false;
+       root->hasLateralRTEs = false;
        hasOuterJoins = false;
        foreach(l, parse->rtable)
        {
@@ -363,12 +368,10 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
                {
                        root->hasJoinRTEs = true;
                        if (IS_OUTER_JOIN(rte->jointype))
-                       {
                                hasOuterJoins = true;
-                               /* Can quit scanning once we find an outer join */
-                               break;
-                       }
                }
+               if (rte->lateral)
+                       root->hasLateralRTEs = true;
        }
 
        /*
@@ -438,18 +441,38 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
                preprocess_expression(root, (Node *) root->append_rel_list,
                                                          EXPRKIND_APPINFO);
 
-       /* Also need to preprocess expressions for function and values RTEs */
+       /* Also need to preprocess expressions within RTEs */
        foreach(l, parse->rtable)
        {
                RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
+               int                     kind;
 
-               if (rte->rtekind == RTE_FUNCTION)
-                       rte->funcexpr = preprocess_expression(root, rte->funcexpr,
-                                                                                                 EXPRKIND_RTFUNC);
+               if (rte->rtekind == RTE_SUBQUERY)
+               {
+                       /*
+                        * We don't want to do all preprocessing yet on the subquery's
+                        * expressions, since that will happen when we plan it.  But if it
+                        * contains any join aliases of our level, those have to get
+                        * expanded now, because planning of the subquery won't do it.
+                        * That's only possible if the subquery is LATERAL.
+                        */
+                       if (rte->lateral && root->hasJoinRTEs)
+                               rte->subquery = (Query *)
+                                       flatten_join_alias_vars(root, (Node *) rte->subquery);
+               }
+               else if (rte->rtekind == RTE_FUNCTION)
+               {
+                       /* Preprocess the function expression fully */
+                       kind = rte->lateral ? EXPRKIND_RTFUNC_LATERAL : EXPRKIND_RTFUNC;
+                       rte->funcexpr = preprocess_expression(root, rte->funcexpr, kind);
+               }
                else if (rte->rtekind == RTE_VALUES)
+               {
+                       /* Preprocess the values lists fully */
+                       kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES;
                        rte->values_lists = (List *)
-                               preprocess_expression(root, (Node *) rte->values_lists,
-                                                                         EXPRKIND_VALUES);
+                               preprocess_expression(root, (Node *) rte->values_lists, kind);
+               }
        }
 
        /*
@@ -531,22 +554,10 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
                        List       *rowMarks;
 
                        /*
-                        * Deal with the RETURNING clause if any.  It's convenient to pass
-                        * the returningList through setrefs.c now rather than at top
-                        * level (if we waited, handling inherited UPDATE/DELETE would be
-                        * much harder).
+                        * Set up the RETURNING list-of-lists, if needed.
                         */
                        if (parse->returningList)
-                       {
-                               List       *rlist;
-
-                               Assert(parse->resultRelation);
-                               rlist = set_returning_clause_references(root->glob,
-                                                                                                               parse->returningList,
-                                                                                                               plan,
-                                                                                                         parse->resultRelation);
-                               returningLists = list_make1(rlist);
-                       }
+                               returningLists = list_make1(parse->returningList);
                        else
                                returningLists = NIL;
 
@@ -561,7 +572,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
                                rowMarks = root->rowMarks;
 
                        plan = (Plan *) make_modifytable(parse->commandType,
-                                                                                  copyObject(root->resultRelations),
+                                                                                        parse->canSetTag,
+                                                                          list_make1_int(parse->resultRelation),
                                                                                         list_make1(plan),
                                                                                         returningLists,
                                                                                         rowMarks,
@@ -575,7 +587,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
         * and attach the initPlans to the top plan node.
         */
        if (list_length(glob->subplans) != num_old_subplans ||
-               root->glob->paramlist != NIL)
+               root->glob->nParamExec > 0)
                SS_finalize_plan(root, plan, true);
 
        /* Return internal info if caller wants it */
@@ -589,7 +601,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
  * preprocess_expression
  *             Do subquery_planner's preprocessing work for an expression,
  *             which can be a targetlist, a WHERE clause (including JOIN/ON
- *             conditions), or a HAVING clause.
+ *             conditions), a HAVING clause, or a few other things.
  */
 static Node *
 preprocess_expression(PlannerInfo *root, Node *expr, int kind)
@@ -604,12 +616,13 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
 
        /*
         * If the query has any join RTEs, replace join alias variables with
-        * base-relation variables. We must do this before sublink processing,
-        * else sublinks expanded out from join aliases wouldn't get processed. We
-        * can skip it in VALUES lists, however, since they can't contain any Vars
-        * at all.
+        * base-relation variables.  We must do this before sublink processing,
+        * else sublinks expanded out from join aliases would not get processed.
+        * We can skip it in non-lateral RTE functions and VALUES lists, however,
+        * since they can't contain any Vars of the current query level.
         */
-       if (root->hasJoinRTEs && kind != EXPRKIND_VALUES)
+       if (root->hasJoinRTEs &&
+               !(kind == EXPRKIND_RTFUNC || kind == EXPRKIND_VALUES))
                expr = flatten_join_alias_vars(root, expr);
 
        /*
@@ -705,6 +718,23 @@ preprocess_qual_conditions(PlannerInfo *root, Node *jtnode)
                         (int) nodeTag(jtnode));
 }
 
+/*
+ * preprocess_phv_expression
+ *       Do preprocessing on a PlaceHolderVar expression that's been pulled up.
+ *
+ * If a LATERAL subquery references an output of another subquery, and that
+ * output must be wrapped in a PlaceHolderVar because of an intermediate outer
+ * join, then we'll push the PlaceHolderVar expression down into the subquery
+ * and later pull it back up during find_lateral_references, which runs after
+ * subquery_planner has preprocessed all the expressions that were in the
+ * current query level to start with.  So we need to preprocess it then.
+ */
+Expr *
+preprocess_phv_expression(PlannerInfo *root, Expr *expr)
+{
+       return (Expr *) preprocess_expression(root, (Node *) expr, EXPRKIND_PHV);
+}
+
 /*
  * inheritance_planner
  *       Generate a plan in the case where the result relation is an
@@ -725,76 +755,177 @@ inheritance_planner(PlannerInfo *root)
 {
        Query      *parse = root->parse;
        int                     parentRTindex = parse->resultRelation;
+       List       *final_rtable = NIL;
+       int                     save_rel_array_size = 0;
+       RelOptInfo **save_rel_array = NULL;
        List       *subplans = NIL;
        List       *resultRelations = NIL;
        List       *returningLists = NIL;
-       List       *rtable = NIL;
        List       *rowMarks;
-       List       *tlist;
-       PlannerInfo subroot;
-       ListCell   *l;
+       ListCell   *lc;
 
-       foreach(l, root->append_rel_list)
+       /*
+        * We generate a modified instance of the original Query for each target
+        * relation, plan that, and put all the plans into a list that will be
+        * controlled by a single ModifyTable node.  All the instances share the
+        * same rangetable, but each instance must have its own set of subquery
+        * RTEs within the finished rangetable because (1) they are likely to get
+        * scribbled on during planning, and (2) it's not inconceivable that
+        * subqueries could get planned differently in different cases.  We need
+        * not create duplicate copies of other RTE kinds, in particular not the
+        * target relations, because they don't have either of those issues.  Not
+        * having to duplicate the target relations is important because doing so
+        * (1) would result in a rangetable of length O(N^2) for N targets, with
+        * at least O(N^3) work expended here; and (2) would greatly complicate
+        * management of the rowMarks list.
+        */
+       foreach(lc, root->append_rel_list)
        {
-               AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
+               AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
+               PlannerInfo subroot;
                Plan       *subplan;
+               Index           rti;
 
                /* append_rel_list contains all append rels; ignore others */
                if (appinfo->parent_relid != parentRTindex)
                        continue;
 
                /*
-                * Generate modified query with this rel as target.
+                * We need a working copy of the PlannerInfo so that we can control
+                * propagation of information back to the main copy.
                 */
                memcpy(&subroot, root, sizeof(PlannerInfo));
+
+               /*
+                * Generate modified query with this rel as target.  We first apply
+                * adjust_appendrel_attrs, which copies the Query and changes
+                * references to the parent RTE to refer to the current child RTE,
+                * then fool around with subquery RTEs.
+                */
                subroot.parse = (Query *)
-                       adjust_appendrel_attrs((Node *) parse,
+                       adjust_appendrel_attrs(root,
+                                                                  (Node *) parse,
                                                                   appinfo);
-               subroot.init_plans = NIL;
-               subroot.hasInheritedTarget = true;
+
+               /*
+                * The rowMarks list might contain references to subquery RTEs, so
+                * make a copy that we can apply ChangeVarNodes to.  (Fortunately, the
+                * executor doesn't need to see the modified copies --- we can just
+                * pass it the original rowMarks list.)
+                */
+               subroot.rowMarks = (List *) copyObject(root->rowMarks);
+
+               /*
+                * Add placeholders to the child Query's rangetable list to fill the
+                * RT indexes already reserved for subqueries in previous children.
+                * These won't be referenced, so there's no need to make them very
+                * valid-looking.
+                */
+               while (list_length(subroot.parse->rtable) < list_length(final_rtable))
+                       subroot.parse->rtable = lappend(subroot.parse->rtable,
+                                                                                       makeNode(RangeTblEntry));
+
+               /*
+                * If this isn't the first child Query, generate duplicates of all
+                * subquery RTEs, and adjust Var numbering to reference the
+                * duplicates. To simplify the loop logic, we scan the original rtable
+                * not the copy just made by adjust_appendrel_attrs; that should be OK
+                * since subquery RTEs couldn't contain any references to the target
+                * rel.
+                */
+               if (final_rtable != NIL)
+               {
+                       ListCell   *lr;
+
+                       rti = 1;
+                       foreach(lr, parse->rtable)
+                       {
+                               RangeTblEntry *rte = (RangeTblEntry *) lfirst(lr);
+
+                               if (rte->rtekind == RTE_SUBQUERY)
+                               {
+                                       Index           newrti;
+
+                                       /*
+                                        * The RTE can't contain any references to its own RT
+                                        * index, so we can save a few cycles by applying
+                                        * ChangeVarNodes before we append the RTE to the
+                                        * rangetable.
+                                        */
+                                       newrti = list_length(subroot.parse->rtable) + 1;
+                                       ChangeVarNodes((Node *) subroot.parse, rti, newrti, 0);
+                                       ChangeVarNodes((Node *) subroot.rowMarks, rti, newrti, 0);
+                                       rte = copyObject(rte);
+                                       subroot.parse->rtable = lappend(subroot.parse->rtable,
+                                                                                                       rte);
+                               }
+                               rti++;
+                       }
+               }
+
                /* We needn't modify the child's append_rel_list */
-               /* There shouldn't be any OJ info to translate, as yet */
+               /* There shouldn't be any OJ or LATERAL info to translate, as yet */
                Assert(subroot.join_info_list == NIL);
+               Assert(subroot.lateral_info_list == NIL);
                /* and we haven't created PlaceHolderInfos, either */
                Assert(subroot.placeholder_list == NIL);
+               /* hack to mark target relation as an inheritance partition */
+               subroot.hasInheritedTarget = true;
 
                /* Generate plan */
                subplan = grouping_planner(&subroot, 0.0 /* retrieve all tuples */ );
 
                /*
                 * If this child rel was excluded by constraint exclusion, exclude it
-                * from the plan.
+                * from the result plan.
                 */
                if (is_dummy_plan(subplan))
                        continue;
 
-               /* Save rtable from first rel for use below */
-               if (subplans == NIL)
-                       rtable = subroot.parse->rtable;
-
                subplans = lappend(subplans, subplan);
 
+               /*
+                * If this is the first non-excluded child, its post-planning rtable
+                * becomes the initial contents of final_rtable; otherwise, append
+                * just its modified subquery RTEs to final_rtable.
+                */
+               if (final_rtable == NIL)
+                       final_rtable = subroot.parse->rtable;
+               else
+                       final_rtable = list_concat(final_rtable,
+                                                                          list_copy_tail(subroot.parse->rtable,
+                                                                                                list_length(final_rtable)));
+
+               /*
+                * We need to collect all the RelOptInfos from all child plans into
+                * the main PlannerInfo, since setrefs.c will need them.  We use the
+                * last child's simple_rel_array (previous ones are too short), so we
+                * have to propagate forward the RelOptInfos that were already built
+                * in previous children.
+                */
+               Assert(subroot.simple_rel_array_size >= save_rel_array_size);
+               for (rti = 1; rti < save_rel_array_size; rti++)
+               {
+                       RelOptInfo *brel = save_rel_array[rti];
+
+                       if (brel)
+                               subroot.simple_rel_array[rti] = brel;
+               }
+               save_rel_array_size = subroot.simple_rel_array_size;
+               save_rel_array = subroot.simple_rel_array;
+
                /* Make sure any initplans from this rel get into the outer list */
-               root->init_plans = list_concat(root->init_plans, subroot.init_plans);
+               root->init_plans = subroot.init_plans;
 
-               /* Build target-relations list for the executor */
+               /* Build list of target-relation RT indexes */
                resultRelations = lappend_int(resultRelations, appinfo->child_relid);
 
                /* Build list of per-relation RETURNING targetlists */
                if (parse->returningList)
-               {
-                       List       *rlist;
-
-                       rlist = set_returning_clause_references(root->glob,
-                                                                                               subroot.parse->returningList,
-                                                                                                       subplan,
-                                                                                                       appinfo->child_relid);
-                       returningLists = lappend(returningLists, rlist);
-               }
+                       returningLists = lappend(returningLists,
+                                                                        subroot.parse->returningList);
        }
 
-       root->resultRelations = resultRelations;
-
        /* Mark result as unordered (probably unnecessary) */
        root->query_pathkeys = NIL;
 
@@ -804,8 +935,9 @@ inheritance_planner(PlannerInfo *root)
         */
        if (subplans == NIL)
        {
-               root->resultRelations = list_make1_int(parentRTindex);
                /* although dummy, it must have a valid tlist for executor */
+               List       *tlist;
+
                tlist = preprocess_targetlist(root, parse->targetList);
                return (Plan *) make_result(root,
                                                                        tlist,
@@ -815,17 +947,11 @@ inheritance_planner(PlannerInfo *root)
        }
 
        /*
-        * Planning might have modified the rangetable, due to changes of the
-        * Query structures inside subquery RTEs.  We have to ensure that this
-        * gets propagated back to the master copy.  But can't do this until we
-        * are done planning, because all the calls to grouping_planner need
-        * virgin sub-Queries to work from.  (We are effectively assuming that
-        * sub-Queries will get planned identically each time, or at least that
-        * the impacts on their rangetables will be the same each time.)
-        *
-        * XXX should clean this up someday
+        * Put back the final adjusted rtable into the master copy of the Query.
         */
-       parse->rtable = rtable;
+       parse->rtable = final_rtable;
+       root->simple_rel_array_size = save_rel_array_size;
+       root->simple_rel_array = save_rel_array;
 
        /*
         * If there was a FOR UPDATE/SHARE clause, the LockRows node will have
@@ -839,7 +965,8 @@ inheritance_planner(PlannerInfo *root)
 
        /* And last, tack on a ModifyTable node to do the UPDATE/DELETE work */
        return (Plan *) make_modifytable(parse->commandType,
-                                                                        copyObject(root->resultRelations),
+                                                                        parse->canSetTag,
+                                                                        resultRelations,
                                                                         subplans,
                                                                         returningLists,
                                                                         rowMarks,
@@ -959,14 +1086,14 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
        {
                /* No set operations, do regular planning */
                List       *sub_tlist;
+               double          sub_limit_tuples;
                AttrNumber *groupColIdx = NULL;
                bool            need_tlist_eval = true;
-               QualCost        tlist_cost;
                Path       *cheapest_path;
                Path       *sorted_path;
                Path       *best_path;
                long            numGroups = 0;
-               AggClauseCounts agg_counts;
+               AggClauseCosts agg_costs;
                int                     numGroupCols;
                double          path_rows;
                int                     path_width;
@@ -974,7 +1101,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                WindowFuncLists *wflists = NULL;
                List       *activeWindows = NIL;
 
-               MemSet(&agg_counts, 0, sizeof(AggClauseCounts));
+               MemSet(&agg_costs, 0, sizeof(AggClauseCosts));
 
                /* A recursive query should always have setOperations */
                Assert(!root->hasRecursion);
@@ -1021,15 +1148,18 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                if (parse->hasAggs)
                {
                        /*
-                        * Will need actual number of aggregates for estimating costs.
-                        * Note: we do not attempt to detect duplicate aggregates here; a
-                        * somewhat-overestimated count is okay for our present purposes.
+                        * Collect statistics about aggregates for estimating costs. Note:
+                        * we do not attempt to detect duplicate aggregates here; a
+                        * somewhat-overestimated cost is okay for our present purposes.
                         */
-                       count_agg_clauses((Node *) tlist, &agg_counts);
-                       count_agg_clauses(parse->havingQual, &agg_counts);
+                       count_agg_clauses(root, (Node *) tlist, &agg_costs);
+                       count_agg_clauses(root, parse->havingQual, &agg_costs);
 
                        /*
-                        * Preprocess MIN/MAX aggregates, if any.
+                        * Preprocess MIN/MAX aggregates, if any.  Note: be careful about
+                        * adding logic between here and the optimize_minmax_aggregates
+                        * call.  Anything that is needed in MIN/MAX-optimizable cases
+                        * will have to be duplicated in planagg.c.
                         */
                        preprocess_minmax_aggregates(root, tlist);
                }
@@ -1110,13 +1240,28 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                else
                        root->query_pathkeys = NIL;
 
+               /*
+                * Figure out whether there's a hard limit on the number of rows that
+                * query_planner's result subplan needs to return.  Even if we know a
+                * hard limit overall, it doesn't apply if the query has any
+                * grouping/aggregation operations.
+                */
+               if (parse->groupClause ||
+                       parse->distinctClause ||
+                       parse->hasAggs ||
+                       parse->hasWindowFuncs ||
+                       root->hasHavingQual)
+                       sub_limit_tuples = -1.0;
+               else
+                       sub_limit_tuples = limit_tuples;
+
                /*
                 * Generate the best unsorted and presorted paths for this Query (but
                 * note there may not be any presorted path).  query_planner will also
                 * estimate the number of groups in the query, and canonicalize all
                 * the pathkeys.
                 */
-               query_planner(root, sub_tlist, tuple_fraction, limit_tuples,
+               query_planner(root, sub_tlist, tuple_fraction, sub_limit_tuples,
                                          &cheapest_path, &sorted_path, &dNumGroups);
 
                /*
@@ -1145,7 +1290,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                           tuple_fraction, limit_tuples,
                                                                           path_rows, path_width,
                                                                           cheapest_path, sorted_path,
-                                                                          dNumGroups, &agg_counts);
+                                                                          dNumGroups, &agg_costs);
                        /* Also convert # groups to long int --- but 'ware overflow! */
                        numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
                }
@@ -1188,6 +1333,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                 */
                result_plan = optimize_minmax_aggregates(root,
                                                                                                 tlist,
+                                                                                                &agg_costs,
                                                                                                 best_path);
                if (result_plan != NULL)
                {
@@ -1215,18 +1361,17 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                need_sort_for_grouping = true;
 
                                /*
-                                * Always override query_planner's tlist, so that we don't
-                                * sort useless data from a "physical" tlist.
+                                * Always override create_plan's tlist, so that we don't sort
+                                * useless data from a "physical" tlist.
                                 */
                                need_tlist_eval = true;
                        }
 
                        /*
-                        * create_plan() returns a plan with just a "flat" tlist of
-                        * required Vars.  Usually we need to insert the sub_tlist as the
-                        * tlist of the top plan node.  However, we can skip that if we
-                        * determined that whatever query_planner chose to return will be
-                        * good enough.
+                        * create_plan returns a plan with just a "flat" tlist of required
+                        * Vars.  Usually we need to insert the sub_tlist as the tlist of
+                        * the top plan node.  However, we can skip that if we determined
+                        * that whatever create_plan chose to return will be good enough.
                         */
                        if (need_tlist_eval)
                        {
@@ -1253,32 +1398,14 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
 
                                /*
                                 * Also, account for the cost of evaluation of the sub_tlist.
-                                *
-                                * Up to now, we have only been dealing with "flat" tlists,
-                                * containing just Vars.  So their evaluation cost is zero
-                                * according to the model used by cost_qual_eval() (or if you
-                                * prefer, the cost is factored into cpu_tuple_cost).  Thus we
-                                * can avoid accounting for tlist cost throughout
-                                * query_planner() and subroutines.  But now we've inserted a
-                                * tlist that might contain actual operators, sub-selects, etc
-                                * --- so we'd better account for its cost.
-                                *
-                                * Below this point, any tlist eval cost for added-on nodes
-                                * should be accounted for as we create those nodes.
-                                * Presently, of the node types we can add on, only Agg,
-                                * WindowAgg, and Group project new tlists (the rest just copy
-                                * their input tuples) --- so make_agg(), make_windowagg() and
-                                * make_group() are responsible for computing the added cost.
+                                * See comments for add_tlist_costs_to_plan() for more info.
                                 */
-                               cost_qual_eval(&tlist_cost, sub_tlist, root);
-                               result_plan->startup_cost += tlist_cost.startup;
-                               result_plan->total_cost += tlist_cost.startup +
-                                       tlist_cost.per_tuple * result_plan->plan_rows;
+                               add_tlist_costs_to_plan(root, result_plan, sub_tlist);
                        }
                        else
                        {
                                /*
-                                * Since we're using query_planner's tlist and not the one
+                                * Since we're using create_plan's tlist and not the one
                                 * make_subplanTargetList calculated, we have to refigure any
                                 * grouping-column indexes make_subplanTargetList computed.
                                 */
@@ -1299,11 +1426,11 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                                tlist,
                                                                                                (List *) parse->havingQual,
                                                                                                AGG_HASHED,
+                                                                                               &agg_costs,
                                                                                                numGroupCols,
                                                                                                groupColIdx,
                                                                        extract_grouping_ops(parse->groupClause),
                                                                                                numGroups,
-                                                                                               agg_counts.numAggs,
                                                                                                result_plan);
                                /* Hashed aggregation produces randomly-ordered results */
                                current_pathkeys = NIL;
@@ -1342,11 +1469,11 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                                tlist,
                                                                                                (List *) parse->havingQual,
                                                                                                aggstrategy,
+                                                                                               &agg_costs,
                                                                                                numGroupCols,
                                                                                                groupColIdx,
                                                                        extract_grouping_ops(parse->groupClause),
                                                                                                numGroups,
-                                                                                               agg_counts.numAggs,
                                                                                                result_plan);
                        }
                        else if (parse->groupClause)
@@ -1441,11 +1568,16 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                         * step.  That's handled internally by make_sort_from_pathkeys,
                         * but we need the copyObject steps here to ensure that each plan
                         * node has a separately modifiable tlist.
+                        *
+                        * Note: it's essential here to use PVC_INCLUDE_AGGREGATES so that
+                        * Vars mentioned only in aggregate expressions aren't pulled out
+                        * as separate targetlist entries.      Otherwise we could be putting
+                        * ungrouped Vars directly into an Agg node's tlist, resulting in
+                        * undefined behavior.
                         */
-                       window_tlist = flatten_tlist(tlist);
-                       if (parse->hasAggs)
-                               window_tlist = add_to_flat_tlist(window_tlist,
-                                                                                       pull_agg_clause((Node *) tlist));
+                       window_tlist = flatten_tlist(tlist,
+                                                                                PVC_INCLUDE_AGGREGATES,
+                                                                                PVC_INCLUDE_PLACEHOLDERS);
                        window_tlist = add_volatile_sort_exprs(window_tlist, tlist,
                                                                                                   activeWindows);
                        result_plan->targetlist = (List *) copyObject(window_tlist);
@@ -1528,7 +1660,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                result_plan = (Plan *)
                                        make_windowagg(root,
                                                                   (List *) copyObject(window_tlist),
-                                                          list_length(wflists->windowFuncs[wc->winref]),
+                                                                  wflists->windowFuncs[wc->winref],
                                                                   wc->winref,
                                                                   partNumCols,
                                                                   partColIdx,
@@ -1594,12 +1726,12 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                        result_plan->targetlist,
                                                                                        NIL,
                                                                                        AGG_HASHED,
+                                                                                       NULL,
                                                                                  list_length(parse->distinctClause),
                                                                 extract_grouping_cols(parse->distinctClause,
                                                                                                        result_plan->targetlist),
                                                                 extract_grouping_ops(parse->distinctClause),
                                                                                        numDistinctRows,
-                                                                                       0,
                                                                                        result_plan);
                        /* Hashed aggregation produces randomly-ordered results */
                        current_pathkeys = NIL;
@@ -1699,12 +1831,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                  count_est);
        }
 
-       /* Compute result-relations list if needed */
-       if (parse->resultRelation)
-               root->resultRelations = list_make1_int(parse->resultRelation);
-       else
-               root->resultRelations = NIL;
-
        /*
         * Return the actual output ordering in query_pathkeys for possible use by
         * an outer query level.
@@ -1714,14 +1840,71 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
        return result_plan;
 }
 
+/*
+ * add_tlist_costs_to_plan
+ *
+ * Estimate the execution costs associated with evaluating the targetlist
+ * expressions, and add them to the cost estimates for the Plan node.
+ *
+ * If the tlist contains set-returning functions, also inflate the Plan's cost
+ * and plan_rows estimates accordingly.  (Hence, this must be called *after*
+ * any logic that uses plan_rows to, eg, estimate qual evaluation costs.)
+ *
+ * Note: during initial stages of planning, we mostly consider plan nodes with
+ * "flat" tlists, containing just Vars.  So their evaluation cost is zero
+ * according to the model used by cost_qual_eval() (or if you prefer, the cost
+ * is factored into cpu_tuple_cost).  Thus we can avoid accounting for tlist
+ * cost throughout query_planner() and subroutines.  But once we apply a
+ * tlist that might contain actual operators, sub-selects, etc, we'd better
+ * account for its cost.  Any set-returning functions in the tlist must also
+ * affect the estimated rowcount.
+ *
+ * Once grouping_planner() has applied a general tlist to the topmost
+ * scan/join plan node, any tlist eval cost for added-on nodes should be
+ * accounted for as we create those nodes.     Presently, of the node types we
+ * can add on later, only Agg, WindowAgg, and Group project new tlists (the
+ * rest just copy their input tuples) --- so make_agg(), make_windowagg() and
+ * make_group() are responsible for calling this function to account for their
+ * tlist costs.
+ */
+void
+add_tlist_costs_to_plan(PlannerInfo *root, Plan *plan, List *tlist)
+{
+       QualCost        tlist_cost;
+       double          tlist_rows;
+
+       cost_qual_eval(&tlist_cost, tlist, root);
+       plan->startup_cost += tlist_cost.startup;
+       plan->total_cost += tlist_cost.startup +
+               tlist_cost.per_tuple * plan->plan_rows;
+
+       tlist_rows = tlist_returns_set_rows(tlist);
+       if (tlist_rows > 1)
+       {
+               /*
+                * We assume that execution costs of the tlist proper were all
+                * accounted for by cost_qual_eval.  However, it still seems
+                * appropriate to charge something more for the executor's general
+                * costs of processing the added tuples.  The cost is probably less
+                * than cpu_tuple_cost, though, so we arbitrarily use half of that.
+                */
+               plan->total_cost += plan->plan_rows * (tlist_rows - 1) *
+                       cpu_tuple_cost / 2;
+
+               plan->plan_rows *= tlist_rows;
+       }
+}
+
 /*
  * Detect whether a plan node is a "dummy" plan created when a relation
  * is deemed not to need scanning due to constraint exclusion.
  *
  * Currently, such dummy plans are Result nodes with constant FALSE
- * filter quals.
+ * filter quals (see set_dummy_rel_pathlist and create_append_plan).
+ *
+ * XXX this probably ought to be somewhere else, but not clear where.
  */
-static bool
+bool
 is_dummy_plan(Plan *plan)
 {
        if (IsA(plan, Result))
@@ -1860,16 +2043,13 @@ preprocess_rowmarks(PlannerInfo *root)
 
                newrc = makeNode(PlanRowMark);
                newrc->rti = newrc->prti = rc->rti;
+               newrc->rowmarkId = ++(root->glob->lastRowMarkId);
                if (rc->forUpdate)
                        newrc->markType = ROW_MARK_EXCLUSIVE;
                else
                        newrc->markType = ROW_MARK_SHARE;
                newrc->noWait = rc->noWait;
                newrc->isParent = false;
-               /* attnos will be assigned in preprocess_targetlist */
-               newrc->ctidAttNo = InvalidAttrNumber;
-               newrc->toidAttNo = InvalidAttrNumber;
-               newrc->wholeAttNo = InvalidAttrNumber;
 
                prowmarks = lappend(prowmarks, newrc);
        }
@@ -1889,17 +2069,15 @@ preprocess_rowmarks(PlannerInfo *root)
 
                newrc = makeNode(PlanRowMark);
                newrc->rti = newrc->prti = i;
+               newrc->rowmarkId = ++(root->glob->lastRowMarkId);
                /* real tables support REFERENCE, anything else needs COPY */
-               if (rte->rtekind == RTE_RELATION)
+               if (rte->rtekind == RTE_RELATION &&
+                       rte->relkind != RELKIND_FOREIGN_TABLE)
                        newrc->markType = ROW_MARK_REFERENCE;
                else
                        newrc->markType = ROW_MARK_COPY;
                newrc->noWait = false;  /* doesn't matter */
                newrc->isParent = false;
-               /* attnos will be assigned in preprocess_targetlist */
-               newrc->ctidAttNo = InvalidAttrNumber;
-               newrc->toidAttNo = InvalidAttrNumber;
-               newrc->wholeAttNo = InvalidAttrNumber;
 
                prowmarks = lappend(prowmarks, newrc);
        }
@@ -2193,7 +2371,7 @@ choose_hashed_grouping(PlannerInfo *root,
                                           double tuple_fraction, double limit_tuples,
                                           double path_rows, int path_width,
                                           Path *cheapest_path, Path *sorted_path,
-                                          double dNumGroups, AggClauseCounts *agg_counts)
+                                          double dNumGroups, AggClauseCosts *agg_costs)
 {
        Query      *parse = root->parse;
        int                     numGroupCols = list_length(parse->groupClause);
@@ -2211,7 +2389,7 @@ choose_hashed_grouping(PlannerInfo *root,
         * the hash table, and/or running many sorts in parallel, either of which
         * seems like a certain loser.)
         */
-       can_hash = (agg_counts->numOrderedAggs == 0 &&
+       can_hash = (agg_costs->numOrderedAggs == 0 &&
                                grouping_is_hashable(parse->groupClause));
        can_sort = grouping_is_sortable(parse->groupClause);
 
@@ -2241,9 +2419,9 @@ choose_hashed_grouping(PlannerInfo *root,
        /* Estimate per-hash-entry space at tuple width... */
        hashentrysize = MAXALIGN(path_width) + MAXALIGN(sizeof(MinimalTupleData));
        /* plus space for pass-by-ref transition values... */
-       hashentrysize += agg_counts->transitionSpace;
+       hashentrysize += agg_costs->transitionSpace;
        /* plus the per-hash-entry overhead */
-       hashentrysize += hash_agg_entry_size(agg_counts->numAggs);
+       hashentrysize += hash_agg_entry_size(agg_costs->numAggs);
 
        if (hashentrysize * dNumGroups > work_mem * 1024L)
                return false;
@@ -2277,7 +2455,7 @@ choose_hashed_grouping(PlannerInfo *root,
         * These path variables are dummies that just hold cost fields; we don't
         * make actual Paths for these steps.
         */
-       cost_agg(&hashed_p, root, AGG_HASHED, agg_counts->numAggs,
+       cost_agg(&hashed_p, root, AGG_HASHED, agg_costs,
                         numGroupCols, dNumGroups,
                         cheapest_path->startup_cost, cheapest_path->total_cost,
                         path_rows);
@@ -2308,7 +2486,7 @@ choose_hashed_grouping(PlannerInfo *root,
        }
 
        if (parse->hasAggs)
-               cost_agg(&sorted_p, root, AGG_SORTED, agg_counts->numAggs,
+               cost_agg(&sorted_p, root, AGG_SORTED, agg_costs,
                                 numGroupCols, dNumGroups,
                                 sorted_p.startup_cost, sorted_p.total_cost,
                                 path_rows);
@@ -2427,7 +2605,7 @@ choose_hashed_distinct(PlannerInfo *root,
         * These path variables are dummies that just hold cost fields; we don't
         * make actual Paths for these steps.
         */
-       cost_agg(&hashed_p, root, AGG_HASHED, 0,
+       cost_agg(&hashed_p, root, AGG_HASHED, NULL,
                         numDistinctCols, dNumDistinctRows,
                         cheapest_startup_cost, cheapest_total_cost,
                         path_rows);
@@ -2494,10 +2672,11 @@ choose_hashed_distinct(PlannerInfo *root,
  * make_subplanTargetList
  *       Generate appropriate target list when grouping is required.
  *
- * When grouping_planner inserts Aggregate, Group, or Result plan nodes
- * above the result of query_planner, we typically want to pass a different
- * target list to query_planner than the outer plan nodes should have.
- * This routine generates the correct target list for the subplan.
+ * When grouping_planner inserts grouping or aggregation plan nodes
+ * above the scan/join plan constructed by query_planner+create_plan,
+ * we typically want the scan/join plan to emit a different target list
+ * than the outer plan nodes should have.  This routine generates the
+ * correct target list for the scan/join subplan.
  *
  * The initial target list passed from the parser already contains entries
  * for all ORDER BY and GROUP BY expressions, but it will not have entries
@@ -2508,27 +2687,25 @@ choose_hashed_distinct(PlannerInfo *root,
  * For example, given a query like
  *             SELECT a+b,SUM(c+d) FROM table GROUP BY a+b;
  * we want to pass this targetlist to the subplan:
- *             a,b,c,d,a+b
+ *             a+b,c,d
  * where the a+b target will be used by the Sort/Group steps, and the
- * other targets will be used for computing the final results. (In the
- * above example we could theoretically suppress the a and b targets and
- * pass down only c,d,a+b, but it's not really worth the trouble to
- * eliminate simple var references from the subplan.  We will avoid doing
- * the extra computation to recompute a+b at the outer level; see
- * fix_upper_expr() in setrefs.c.)
+ * other targets will be used for computing the final results.
  *
  * If we are grouping or aggregating, *and* there are no non-Var grouping
  * expressions, then the returned tlist is effectively dummy; we do not
  * need to force it to be evaluated, because all the Vars it contains
- * should be present in the output of query_planner anyway.
+ * should be present in the "flat" tlist generated by create_plan, though
+ * possibly in a different order.  In that case we'll use create_plan's tlist,
+ * and the tlist made here is only needed as input to query_planner to tell
+ * it which Vars are needed in the output of the scan/join plan.
  *
  * 'tlist' is the query's target list.
  * 'groupColIdx' receives an array of column numbers for the GROUP BY
- *                     expressions (if there are any) in the subplan's target list.
+ *                     expressions (if there are any) in the returned target list.
  * 'need_tlist_eval' is set true if we really need to evaluate the
- *                     result tlist.
+ *                     returned tlist as-is.
  *
- * The result is the targetlist to be passed to the subplan.
+ * The result is the targetlist to be passed to query_planner.
  */
 static List *
 make_subplanTargetList(PlannerInfo *root,
@@ -2538,7 +2715,8 @@ make_subplanTargetList(PlannerInfo *root,
 {
        Query      *parse = root->parse;
        List       *sub_tlist;
-       List       *extravars;
+       List       *non_group_cols;
+       List       *non_group_vars;
        int                     numCols;
 
        *groupColIdx = NULL;
@@ -2555,70 +2733,135 @@ make_subplanTargetList(PlannerInfo *root,
        }
 
        /*
-        * Otherwise, start with a "flattened" tlist (having just the vars
-        * mentioned in the targetlist and HAVING qual --- but not upper-level
-        * Vars; they will be replaced by Params later on).  Note this includes
-        * vars used in resjunk items, so we are covering the needs of ORDER BY
-        * and window specifications.
+        * Otherwise, we must build a tlist containing all grouping columns, plus
+        * any other Vars mentioned in the targetlist and HAVING qual.
         */
-       sub_tlist = flatten_tlist(tlist);
-       extravars = pull_var_clause(parse->havingQual, PVC_INCLUDE_PLACEHOLDERS);
-       sub_tlist = add_to_flat_tlist(sub_tlist, extravars);
-       list_free(extravars);
+       sub_tlist = NIL;
+       non_group_cols = NIL;
        *need_tlist_eval = false;       /* only eval if not flat tlist */
 
-       /*
-        * If grouping, create sub_tlist entries for all GROUP BY expressions
-        * (GROUP BY items that are simple Vars should be in the list already),
-        * and make an array showing where the group columns are in the sub_tlist.
-        */
        numCols = list_length(parse->groupClause);
        if (numCols > 0)
        {
-               int                     keyno = 0;
+               /*
+                * If grouping, create sub_tlist entries for all GROUP BY columns, and
+                * make an array showing where the group columns are in the sub_tlist.
+                *
+                * Note: with this implementation, the array entries will always be
+                * 1..N, but we don't want callers to assume that.
+                */
                AttrNumber *grpColIdx;
-               ListCell   *gl;
+               ListCell   *tl;
 
-               grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
+               grpColIdx = (AttrNumber *) palloc0(sizeof(AttrNumber) * numCols);
                *groupColIdx = grpColIdx;
 
-               foreach(gl, parse->groupClause)
+               foreach(tl, tlist)
                {
-                       SortGroupClause *grpcl = (SortGroupClause *) lfirst(gl);
-                       Node       *groupexpr = get_sortgroupclause_expr(grpcl, tlist);
-                       TargetEntry *te;
+                       TargetEntry *tle = (TargetEntry *) lfirst(tl);
+                       int                     colno;
 
-                       /*
-                        * Find or make a matching sub_tlist entry.  If the groupexpr
-                        * isn't a Var, no point in searching.  (Note that the parser
-                        * won't make multiple groupClause entries for the same TLE.)
-                        */
-                       if (groupexpr && IsA(groupexpr, Var))
-                               te = tlist_member(groupexpr, sub_tlist);
-                       else
-                               te = NULL;
+                       colno = get_grouping_column_index(parse, tle);
+                       if (colno >= 0)
+                       {
+                               /*
+                                * It's a grouping column, so add it to the result tlist and
+                                * remember its resno in grpColIdx[].
+                                */
+                               TargetEntry *newtle;
+
+                               newtle = makeTargetEntry(tle->expr,
+                                                                                list_length(sub_tlist) + 1,
+                                                                                NULL,
+                                                                                false);
+                               sub_tlist = lappend(sub_tlist, newtle);
+
+                               Assert(grpColIdx[colno] == 0);  /* no dups expected */
+                               grpColIdx[colno] = newtle->resno;
 
-                       if (!te)
+                               if (!(newtle->expr && IsA(newtle->expr, Var)))
+                                       *need_tlist_eval = true;        /* tlist contains non Vars */
+                       }
+                       else
                        {
-                               te = makeTargetEntry((Expr *) groupexpr,
-                                                                        list_length(sub_tlist) + 1,
-                                                                        NULL,
-                                                                        false);
-                               sub_tlist = lappend(sub_tlist, te);
-                               *need_tlist_eval = true;                /* it's not flat anymore */
+                               /*
+                                * Non-grouping column, so just remember the expression for
+                                * later call to pull_var_clause.  There's no need for
+                                * pull_var_clause to examine the TargetEntry node itself.
+                                */
+                               non_group_cols = lappend(non_group_cols, tle->expr);
                        }
-
-                       /* and save its resno */
-                       grpColIdx[keyno++] = te->resno;
                }
        }
+       else
+       {
+               /*
+                * With no grouping columns, just pass whole tlist to pull_var_clause.
+                * Need (shallow) copy to avoid damaging input tlist below.
+                */
+               non_group_cols = list_copy(tlist);
+       }
+
+       /*
+        * If there's a HAVING clause, we'll need the Vars it uses, too.
+        */
+       if (parse->havingQual)
+               non_group_cols = lappend(non_group_cols, parse->havingQual);
+
+       /*
+        * Pull out all the Vars mentioned in non-group cols (plus HAVING), and
+        * add them to the result tlist if not already present.  (A Var used
+        * directly as a GROUP BY item will be present already.)  Note this
+        * includes Vars used in resjunk items, so we are covering the needs of
+        * ORDER BY and window specifications.  Vars used within Aggrefs will be
+        * pulled out here, too.
+        */
+       non_group_vars = pull_var_clause((Node *) non_group_cols,
+                                                                        PVC_RECURSE_AGGREGATES,
+                                                                        PVC_INCLUDE_PLACEHOLDERS);
+       sub_tlist = add_to_flat_tlist(sub_tlist, non_group_vars);
+
+       /* clean up cruft */
+       list_free(non_group_vars);
+       list_free(non_group_cols);
 
        return sub_tlist;
 }
 
+/*
+ * get_grouping_column_index
+ *             Get the GROUP BY column position, if any, of a targetlist entry.
+ *
+ * Returns the index (counting from 0) of the TLE in the GROUP BY list, or -1
+ * if it's not a grouping column.  Note: the result is unique because the
+ * parser won't make multiple groupClause entries for the same TLE.
+ */
+static int
+get_grouping_column_index(Query *parse, TargetEntry *tle)
+{
+       int                     colno = 0;
+       Index           ressortgroupref = tle->ressortgroupref;
+       ListCell   *gl;
+
+       /* No need to search groupClause if TLE hasn't got a sortgroupref */
+       if (ressortgroupref == 0)
+               return -1;
+
+       foreach(gl, parse->groupClause)
+       {
+               SortGroupClause *grpcl = (SortGroupClause *) lfirst(gl);
+
+               if (grpcl->tleSortGroupRef == ressortgroupref)
+                       return colno;
+               colno++;
+       }
+
+       return -1;
+}
+
 /*
  * locate_grouping_columns
- *             Locate grouping columns in the tlist chosen by query_planner.
+ *             Locate grouping columns in the tlist chosen by create_plan.
  *
  * This is only needed if we don't use the sub_tlist chosen by
  * make_subplanTargetList.     We have to forget the column indexes found
@@ -3057,30 +3300,18 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
        rte = makeNode(RangeTblEntry);
        rte->rtekind = RTE_RELATION;
        rte->relid = tableOid;
+       rte->relkind = RELKIND_RELATION;
+       rte->lateral = false;
        rte->inh = false;
        rte->inFromCl = true;
        query->rtable = list_make1(rte);
 
-       /* ... and insert it into PlannerInfo */
-       root->simple_rel_array_size = 2;
-       root->simple_rel_array = (RelOptInfo **)
-               palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *));
-       root->simple_rte_array = (RangeTblEntry **)
-               palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *));
-       root->simple_rte_array[1] = rte;
+       /* Set up RTE/RelOptInfo arrays */
+       setup_simple_rel_arrays(root);
 
        /* Build RelOptInfo */
        rel = build_simple_rel(root, 1, RELOPT_BASEREL);
 
-       /*
-        * Rather than doing all the pushups that would be needed to use
-        * set_baserel_size_estimates, just do a quick hack for rows and width.
-        */
-       rel->rows = rel->tuples;
-       rel->width = get_relation_data_width(tableOid);
-
-       root->total_table_pages = rel->pages;
-
        /* Locate IndexOptInfo for the target index */
        indexInfo = NULL;
        foreach(lc, rel->indexlist)
@@ -3089,29 +3320,46 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
                if (indexInfo->indexoid == indexOid)
                        break;
        }
+
+       /*
+        * It's possible that get_relation_info did not generate an IndexOptInfo
+        * for the desired index; this could happen if it's not yet reached its
+        * indcheckxmin usability horizon, or if it's a system index and we're
+        * ignoring system indexes.  In such cases we should tell CLUSTER to not
+        * trust the index contents but use seqscan-and-sort.
+        */
        if (lc == NULL)                         /* not in the list? */
-               elog(ERROR, "index %u does not belong to table %u",
-                        indexOid, tableOid);
+               return true;                    /* use sort */
+
+       /*
+        * Rather than doing all the pushups that would be needed to use
+        * set_baserel_size_estimates, just do a quick hack for rows and width.
+        */
+       rel->rows = rel->tuples;
+       rel->width = get_relation_data_width(tableOid, NULL);
+
+       root->total_table_pages = rel->pages;
 
        /*
         * Determine eval cost of the index expressions, if any.  We need to
-        * charge twice that amount for each tuple comparison that happens
-        * during the sort, since tuplesort.c will have to re-evaluate the
-        * index expressions each time.  (XXX that's pretty inefficient...)
+        * charge twice that amount for each tuple comparison that happens during
+        * the sort, since tuplesort.c will have to re-evaluate the index
+        * expressions each time.  (XXX that's pretty inefficient...)
         */
        cost_qual_eval(&indexExprCost, indexInfo->indexprs, root);
        comparisonCost = 2.0 * (indexExprCost.startup + indexExprCost.per_tuple);
 
        /* Estimate the cost of seq scan + sort */
-       seqScanPath = create_seqscan_path(root, rel);
+       seqScanPath = create_seqscan_path(root, rel, NULL);
        cost_sort(&seqScanAndSortPath, root, NIL,
                          seqScanPath->total_cost, rel->tuples, rel->width,
                          comparisonCost, maintenance_work_mem, -1.0);
 
        /* Estimate the cost of index scan */
        indexScanPath = create_index_path(root, indexInfo,
-                                                                         NIL, NIL,
-                                                                         ForwardScanDirection, NULL);
+                                                                         NIL, NIL, NIL, NIL, NIL,
+                                                                         ForwardScanDirection, false,
+                                                                         NULL, 1.0);
 
        return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
 }