]> granicus.if.org Git - postgresql/blobdiff - src/backend/optimizer/plan/planner.c
pgindent run for 8.3.
[postgresql] / src / backend / optimizer / plan / planner.c
index 680bc1521c224db8087c6740dcbe6ab37133a8c1..5234e0433d2c64f944044b8152bcbab1d77f023f 100644 (file)
@@ -3,12 +3,12 @@
  * planner.c
  *       The query optimizer external interface.
  *
- * 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/plan/planner.c,v 1.202 2006/07/11 17:26:58 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.224 2007/11/15 21:14:36 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,7 +18,6 @@
 #include <limits.h>
 
 #include "catalog/pg_operator.h"
-#include "catalog/pg_type.h"
 #include "executor/executor.h"
 #include "executor/nodeAgg.h"
 #include "miscadmin.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
 #include "parser/parsetree.h"
-#include "utils/selfuncs.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
-ParamListInfo PlannerBoundParamList = NULL;            /* current boundParams */
+/* Hook for plugins to get control in planner() */
+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_LIMIT         3
-#define EXPRKIND_ININFO                4
-#define EXPRKIND_APPINFO       5
+#define EXPRKIND_VALUES                3
+#define EXPRKIND_LIMIT         4
+#define EXPRKIND_ININFO                5
+#define EXPRKIND_APPINFO       6
 
 
 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 double preprocess_limit(PlannerInfo *root,
                                 double tuple_fraction,
-                                int *offset_est, int *count_est);
-static bool choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
+                                int64 *offset_est, int64 *count_est);
+static Oid *extract_grouping_ops(List *groupClause);
+static bool choose_hashed_grouping(PlannerInfo *root,
+                                          double tuple_fraction, double limit_tuples,
                                           Path *cheapest_path, Path *sorted_path,
-                                          double dNumGroups, AggClauseCounts *agg_counts);
-static bool hash_safe_grouping(PlannerInfo *root);
+                                          Oid *groupOperators, double dNumGroups,
+                                          AggClauseCounts *agg_counts);
 static List *make_subplanTargetList(PlannerInfo *root, List *tlist,
                                           AttrNumber **groupColIdx, bool *need_tlist_eval);
 static void locate_grouping_columns(PlannerInfo *root,
@@ -79,43 +83,62 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
  *
  *        Query optimizer entry point
  *
+ * To support loadable plugins that monitor or modify planner behavior,
+ * we provide a hook variable that lets a plugin get control before and
+ * after the standard planning process.  The plugin would normally call
+ * standard_planner().
+ *
+ * Note to plugin authors: standard_planner() scribbles on its Query input,
+ * so you'd better copy that data structure if you want to plan more than once.
+ *
  *****************************************************************************/
-Plan *
-planner(Query *parse, bool isCursor, int cursorOptions,
-               ParamListInfo boundParams)
+PlannedStmt *
+planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
+{
+       PlannedStmt *result;
+
+       if (planner_hook)
+               result = (*planner_hook) (parse, cursorOptions, boundParams);
+       else
+               result = standard_planner(parse, cursorOptions, boundParams);
+       return result;
+}
+
+PlannedStmt *
+standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 {
+       PlannedStmt *result;
+       PlannerGlobal *glob;
        double          tuple_fraction;
-       Plan       *result_plan;
-       Index           save_PlannerQueryLevel;
-       List       *save_PlannerParamList;
-       ParamListInfo save_PlannerBoundParamList;
+       PlannerInfo *root;
+       Plan       *top_plan;
+       ListCell   *lp,
+                          *lr;
+
+       /* Cursor options may come from caller or from DECLARE CURSOR stmt */
+       if (parse->utilityStmt &&
+               IsA(parse->utilityStmt, DeclareCursorStmt))
+               cursorOptions |= ((DeclareCursorStmt *) parse->utilityStmt)->options;
 
        /*
-        * The planner can be called recursively (an example is when
-        * eval_const_expressions tries to pre-evaluate an SQL function). So,
-        * these global state variables must be saved and restored.
-        *
-        * Query level and the param list cannot be moved into the per-query
-        * PlannerInfo structure since their whole purpose is communication across
-        * multiple sub-queries. Also, boundParams is explicitly info from outside
-        * the query, and so is likewise better handled as a global variable.
-        *
-        * Note we do NOT save and restore PlannerPlanId: it exists to assign
-        * unique IDs to SubPlan nodes, and we want those IDs to be unique for the
-        * life of a backend.  Also, PlannerInitPlan is saved/restored in
-        * subquery_planner, not here.
+        * Set up global state for this planner invocation.  This data is needed
+        * across all levels of sub-Query that might exist in the given command,
+        * so we keep it in a separate struct that's linked to by each per-Query
+        * PlannerInfo.
         */
-       save_PlannerQueryLevel = PlannerQueryLevel;
-       save_PlannerParamList = PlannerParamList;
-       save_PlannerBoundParamList = PlannerBoundParamList;
+       glob = makeNode(PlannerGlobal);
 
-       /* Initialize state for handling outer-level references and params */
-       PlannerQueryLevel = 0;          /* will be 1 in top-level subquery_planner */
-       PlannerParamList = NIL;
-       PlannerBoundParamList = boundParams;
+       glob->boundParams = boundParams;
+       glob->paramlist = NIL;
+       glob->subplans = NIL;
+       glob->subrtables = NIL;
+       glob->rewindPlanIDs = NULL;
+       glob->finalrtable = NIL;
+       glob->relationOids = NIL;
+       glob->transientPlan = false;
 
        /* Determine what fraction of the plan is likely to be scanned */
-       if (isCursor)
+       if (cursorOptions & CURSOR_OPT_FAST_PLAN)
        {
                /*
                 * We have no real idea how many tuples the user will ultimately FETCH
@@ -132,33 +155,50 @@ planner(Query *parse, bool isCursor, int cursorOptions,
        }
 
        /* primary planning entry point (may recurse for subqueries) */
-       result_plan = subquery_planner(parse, tuple_fraction, NULL);
-
-       /* check we popped out the right number of levels */
-       Assert(PlannerQueryLevel == 0);
+       top_plan = subquery_planner(glob, parse, 1, tuple_fraction, &root);
 
        /*
         * If creating a plan for a scrollable cursor, make sure it can run
         * backwards on demand.  Add a Material node at the top at need.
         */
-       if (isCursor && (cursorOptions & CURSOR_OPT_SCROLL))
+       if (cursorOptions & CURSOR_OPT_SCROLL)
        {
-               if (!ExecSupportsBackwardScan(result_plan))
-                       result_plan = materialize_finished_plan(result_plan);
+               if (!ExecSupportsBackwardScan(top_plan))
+                       top_plan = materialize_finished_plan(top_plan);
        }
 
        /* final cleanup of the plan */
-       result_plan = set_plan_references(result_plan, parse->rtable);
-
-       /* executor wants to know total number of Params used overall */
-       result_plan->nParamExec = list_length(PlannerParamList);
+       Assert(glob->finalrtable == NIL);
+       top_plan = set_plan_references(glob, top_plan, root->parse->rtable);
+       /* ... and the subplans (both regular subplans and initplans) */
+       Assert(list_length(glob->subplans) == list_length(glob->subrtables));
+       forboth(lp, glob->subplans, lr, glob->subrtables)
+       {
+               Plan       *subplan = (Plan *) lfirst(lp);
+               List       *subrtable = (List *) lfirst(lr);
 
-       /* restore state for outer planner, if any */
-       PlannerQueryLevel = save_PlannerQueryLevel;
-       PlannerParamList = save_PlannerParamList;
-       PlannerBoundParamList = save_PlannerBoundParamList;
+               lfirst(lp) = set_plan_references(glob, subplan, subrtable);
+       }
 
-       return result_plan;
+       /* build the PlannedStmt result */
+       result = makeNode(PlannedStmt);
+
+       result->commandType = parse->commandType;
+       result->canSetTag = parse->canSetTag;
+       result->transientPlan = glob->transientPlan;
+       result->planTree = top_plan;
+       result->rtable = glob->finalrtable;
+       result->resultRelations = root->resultRelations;
+       result->utilityStmt = parse->utilityStmt;
+       result->intoClause = parse->intoClause;
+       result->subplans = glob->subplans;
+       result->rewindPlanIDs = glob->rewindPlanIDs;
+       result->returningLists = root->returningLists;
+       result->rowMarks = parse->rowMarks;
+       result->relationOids = glob->relationOids;
+       result->nParamExec = list_length(glob->paramlist);
+
+       return result;
 }
 
 
@@ -167,12 +207,14 @@ planner(Query *parse, bool isCursor, int cursorOptions,
  *       Invokes the planner on a subquery.  We recurse to here for each
  *       sub-SELECT found in the query tree.
  *
+ * glob is the global state for the current planner run.
  * parse is the querytree produced by the parser & rewriter.
+ * level is the current recursion depth (1 at the top-level Query).
  * tuple_fraction is the fraction of tuples we expect will be retrieved.
  * tuple_fraction is interpreted as explained for grouping_planner, below.
  *
- * If subquery_pathkeys isn't NULL, it receives a list of pathkeys indicating
- * the output sort ordering of the completed plan.
+ * If subroot isn't NULL, we pass back the query's final PlannerInfo struct;
+ * among other things this tells the output sort ordering of the plan.
  *
  * Basically, this routine does the stuff that should only be done once
  * per Query object.  It then calls grouping_planner.  At one time,
@@ -187,23 +229,24 @@ planner(Query *parse, bool isCursor, int cursorOptions,
  *--------------------
  */
 Plan *
-subquery_planner(Query *parse, double tuple_fraction,
-                                List **subquery_pathkeys)
+subquery_planner(PlannerGlobal * glob, Query *parse,
+                                Index level, double tuple_fraction,
+                                PlannerInfo **subroot)
 {
-       List       *saved_initplan = PlannerInitPlan;
-       int                     saved_planid = PlannerPlanId;
+       int                     num_old_subplans = list_length(glob->subplans);
        PlannerInfo *root;
        Plan       *plan;
        List       *newHaving;
        ListCell   *l;
 
-       /* Set up for a new level of subquery */
-       PlannerQueryLevel++;
-       PlannerInitPlan = NIL;
-
        /* Create a PlannerInfo data structure for this subquery */
        root = makeNode(PlannerInfo);
        root->parse = parse;
+       root->glob = glob;
+       root->query_level = level;
+       root->planner_cxt = CurrentMemoryContext;
+       root->init_plans = NIL;
+       root->eq_classes = NIL;
        root->in_info_list = NIL;
        root->append_rel_list = NIL;
 
@@ -280,6 +323,10 @@ subquery_planner(Query *parse, double tuple_fraction,
                preprocess_expression(root, (Node *) parse->targetList,
                                                          EXPRKIND_TARGET);
 
+       parse->returningList = (List *)
+               preprocess_expression(root, (Node *) parse->returningList,
+                                                         EXPRKIND_TARGET);
+
        preprocess_qual_conditions(root, (Node *) parse->jointree);
 
        parse->havingQual = preprocess_expression(root, parse->havingQual,
@@ -297,7 +344,7 @@ subquery_planner(Query *parse, double tuple_fraction,
                preprocess_expression(root, (Node *) root->append_rel_list,
                                                          EXPRKIND_APPINFO);
 
-       /* Also need to preprocess expressions for function RTEs */
+       /* Also need to preprocess expressions for function and values RTEs */
        foreach(l, parse->rtable)
        {
                RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
@@ -305,6 +352,10 @@ subquery_planner(Query *parse, double tuple_fraction,
                if (rte->rtekind == RTE_FUNCTION)
                        rte->funcexpr = preprocess_expression(root, rte->funcexpr,
                                                                                                  EXPRKIND_RTFUNC);
+               else if (rte->rtekind == RTE_VALUES)
+                       rte->values_lists = (List *)
+                               preprocess_expression(root, (Node *) rte->values_lists,
+                                                                         EXPRKIND_VALUES);
        }
 
        /*
@@ -384,17 +435,13 @@ subquery_planner(Query *parse, double tuple_fraction,
         * initPlan list and extParam/allParam sets for plan nodes, and attach the
         * initPlans to the top plan node.
         */
-       if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1)
-               SS_finalize_plan(plan, parse->rtable);
+       if (list_length(glob->subplans) != num_old_subplans ||
+               root->query_level > 1)
+               SS_finalize_plan(root, plan);
 
-       /* Return sort ordering info if caller wants it */
-       if (subquery_pathkeys)
-               *subquery_pathkeys = root->query_pathkeys;
-
-       /* Return to outer subquery context */
-       PlannerQueryLevel--;
-       PlannerInitPlan = saved_initplan;
-       /* we do NOT restore PlannerPlanId; that's not an oversight! */
+       /* Return internal info if caller wants it */
+       if (subroot)
+               *subroot = root;
 
        return plan;
 }
@@ -419,9 +466,11 @@ 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.
+        * 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.
         */
-       if (root->hasJoinRTEs)
+       if (root->hasJoinRTEs && kind != EXPRKIND_VALUES)
                expr = flatten_join_alias_vars(root, expr);
 
        /*
@@ -439,10 +488,14 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
         * and we will waste cycles copying the tree.  Notice however that we
         * still must do it for quals (to get AND/OR flatness); and if we are in a
         * subquery we should not assume it will be done only once.
+        *
+        * For VALUES lists we never do this at all, again on the grounds that we
+        * should optimize for one-time evaluation.
         */
-       if (root->parse->jointree->fromlist != NIL ||
-               kind == EXPRKIND_QUAL ||
-               PlannerQueryLevel > 1)
+       if (kind != EXPRKIND_VALUES &&
+               (root->parse->jointree->fromlist != NIL ||
+                kind == EXPRKIND_QUAL ||
+                root->query_level > 1))
                expr = eval_const_expressions(expr);
 
        /*
@@ -460,16 +513,16 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
 
        /* Expand SubLinks to SubPlans */
        if (root->parse->hasSubLinks)
-               expr = SS_process_sublinks(expr, (kind == EXPRKIND_QUAL));
+               expr = SS_process_sublinks(root, expr, (kind == EXPRKIND_QUAL));
 
        /*
         * XXX do not insert anything here unless you have grokked the comments in
         * SS_replace_correlation_vars ...
         */
 
-       /* Replace uplevel vars with Param nodes */
-       if (PlannerQueryLevel > 1)
-               expr = SS_replace_correlation_vars(expr);
+       /* Replace uplevel vars with Param nodes (this IS possible in VALUES) */
+       if (root->query_level > 1)
+               expr = SS_replace_correlation_vars(root, expr);
 
        /*
         * If it's a qual or havingQual, convert it to implicit-AND format. (We
@@ -544,14 +597,13 @@ inheritance_planner(PlannerInfo *root)
        Query      *parse = root->parse;
        int                     parentRTindex = parse->resultRelation;
        List       *subplans = NIL;
+       List       *resultRelations = NIL;
+       List       *returningLists = NIL;
+       List       *rtable = NIL;
        List       *tlist = NIL;
        PlannerInfo subroot;
        ListCell   *l;
 
-       subroot.parse = NULL;           /* catch it if no matches in loop */
-
-       parse->resultRelations = NIL;
-
        foreach(l, root->append_rel_list)
        {
                AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
@@ -561,10 +613,6 @@ inheritance_planner(PlannerInfo *root)
                if (appinfo->parent_relid != parentRTindex)
                        continue;
 
-               /* Build target-relations list for the executor */
-               parse->resultRelations = lappend_int(parse->resultRelations,
-                                                                                        appinfo->child_relid);
-
                /*
                 * Generate modified query with this rel as target.  We have to be
                 * prepared to translate varnos in in_info_list as well as in the
@@ -577,17 +625,63 @@ inheritance_planner(PlannerInfo *root)
                subroot.in_info_list = (List *)
                        adjust_appendrel_attrs((Node *) root->in_info_list,
                                                                   appinfo);
+               subroot.init_plans = NIL;
                /* There shouldn't be any OJ info to translate, as yet */
                Assert(subroot.oj_info_list == NIL);
 
                /* Generate plan */
                subplan = grouping_planner(&subroot, 0.0 /* retrieve all tuples */ );
 
-               subplans = lappend(subplans, subplan);
+               /*
+                * If this child rel was excluded by constraint exclusion, exclude it
+                * from the plan.
+                */
+               if (is_dummy_plan(subplan))
+                       continue;
 
-               /* Save preprocessed tlist from first rel for use in Append */
-               if (tlist == NIL)
+               /* Save rtable and tlist from first rel for use below */
+               if (subplans == NIL)
+               {
+                       rtable = subroot.parse->rtable;
                        tlist = subplan->targetlist;
+               }
+
+               subplans = lappend(subplans, subplan);
+
+               /* Make sure any initplans from this rel get into the outer list */
+               root->init_plans = list_concat(root->init_plans, subroot.init_plans);
+
+               /* Build target-relations list for the executor */
+               resultRelations = lappend_int(resultRelations, appinfo->child_relid);
+
+               /* Build list of per-relation RETURNING targetlists */
+               if (parse->returningList)
+               {
+                       Assert(list_length(subroot.returningLists) == 1);
+                       returningLists = list_concat(returningLists,
+                                                                                subroot.returningLists);
+               }
+       }
+
+       root->resultRelations = resultRelations;
+       root->returningLists = returningLists;
+
+       /* Mark result as unordered (probably unnecessary) */
+       root->query_pathkeys = NIL;
+
+       /*
+        * If we managed to exclude every child rel, return a dummy plan
+        */
+       if (subplans == NIL)
+       {
+               root->resultRelations = list_make1_int(parentRTindex);
+               /* although dummy, it must have a valid tlist for executor */
+               tlist = preprocess_targetlist(root, parse->targetList);
+               return (Plan *) make_result(root,
+                                                                       tlist,
+                                                                       (Node *) list_make1(makeBoolConst(false,
+                                                                                                                                         false)),
+                                                                       NULL);
        }
 
        /*
@@ -601,10 +695,11 @@ inheritance_planner(PlannerInfo *root)
         *
         * XXX should clean this up someday
         */
-       parse->rtable = subroot.parse->rtable;
+       parse->rtable = rtable;
 
-       /* Mark result as unordered (probably unnecessary) */
-       root->query_pathkeys = NIL;
+       /* Suppress Append if there's only one surviving child rel */
+       if (list_length(subplans) == 1)
+               return (Plan *) linitial(subplans);
 
        return (Plan *) make_append(subplans, true, tlist);
 }
@@ -633,8 +728,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
 {
        Query      *parse = root->parse;
        List       *tlist = parse->targetList;
-       int                     offset_est = 0;
-       int                     count_est = 0;
+       int64           offset_est = 0;
+       int64           count_est = 0;
+       double          limit_tuples = -1.0;
        Plan       *result_plan;
        List       *current_pathkeys;
        List       *sort_pathkeys;
@@ -642,9 +738,18 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
 
        /* Tweak caller-supplied tuple_fraction if have LIMIT/OFFSET */
        if (parse->limitCount || parse->limitOffset)
+       {
                tuple_fraction = preprocess_limit(root, tuple_fraction,
                                                                                  &offset_est, &count_est);
 
+               /*
+                * If we have a known LIMIT, and don't have an unknown OFFSET, we can
+                * estimate the effects of using a bounded sort.
+                */
+               if (count_est > 0 && offset_est >= 0)
+                       limit_tuples = (double) count_est + (double) offset_est;
+       }
+
        if (parse->setOperations)
        {
                List       *set_sortclauses;
@@ -671,9 +776,10 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                 * operation's result.  We have to do this before overwriting the sort
                 * key information...
                 */
-               current_pathkeys = make_pathkeys_for_sortclauses(set_sortclauses,
-                                                                                                       result_plan->targetlist);
-               current_pathkeys = canonicalize_pathkeys(root, current_pathkeys);
+               current_pathkeys = make_pathkeys_for_sortclauses(root,
+                                                                                                                set_sortclauses,
+                                                                                                        result_plan->targetlist,
+                                                                                                                true);
 
                /*
                 * We should not need to call preprocess_targetlist, since we must be
@@ -698,9 +804,10 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                /*
                 * Calculate pathkeys that represent result ordering requirements
                 */
-               sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause,
-                                                                                                         tlist);
-               sort_pathkeys = canonicalize_pathkeys(root, sort_pathkeys);
+               sort_pathkeys = make_pathkeys_for_sortclauses(root,
+                                                                                                         parse->sortClause,
+                                                                                                         tlist,
+                                                                                                         true);
        }
        else
        {
@@ -708,6 +815,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                List       *sub_tlist;
                List       *group_pathkeys;
                AttrNumber *groupColIdx = NULL;
+               Oid                *groupOperators = NULL;
                bool            need_tlist_eval = true;
                QualCost        tlist_cost;
                Path       *cheapest_path;
@@ -733,12 +841,18 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                /*
                 * Calculate pathkeys that represent grouping/ordering requirements.
                 * Stash them in PlannerInfo so that query_planner can canonicalize
-                * them.
+                * them after EquivalenceClasses have been formed.
                 */
                root->group_pathkeys =
-                       make_pathkeys_for_sortclauses(parse->groupClause, tlist);
+                       make_pathkeys_for_sortclauses(root,
+                                                                                 parse->groupClause,
+                                                                                 tlist,
+                                                                                 false);
                root->sort_pathkeys =
-                       make_pathkeys_for_sortclauses(parse->sortClause, tlist);
+                       make_pathkeys_for_sortclauses(root,
+                                                                                 parse->sortClause,
+                                                                                 tlist,
+                                                                                 false);
 
                /*
                 * Will need actual number of aggregates for estimating costs.
@@ -780,21 +894,24 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                 * estimate the number of groups in the query, and canonicalize all
                 * the pathkeys.
                 */
-               query_planner(root, sub_tlist, tuple_fraction,
+               query_planner(root, sub_tlist, tuple_fraction, limit_tuples,
                                          &cheapest_path, &sorted_path, &dNumGroups);
 
                group_pathkeys = root->group_pathkeys;
                sort_pathkeys = root->sort_pathkeys;
 
                /*
-                * If grouping, decide whether we want to use hashed grouping.
+                * If grouping, extract the grouping operators and decide whether we
+                * want to use hashed grouping.
                 */
                if (parse->groupClause)
                {
+                       groupOperators = extract_grouping_ops(parse->groupClause);
                        use_hashed_grouping =
-                               choose_hashed_grouping(root, tuple_fraction,
+                               choose_hashed_grouping(root, tuple_fraction, limit_tuples,
                                                                           cheapest_path, sorted_path,
-                                                                          dNumGroups, &agg_counts);
+                                                                          groupOperators, dNumGroups,
+                                                                          &agg_counts);
 
                        /* Also convert # groups to long int --- but 'ware overflow! */
                        numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
@@ -852,7 +969,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                 */
                                if (!is_projection_capable_plan(result_plan))
                                {
-                                       result_plan = (Plan *) make_result(sub_tlist, NULL,
+                                       result_plan = (Plan *) make_result(root,
+                                                                                                          sub_tlist,
+                                                                                                          NULL,
                                                                                                           result_plan);
                                }
                                else
@@ -883,7 +1002,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                 * tuples) --- so make_agg() and make_group() are responsible
                                 * for computing the added cost.
                                 */
-                               cost_qual_eval(&tlist_cost, sub_tlist);
+                               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;
@@ -914,6 +1033,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                                AGG_HASHED,
                                                                                                numGroupCols,
                                                                                                groupColIdx,
+                                                                                               groupOperators,
                                                                                                numGroups,
                                                                                                agg_counts.numAggs,
                                                                                                result_plan);
@@ -957,6 +1077,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                                aggstrategy,
                                                                                                numGroupCols,
                                                                                                groupColIdx,
+                                                                                               groupOperators,
                                                                                                numGroups,
                                                                                                agg_counts.numAggs,
                                                                                                result_plan);
@@ -985,6 +1106,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                                  (List *) parse->havingQual,
                                                                                                  numGroupCols,
                                                                                                  groupColIdx,
+                                                                                                 groupOperators,
                                                                                                  dNumGroups,
                                                                                                  result_plan);
                                /* The Group node won't change sort ordering */
@@ -1003,7 +1125,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                 * this routine to avoid having to generate the plan in the
                                 * first place.
                                 */
-                               result_plan = (Plan *) make_result(tlist,
+                               result_plan = (Plan *) make_result(root,
+                                                                                                  tlist,
                                                                                                   parse->havingQual,
                                                                                                   NULL);
                        }
@@ -1018,10 +1141,10 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
        {
                if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys))
                {
-                       result_plan = (Plan *)
-                               make_sort_from_sortclauses(root,
-                                                                                  parse->sortClause,
-                                                                                  result_plan);
+                       result_plan = (Plan *) make_sort_from_pathkeys(root,
+                                                                                                                  result_plan,
+                                                                                                                  sort_pathkeys,
+                                                                                                                  limit_tuples);
                        current_pathkeys = sort_pathkeys;
                }
        }
@@ -1054,6 +1177,31 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                  count_est);
        }
 
+       /*
+        * 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).
+        */
+       if (parse->returningList)
+       {
+               List       *rlist;
+
+               Assert(parse->resultRelation);
+               rlist = set_returning_clause_references(root->glob,
+                                                                                               parse->returningList,
+                                                                                               result_plan,
+                                                                                               parse->resultRelation);
+               root->returningLists = list_make1(rlist);
+       }
+       else
+               root->returningLists = NIL;
+
+       /* 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.
@@ -1063,6 +1211,35 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
        return result_plan;
 }
 
+/*
+ * 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.
+ */
+static bool
+is_dummy_plan(Plan *plan)
+{
+       if (IsA(plan, Result))
+       {
+               List       *rcqual = (List *) ((Result *) plan)->resconstantqual;
+
+               if (list_length(rcqual) == 1)
+               {
+                       Const      *constqual = (Const *) linitial(rcqual);
+
+                       if (constqual && IsA(constqual, Const))
+                       {
+                               if (!constqual->constisnull &&
+                                       !DatumGetBool(constqual->constvalue))
+                                       return true;
+                       }
+               }
+       }
+       return false;
+}
+
 /*
  * preprocess_limit - do pre-estimation for LIMIT and/or OFFSET clauses
  *
@@ -1082,7 +1259,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
  */
 static double
 preprocess_limit(PlannerInfo *root, double tuple_fraction,
-                                int *offset_est, int *count_est)
+                                int64 *offset_est, int64 *count_est)
 {
        Query      *parse = root->parse;
        Node       *est;
@@ -1097,7 +1274,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
         */
        if (parse->limitCount)
        {
-               est = estimate_expression_value(parse->limitCount);
+               est = estimate_expression_value(root, parse->limitCount);
                if (est && IsA(est, Const))
                {
                        if (((Const *) est)->constisnull)
@@ -1107,7 +1284,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
                        }
                        else
                        {
-                               *count_est = DatumGetInt32(((Const *) est)->constvalue);
+                               *count_est = DatumGetInt64(((Const *) est)->constvalue);
                                if (*count_est <= 0)
                                        *count_est = 1;         /* force to at least 1 */
                        }
@@ -1120,7 +1297,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
 
        if (parse->limitOffset)
        {
-               est = estimate_expression_value(parse->limitOffset);
+               est = estimate_expression_value(root, parse->limitOffset);
                if (est && IsA(est, Const))
                {
                        if (((Const *) est)->constisnull)
@@ -1130,7 +1307,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
                        }
                        else
                        {
-                               *offset_est = DatumGetInt32(((Const *) est)->constvalue);
+                               *offset_est = DatumGetInt64(((Const *) est)->constvalue);
                                if (*offset_est < 0)
                                        *offset_est = 0;        /* less than 0 is same as 0 */
                        }
@@ -1251,13 +1428,43 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
        return tuple_fraction;
 }
 
+/*
+ * extract_grouping_ops - make an array of the equality operator OIDs
+ *             for the GROUP BY clause
+ */
+static Oid *
+extract_grouping_ops(List *groupClause)
+{
+       int                     numCols = list_length(groupClause);
+       int                     colno = 0;
+       Oid                *groupOperators;
+       ListCell   *glitem;
+
+       groupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
+
+       foreach(glitem, groupClause)
+       {
+               GroupClause *groupcl = (GroupClause *) lfirst(glitem);
+
+               groupOperators[colno] = get_equality_op_for_ordering_op(groupcl->sortop);
+               if (!OidIsValid(groupOperators[colno])) /* shouldn't happen */
+                       elog(ERROR, "could not find equality operator for ordering operator %u",
+                                groupcl->sortop);
+               colno++;
+       }
+
+       return groupOperators;
+}
+
 /*
  * choose_hashed_grouping - should we use hashed grouping?
  */
 static bool
-choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
+choose_hashed_grouping(PlannerInfo *root,
+                                          double tuple_fraction, double limit_tuples,
                                           Path *cheapest_path, Path *sorted_path,
-                                          double dNumGroups, AggClauseCounts *agg_counts)
+                                          Oid *groupOperators, double dNumGroups,
+                                          AggClauseCounts *agg_counts)
 {
        int                     numGroupCols = list_length(root->parse->groupClause);
        double          cheapest_path_rows;
@@ -1266,10 +1473,13 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
        List       *current_pathkeys;
        Path            hashed_p;
        Path            sorted_p;
+       int                     i;
 
        /*
         * Check can't-do-it conditions, including whether the grouping operators
-        * are hashjoinable.
+        * are hashjoinable.  (We assume hashing is OK if they are marked
+        * oprcanhash.  If there isn't actually a supporting hash function, the
+        * executor will complain at runtime.)
         *
         * Executor doesn't support hashed aggregation with DISTINCT aggregates.
         * (Doing so would imply storing *all* the input values in the hash table,
@@ -1279,8 +1489,11 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
                return false;
        if (agg_counts->numDistinctAggs != 0)
                return false;
-       if (!hash_safe_grouping(root))
-               return false;
+       for (i = 0; i < numGroupCols; i++)
+       {
+               if (!op_hashjoinable(groupOperators[i]))
+                       return false;
+       }
 
        /*
         * Don't do it if it doesn't look like the hashtable will fit into
@@ -1333,7 +1546,7 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
        /* Result of hashed agg is always unsorted */
        if (root->sort_pathkeys)
                cost_sort(&hashed_p, root, root->sort_pathkeys, hashed_p.total_cost,
-                                 dNumGroups, cheapest_path_width);
+                                 dNumGroups, cheapest_path_width, limit_tuples);
 
        if (sorted_path)
        {
@@ -1350,7 +1563,7 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
        if (!pathkeys_contained_in(root->group_pathkeys, current_pathkeys))
        {
                cost_sort(&sorted_p, root, root->group_pathkeys, sorted_p.total_cost,
-                                 cheapest_path_rows, cheapest_path_width);
+                                 cheapest_path_rows, cheapest_path_width, -1.0);
                current_pathkeys = root->group_pathkeys;
        }
 
@@ -1367,7 +1580,7 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
        if (root->sort_pathkeys &&
                !pathkeys_contained_in(root->sort_pathkeys, current_pathkeys))
                cost_sort(&sorted_p, root, root->sort_pathkeys, sorted_p.total_cost,
-                                 dNumGroups, cheapest_path_width);
+                                 dNumGroups, cheapest_path_width, limit_tuples);
 
        /*
         * Now make the decision using the top-level tuple fraction.  First we
@@ -1385,36 +1598,6 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
        return false;
 }
 
-/*
- * hash_safe_grouping - are grouping operators hashable?
- *
- * We assume hashed aggregation will work if the datatype's equality operator
- * is marked hashjoinable.
- */
-static bool
-hash_safe_grouping(PlannerInfo *root)
-{
-       ListCell   *gl;
-
-       foreach(gl, root->parse->groupClause)
-       {
-               GroupClause *grpcl = (GroupClause *) lfirst(gl);
-               TargetEntry *tle = get_sortgroupclause_tle(grpcl,
-                                                                                                  root->parse->targetList);
-               Operator        optup;
-               bool            oprcanhash;
-
-               optup = equality_oper(exprType((Node *) tle->expr), true);
-               if (!optup)
-                       return false;
-               oprcanhash = ((Form_pg_operator) GETSTRUCT(optup))->oprcanhash;
-               ReleaseSysCache(optup);
-               if (!oprcanhash)
-                       return false;
-       }
-       return true;
-}
-
 /*---------------
  * make_subplanTargetList
  *       Generate appropriate target list when grouping is required.
@@ -1440,7 +1623,7 @@ hash_safe_grouping(PlannerInfo *root)
  * 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
- * replace_vars_with_subplan_refs() in setrefs.c.)
+ * fix_upper_expr() in setrefs.c.)
  *
  * If we are grouping or aggregating, *and* there are no non-Var grouping
  * expressions, then the returned tlist is effectively dummy; we do not