]> 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 b66a508c22da934e96771c99a0a5010dc6c64177..385e64647ea0dea00c15889064421a01ad2dab79 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <limits.h>
 
+#include "access/htup_details.h"
 #include "executor/executor.h"
 #include "executor/nodeAgg.h"
 #include "miscadmin.h"
@@ -48,12 +49,15 @@ 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);
@@ -151,7 +155,6 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        glob = makeNode(PlannerGlobal);
 
        glob->boundParams = boundParams;
-       glob->paramlist = NIL;
        glob->subplans = NIL;
        glob->subroots = NIL;
        glob->rewindPlanIDs = NULL;
@@ -160,6 +163,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        glob->resultRelations = NIL;
        glob->relationOids = NIL;
        glob->invalItems = NIL;
+       glob->nParamExec = 0;
        glob->lastPHId = 0;
        glob->lastRowMarkId = 0;
        glob->transientPlan = false;
@@ -225,6 +229,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        result = makeNode(PlannedStmt);
 
        result->commandType = parse->commandType;
+       result->queryId = parse->queryId;
        result->hasReturning = (parse->returningList != NIL);
        result->hasModifyingCTE = parse->hasModifyingCTE;
        result->canSetTag = parse->canSetTag;
@@ -233,13 +238,12 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        result->rtable = glob->finalrtable;
        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;
 }
@@ -291,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;
@@ -334,7 +339,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
         * 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
@@ -348,10 +353,12 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
        /*
         * 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)
        {
@@ -361,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;
        }
 
        /*
@@ -436,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);
+               }
        }
 
        /*
@@ -529,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,
-                                                                                                               parse->returningList,
-                                                                                                               plan,
-                                                                                                         parse->resultRelation);
-                               returningLists = list_make1(rlist);
-                       }
+                               returningLists = list_make1(parse->returningList);
                        else
                                returningLists = NIL;
 
@@ -574,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 */
@@ -588,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)
@@ -603,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);
 
        /*
@@ -704,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
@@ -772,14 +803,15 @@ inheritance_planner(PlannerInfo *root)
                 * then fool around with subquery RTEs.
                 */
                subroot.parse = (Query *)
-                       adjust_appendrel_attrs((Node *) parse,
+                       adjust_appendrel_attrs(root,
+                                                                  (Node *) parse,
                                                                   appinfo);
 
                /*
                 * 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.)
+                * 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);
 
@@ -795,10 +827,11 @@ inheritance_planner(PlannerInfo *root)
 
                /*
                 * 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.
+                * 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)
                {
@@ -811,7 +844,7 @@ inheritance_planner(PlannerInfo *root)
 
                                if (rte->rtekind == RTE_SUBQUERY)
                                {
-                                       Index   newrti;
+                                       Index           newrti;
 
                                        /*
                                         * The RTE can't contain any references to its own RT
@@ -831,12 +864,11 @@ inheritance_planner(PlannerInfo *root)
                }
 
                /* 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);
-               /* build a separate list of initplans for each child */
-               subroot.init_plans = NIL;
                /* hack to mark target relation as an inheritance partition */
                subroot.hasInheritedTarget = true;
 
@@ -862,7 +894,7 @@ inheritance_planner(PlannerInfo *root)
                else
                        final_rtable = list_concat(final_rtable,
                                                                           list_copy_tail(subroot.parse->rtable,
-                                                                                                         list_length(final_rtable)));
+                                                                                                list_length(final_rtable)));
 
                /*
                 * We need to collect all the RelOptInfos from all child plans into
@@ -883,22 +915,15 @@ inheritance_planner(PlannerInfo *root)
                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 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(&subroot,
-                                                                                               subroot.parse->returningList,
-                                                                                                       subplan,
-                                                                                                       appinfo->child_relid);
-                       returningLists = lappend(returningLists, rlist);
-               }
+                       returningLists = lappend(returningLists,
+                                                                        subroot.parse->returningList);
        }
 
        /* Mark result as unordered (probably unnecessary) */
@@ -1064,7 +1089,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                double          sub_limit_tuples;
                AttrNumber *groupColIdx = NULL;
                bool            need_tlist_eval = true;
-               QualCost        tlist_cost;
                Path       *cheapest_path;
                Path       *sorted_path;
                Path       *best_path;
@@ -1337,18 +1361,17 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                need_sort_for_grouping = true;
 
                                /*
-                                * Always override create_plan'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 create_plan 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)
                        {
@@ -1375,27 +1398,9 @@ 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
                        {
@@ -1566,7 +1571,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                         *
                         * 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
+                        * as separate targetlist entries.      Otherwise we could be putting
                         * ungrouped Vars directly into an Agg node's tlist, resulting in
                         * undefined behavior.
                         */
@@ -1835,6 +1840,61 @@ 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.
@@ -2673,8 +2733,8 @@ make_subplanTargetList(PlannerInfo *root,
        }
 
        /*
-        * Otherwise, we must build a tlist containing all grouping columns,
-        * plus any other Vars mentioned in the targetlist and HAVING qual.
+        * Otherwise, we must build a tlist containing all grouping columns, plus
+        * any other Vars mentioned in the targetlist and HAVING qual.
         */
        sub_tlist = NIL;
        non_group_cols = NIL;
@@ -2725,8 +2785,8 @@ make_subplanTargetList(PlannerInfo *root,
                        else
                        {
                                /*
-                                * Non-grouping column, so just remember the expression
-                                * for later call to pull_var_clause.  There's no need for
+                                * 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);
@@ -2753,7 +2813,7 @@ make_subplanTargetList(PlannerInfo *root,
         * 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
+        * 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,
@@ -3241,6 +3301,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
        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);
@@ -3289,7 +3350,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
        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);
@@ -3297,7 +3358,8 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
        /* Estimate the cost of index scan */
        indexScanPath = create_index_path(root, indexInfo,
                                                                          NIL, NIL, NIL, NIL, NIL,
-                                                                         ForwardScanDirection, false, NULL);
+                                                                         ForwardScanDirection, false,
+                                                                         NULL, 1.0);
 
        return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
 }