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.c222
1 files changed, 115 insertions, 107 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 1896982f02e..c2aec37470a 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.157 2003/07/25 00:01:07 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.158 2003/08/04 00:43:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -45,10 +45,10 @@
/* Expression kind codes for preprocess_expression */
#define EXPRKIND_QUAL 0
-#define EXPRKIND_TARGET 1
-#define EXPRKIND_RTFUNC 2
+#define EXPRKIND_TARGET 1
+#define EXPRKIND_RTFUNC 2
#define EXPRKIND_LIMIT 3
-#define EXPRKIND_ININFO 4
+#define EXPRKIND_ININFO 4
static Node *preprocess_expression(Query *parse, Node *expr, int kind);
@@ -59,9 +59,9 @@ static bool hash_safe_grouping(Query *parse);
static List *make_subplanTargetList(Query *parse, List *tlist,
AttrNumber **groupColIdx, bool *need_tlist_eval);
static void locate_grouping_columns(Query *parse,
- List *tlist,
- List *sub_tlist,
- AttrNumber *groupColIdx);
+ List *tlist,
+ List *sub_tlist,
+ AttrNumber *groupColIdx);
static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
@@ -103,9 +103,9 @@ planner(Query *parse, bool isCursor, int cursorOptions)
{
/*
* We have no real idea how many tuples the user will ultimately
- * FETCH from a cursor, but it seems a good bet that he
- * doesn't want 'em all. Optimize for 10% retrieval (you
- * gotta better number? Should this be a SETtable parameter?)
+ * FETCH from a cursor, but it seems a good bet that he doesn't
+ * want 'em all. Optimize for 10% retrieval (you gotta better
+ * number? Should this be a SETtable parameter?)
*/
tuple_fraction = 0.10;
}
@@ -121,8 +121,8 @@ planner(Query *parse, bool isCursor, int cursorOptions)
Assert(PlannerQueryLevel == 0);
/*
- * 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 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))
{
@@ -181,14 +181,14 @@ subquery_planner(Query *parse, double tuple_fraction)
/*
* Look for IN clauses at the top level of WHERE, and transform them
- * into joins. Note that this step only handles IN clauses originally
- * at top level of WHERE; if we pull up any subqueries in the next step,
- * their INs are processed just before pulling them up.
+ * into joins. Note that this step only handles IN clauses originally
+ * at top level of WHERE; if we pull up any subqueries in the next
+ * step, their INs are processed just before pulling them up.
*/
parse->in_info_list = NIL;
if (parse->hasSubLinks)
parse->jointree->quals = pull_up_IN_clauses(parse,
- parse->jointree->quals);
+ parse->jointree->quals);
/*
* Check to see if any subqueries in the rangetable can be merged into
@@ -198,10 +198,11 @@ subquery_planner(Query *parse, double tuple_fraction)
pull_up_subqueries(parse, (Node *) parse->jointree, false);
/*
- * 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.
+ * 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.
*/
parse->hasJoinRTEs = false;
hasOuterJoins = false;
@@ -283,19 +284,20 @@ subquery_planner(Query *parse, double tuple_fraction)
parse->havingQual = (Node *) newHaving;
/*
- * If we have any outer joins, try to reduce them to plain inner joins.
- * This step is most easily done after we've done expression preprocessing.
+ * If we have any outer joins, try to reduce them to plain inner
+ * joins. This step is most easily done after we've done expression
+ * preprocessing.
*/
if (hasOuterJoins)
reduce_outer_joins(parse);
/*
- * See if we can simplify the jointree; opportunities for this may come
- * from having pulled up subqueries, or from flattening explicit JOIN
- * syntax. We must do this after flattening JOIN alias variables, since
- * eliminating explicit JOIN nodes from the jointree will cause
- * get_relids_for_join() to fail. But it should happen after
- * reduce_outer_joins, anyway.
+ * See if we can simplify the jointree; opportunities for this may
+ * come from having pulled up subqueries, or from flattening explicit
+ * JOIN syntax. We must do this after flattening JOIN alias
+ * variables, since eliminating explicit JOIN nodes from the jointree
+ * will cause get_relids_for_join() to fail. But it should happen
+ * after reduce_outer_joins, anyway.
*/
parse->jointree = (FromExpr *)
simplify_jointree(parse, (Node *) parse->jointree);
@@ -318,26 +320,26 @@ subquery_planner(Query *parse, double tuple_fraction)
*/
if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1)
{
- Cost initplan_cost = 0;
+ Cost initplan_cost = 0;
/* Prepare extParam/allParam sets for all nodes in tree */
SS_finalize_plan(plan, parse->rtable);
/*
- * SS_finalize_plan doesn't handle initPlans, so we have to manually
- * attach them to the topmost plan node, and add their extParams to
- * the topmost node's, too.
+ * SS_finalize_plan doesn't handle initPlans, so we have to
+ * manually attach them to the topmost plan node, and add their
+ * extParams to the topmost node's, too.
*
- * We also add the total_cost of each initPlan to the startup cost
- * of the top node. This is a conservative overestimate, since in
- * fact each initPlan might be executed later than plan startup, or
- * even not at all.
+ * We also add the total_cost of each initPlan to the startup cost of
+ * the top node. This is a conservative overestimate, since in
+ * fact each initPlan might be executed later than plan startup,
+ * or even not at all.
*/
plan->initPlan = PlannerInitPlan;
foreach(lst, plan->initPlan)
{
- SubPlan *initplan = (SubPlan *) lfirst(lst);
+ SubPlan *initplan = (SubPlan *) lfirst(lst);
plan->extParam = bms_add_members(plan->extParam,
initplan->plan->extParam);
@@ -368,7 +370,8 @@ preprocess_expression(Query *parse, 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.
*/
if (parse->hasJoinRTEs)
expr = flatten_join_alias_vars(parse, expr);
@@ -403,8 +406,8 @@ preprocess_expression(Query *parse, Node *expr, int kind)
expr = SS_process_sublinks(expr, (kind == EXPRKIND_QUAL));
/*
- * XXX do not insert anything here unless you have grokked the comments
- * in SS_replace_correlation_vars ...
+ * XXX do not insert anything here unless you have grokked the
+ * comments in SS_replace_correlation_vars ...
*/
/* Replace uplevel vars with Param nodes */
@@ -498,20 +501,21 @@ inheritance_planner(Query *parse, List *inheritlist)
/* Generate plan */
subplan = grouping_planner(subquery, 0.0 /* retrieve all tuples */ );
subplans = lappend(subplans, subplan);
+
/*
* It's possible that additional RTEs got added to the rangetable
* due to expansion of inherited source tables (see allpaths.c).
* If so, we must copy 'em back to the main parse tree's rtable.
*
- * XXX my goodness this is ugly. Really need to think about ways
- * to rein in planner's habit of scribbling on its input.
+ * XXX my goodness this is ugly. Really need to think about ways to
+ * rein in planner's habit of scribbling on its input.
*/
subrtlength = length(subquery->rtable);
if (subrtlength > mainrtlength)
{
- List *subrt = subquery->rtable;
+ List *subrt = subquery->rtable;
- while (mainrtlength-- > 0) /* wish we had nthcdr() */
+ while (mainrtlength-- > 0) /* wish we had nthcdr() */
subrt = lnext(subrt);
parse->rtable = nconc(parse->rtable, subrt);
mainrtlength = subrtlength;
@@ -684,7 +688,7 @@ grouping_planner(Query *parse, double tuple_fraction)
* from tlist if grouping or aggregation is needed.
*/
sub_tlist = make_subplanTargetList(parse, tlist,
- &groupColIdx, &need_tlist_eval);
+ &groupColIdx, &need_tlist_eval);
/*
* Calculate pathkeys that represent grouping/ordering
@@ -700,8 +704,8 @@ grouping_planner(Query *parse, double tuple_fraction)
* Also, it's possible that optimization has eliminated all
* aggregates, and we may as well check for that here.
*
- * Note: we do not attempt to detect duplicate aggregates here;
- * a somewhat-overestimated count is okay for our present purposes.
+ * Note: we do not attempt to detect duplicate aggregates here; a
+ * somewhat-overestimated count is okay for our present purposes.
*/
if (parse->hasAggs)
{
@@ -892,8 +896,8 @@ grouping_planner(Query *parse, double tuple_fraction)
&cheapest_path, &sorted_path);
/*
- * We couldn't canonicalize group_pathkeys and sort_pathkeys before
- * running query_planner(), so do it now.
+ * We couldn't canonicalize group_pathkeys and sort_pathkeys
+ * before running query_planner(), so do it now.
*/
group_pathkeys = canonicalize_pathkeys(parse, group_pathkeys);
sort_pathkeys = canonicalize_pathkeys(parse, sort_pathkeys);
@@ -903,9 +907,9 @@ grouping_planner(Query *parse, double tuple_fraction)
*/
if (parse->groupClause)
{
- List *groupExprs;
- double cheapest_path_rows;
- int cheapest_path_width;
+ List *groupExprs;
+ double cheapest_path_rows;
+ int cheapest_path_width;
/*
* Beware in this section of the possibility that
@@ -919,13 +923,13 @@ grouping_planner(Query *parse, double tuple_fraction)
}
else
{
- cheapest_path_rows = 1; /* assume non-set result */
- cheapest_path_width = 100; /* arbitrary */
+ cheapest_path_rows = 1; /* assume non-set result */
+ cheapest_path_width = 100; /* arbitrary */
}
/*
- * Always estimate the number of groups. We can't do this until
- * after running query_planner(), either.
+ * Always estimate the number of groups. We can't do this
+ * until after running query_planner(), either.
*/
groupExprs = get_sortgrouplist_exprs(parse->groupClause,
parse->targetList);
@@ -936,12 +940,13 @@ grouping_planner(Query *parse, double tuple_fraction)
numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
/*
- * Check can't-do-it conditions, including whether the grouping
- * operators are hashjoinable.
+ * Check can't-do-it conditions, including whether the
+ * grouping operators are hashjoinable.
*
* Executor doesn't support hashed aggregation with DISTINCT
- * aggregates. (Doing so would imply storing *all* the input
- * values in the hash table, which seems like a certain loser.)
+ * aggregates. (Doing so would imply storing *all* the input
+ * values in the hash table, which seems like a certain
+ * loser.)
*/
if (!enable_hashagg || !hash_safe_grouping(parse))
use_hashed_grouping = false;
@@ -953,32 +958,30 @@ grouping_planner(Query *parse, double tuple_fraction)
{
/*
* Use hashed grouping if (a) we think we can fit the
- * hashtable into SortMem, *and* (b) the estimated cost
- * is no more than doing it the other way. While avoiding
+ * hashtable into SortMem, *and* (b) the estimated cost is
+ * no more than doing it the other way. While avoiding
* the need for sorted input is usually a win, the fact
* that the output won't be sorted may be a loss; so we
* need to do an actual cost comparison.
*
* In most cases we have no good way to estimate the size of
- * the transition value needed by an aggregate; arbitrarily
- * assume it is 100 bytes. Also set the overhead per hashtable
- * entry at 64 bytes.
+ * the transition value needed by an aggregate;
+ * arbitrarily assume it is 100 bytes. Also set the
+ * overhead per hashtable entry at 64 bytes.
*/
- int hashentrysize = cheapest_path_width + 64 + numAggs * 100;
+ int hashentrysize = cheapest_path_width + 64 + numAggs * 100;
if (hashentrysize * dNumGroups <= SortMem * 1024L)
{
/*
* Okay, do the cost comparison. We need to consider
- * cheapest_path + hashagg [+ final sort]
- * versus either
- * cheapest_path [+ sort] + group or agg [+ final sort]
- * or
- * presorted_path + group or agg [+ final sort]
- * where brackets indicate a step that may not be needed.
- * We assume query_planner() will have returned a
- * presorted path only if it's a winner compared to
- * cheapest_path for this purpose.
+ * cheapest_path + hashagg [+ final sort] versus
+ * either cheapest_path [+ sort] + group or agg [+
+ * final sort] or presorted_path + group or agg [+
+ * final sort] where brackets indicate a step that may
+ * not be needed. We assume query_planner() will have
+ * returned a presorted path only if it's a winner
+ * compared to cheapest_path for this purpose.
*
* These path variables are dummies that just hold cost
* fields; we don't make actual Paths for these steps.
@@ -1065,9 +1068,9 @@ grouping_planner(Query *parse, double tuple_fraction)
/*
* Select the best path and create a plan to execute it.
*
- * If we are doing hashed grouping, we will always read all the
- * input tuples, so use the cheapest-total path. Otherwise,
- * trust query_planner's decision about which to use.
+ * If we are doing hashed grouping, we will always read all the input
+ * tuples, so use the cheapest-total path. Otherwise, trust
+ * query_planner's decision about which to use.
*/
if (sorted_path && !use_hashed_grouping)
{
@@ -1081,19 +1084,19 @@ grouping_planner(Query *parse, double tuple_fraction)
}
/*
- * 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 query_planner chose to return will be
+ * good enough.
*/
if (need_tlist_eval)
{
/*
* 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.
+ * 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))
{
@@ -1108,23 +1111,25 @@ grouping_planner(Query *parse, double tuple_fraction)
*/
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.
+ * 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.
+ * 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;
@@ -1135,8 +1140,8 @@ grouping_planner(Query *parse, double tuple_fraction)
{
/*
* 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.
+ * make_subplanTargetList calculated, we have to refigure any
+ * grouping-column indexes make_subplanTargetList computed.
*/
locate_grouping_columns(parse, tlist, result_plan->targetlist,
groupColIdx);
@@ -1180,6 +1185,7 @@ grouping_planner(Query *parse, double tuple_fraction)
current_pathkeys = group_pathkeys;
}
aggstrategy = AGG_SORTED;
+
/*
* The AGG node will not change the sort ordering of its
* groups, so current_pathkeys describes the result too.
@@ -1205,7 +1211,8 @@ grouping_planner(Query *parse, double tuple_fraction)
else
{
/*
- * If there are no Aggs, we shouldn't have any HAVING qual anymore
+ * If there are no Aggs, we shouldn't have any HAVING qual
+ * anymore
*/
Assert(parse->havingQual == NULL);
@@ -1216,8 +1223,8 @@ grouping_planner(Query *parse, double tuple_fraction)
if (parse->groupClause)
{
/*
- * Add an explicit sort if we couldn't make the path come out
- * the way the GROUP node needs it.
+ * Add an explicit sort if we couldn't make the path come
+ * out the way the GROUP node needs it.
*/
if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))
{
@@ -1238,7 +1245,7 @@ grouping_planner(Query *parse, double tuple_fraction)
/* The Group node won't change sort ordering */
}
}
- } /* end of if (setOperations) */
+ } /* end of if (setOperations) */
/*
* If we were not able to make the plan come out in the right order,
@@ -1264,6 +1271,7 @@ grouping_planner(Query *parse, double tuple_fraction)
{
result_plan = (Plan *) make_unique(tlist, result_plan,
parse->distinctClause);
+
/*
* If there was grouping or aggregation, leave plan_rows as-is
* (ie, assume the result was already mostly unique). If not,
@@ -1272,13 +1280,13 @@ grouping_planner(Query *parse, double tuple_fraction)
*/
if (!parse->groupClause && !parse->hasAggs)
{
- List *distinctExprs;
+ List *distinctExprs;
distinctExprs = get_sortgrouplist_exprs(parse->distinctClause,
parse->targetList);
result_plan->plan_rows = estimate_num_groups(parse,
distinctExprs,
- result_plan->plan_rows);
+ result_plan->plan_rows);
}
}
@@ -1443,7 +1451,7 @@ make_subplanTargetList(Query *parse,
false),
(Expr *) groupexpr);
sub_tlist = lappend(sub_tlist, te);
- *need_tlist_eval = true; /* it's not flat anymore */
+ *need_tlist_eval = true; /* it's not flat anymore */
}
/* and save its resno */
@@ -1459,7 +1467,7 @@ make_subplanTargetList(Query *parse,
* 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
+ * 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
@@ -1528,7 +1536,7 @@ postprocess_setop_tlist(List *new_tlist, List *orig_tlist)
Assert(orig_tlist != NIL);
orig_tle = (TargetEntry *) lfirst(orig_tlist);
orig_tlist = lnext(orig_tlist);
- if (orig_tle->resdom->resjunk) /* should not happen */
+ if (orig_tle->resdom->resjunk) /* should not happen */
elog(ERROR, "resjunk output columns are not implemented");
Assert(new_tle->resdom->resno == orig_tle->resdom->resno);
Assert(new_tle->resdom->restype == orig_tle->resdom->restype);