aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c158
1 files changed, 122 insertions, 36 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 1b481ccbd25..f01b9feffe2 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.142 2003/01/25 23:10:27 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.143 2003/02/03 15:07:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -55,7 +55,11 @@ static Plan *inheritance_planner(Query *parse, List *inheritlist);
static Plan *grouping_planner(Query *parse, double tuple_fraction);
static bool hash_safe_grouping(Query *parse);
static List *make_subplanTargetList(Query *parse, List *tlist,
- AttrNumber **groupColIdx);
+ AttrNumber **groupColIdx, bool *need_tlist_eval);
+static void locate_grouping_columns(Query *parse,
+ List *tlist,
+ List *sub_tlist,
+ AttrNumber *groupColIdx);
static Plan *make_groupsortplan(Query *parse,
List *groupClause,
AttrNumber *grpColIdx,
@@ -530,6 +534,7 @@ grouping_planner(Query *parse, double tuple_fraction)
List *sub_tlist;
List *group_pathkeys;
AttrNumber *groupColIdx = NULL;
+ bool need_tlist_eval = true;
QualCost tlist_cost;
double sub_tuple_fraction;
Path *cheapest_path;
@@ -602,7 +607,8 @@ grouping_planner(Query *parse, double tuple_fraction)
* Generate appropriate target list for subplan; may be different
* from tlist if grouping or aggregation is needed.
*/
- sub_tlist = make_subplanTargetList(parse, tlist, &groupColIdx);
+ sub_tlist = make_subplanTargetList(parse, tlist,
+ &groupColIdx, &need_tlist_eval);
/*
* Calculate pathkeys that represent grouping/ordering
@@ -1003,45 +1009,65 @@ grouping_planner(Query *parse, double tuple_fraction)
/*
* create_plan() returns a plan with just a "flat" tlist of required
- * Vars. We want to insert the sub_tlist as the tlist of the top
- * plan node. If the top-level plan node is one that cannot do
- * expression evaluation, we must insert a Result node to project the
- * desired tlist.
- * Currently, the only plan node we might see here that falls into
- * that category is Append.
+ * 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.
*/
- if (IsA(result_plan, Append))
+ if (need_tlist_eval)
{
- result_plan = (Plan *) make_result(sub_tlist, NULL, result_plan);
+ /*
+ * If the top-level plan node is one that cannot do expression
+ * evaluation, we must insert a Result node to project the desired
+ * tlist.
+ * Currently, the only plan node we might see here that falls into
+ * that category is Append.
+ */
+ if (IsA(result_plan, Append))
+ {
+ result_plan = (Plan *) make_result(sub_tlist, NULL,
+ result_plan);
+ }
+ else
+ {
+ /*
+ * Otherwise, just replace the subplan's flat tlist with
+ * the desired tlist.
+ */
+ result_plan->targetlist = sub_tlist;
+ }
+ /*
+ * 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 and Group project new tlists
+ * (the rest just copy their input tuples) --- so make_agg() and
+ * make_group() are responsible for computing the added cost.
+ */
+ cost_qual_eval(&tlist_cost, sub_tlist);
+ result_plan->startup_cost += tlist_cost.startup;
+ result_plan->total_cost += tlist_cost.startup +
+ tlist_cost.per_tuple * result_plan->plan_rows;
}
else
{
/*
- * Otherwise, just replace the flat tlist with the desired tlist.
+ * Since we're using query_planner's tlist and not the one
+ * make_subplanTargetList calculated, we have to refigure
+ * any grouping-column indexes make_subplanTargetList computed.
*/
- result_plan->targetlist = sub_tlist;
+ locate_grouping_columns(parse, tlist, result_plan->targetlist,
+ groupColIdx);
}
- /*
- * 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 and Group project new tlists
- * (the rest just copy their input tuples) --- so make_agg() and
- * make_group() are responsible for computing the added cost.
- */
- cost_qual_eval(&tlist_cost, sub_tlist);
- result_plan->startup_cost += tlist_cost.startup;
- result_plan->total_cost += tlist_cost.startup +
- tlist_cost.per_tuple * result_plan->plan_rows;
/*
* Insert AGG or GROUP node if needed, plus an explicit sort step
@@ -1245,10 +1271,17 @@ hash_safe_grouping(Query *parse)
* the extra computation to recompute a+b at the outer level; see
* replace_vars_with_subplan_refs() 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
+ * need to force it to be evaluated, because all the Vars it contains
+ * should be present in the output of query_planner anyway.
+ *
* 'parse' is the query being processed.
* '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 subplan's target list.
+ * 'need_tlist_eval' is set true if we really need to evaluate the
+ * result tlist.
*
* The result is the targetlist to be passed to the subplan.
*---------------
@@ -1256,7 +1289,8 @@ hash_safe_grouping(Query *parse)
static List *
make_subplanTargetList(Query *parse,
List *tlist,
- AttrNumber **groupColIdx)
+ AttrNumber **groupColIdx,
+ bool *need_tlist_eval)
{
List *sub_tlist;
List *extravars;
@@ -1269,7 +1303,10 @@ make_subplanTargetList(Query *parse,
* query_planner should receive the unmodified target list.
*/
if (!parse->hasAggs && !parse->groupClause && !parse->havingQual)
+ {
+ *need_tlist_eval = true;
return tlist;
+ }
/*
* Otherwise, start with a "flattened" tlist (having just the vars
@@ -1280,6 +1317,7 @@ make_subplanTargetList(Query *parse,
extravars = pull_var_clause(parse->havingQual, false);
sub_tlist = add_to_flat_tlist(sub_tlist, extravars);
freeList(extravars);
+ *need_tlist_eval = false; /* only eval if not flat tlist */
/*
* If grouping, create sub_tlist entries for all GROUP BY expressions
@@ -1320,6 +1358,7 @@ make_subplanTargetList(Query *parse,
false),
(Expr *) groupexpr);
sub_tlist = lappend(sub_tlist, te);
+ *need_tlist_eval = true; /* it's not flat anymore */
}
/* and save its resno */
@@ -1331,6 +1370,53 @@ make_subplanTargetList(Query *parse,
}
/*
+ * locate_grouping_columns
+ * Locate grouping columns in the tlist chosen by query_planner.
+ *
+ * This is only needed if we don't use the sub_tlist chosen by
+ * make_subplanTargetList. We have to forget the column indexes found
+ * by that routine and re-locate the grouping vars in the real sub_tlist.
+ */
+static void
+locate_grouping_columns(Query *parse,
+ List *tlist,
+ List *sub_tlist,
+ AttrNumber *groupColIdx)
+{
+ int keyno = 0;
+ List *gl;
+
+ /*
+ * No work unless grouping.
+ */
+ if (!parse->groupClause)
+ {
+ Assert(groupColIdx == NULL);
+ return;
+ }
+ Assert(groupColIdx != NULL);
+
+ foreach(gl, parse->groupClause)
+ {
+ GroupClause *grpcl = (GroupClause *) lfirst(gl);
+ Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist);
+ TargetEntry *te = NULL;
+ List *sl;
+
+ foreach(sl, sub_tlist)
+ {
+ te = (TargetEntry *) lfirst(sl);
+ if (equal(groupexpr, te->expr))
+ break;
+ }
+ if (!sl)
+ elog(ERROR, "locate_grouping_columns: failed");
+
+ groupColIdx[keyno++] = te->resdom->resno;
+ }
+}
+
+/*
* make_groupsortplan
* Add a Sort node to explicitly sort according to the GROUP BY clause.
*