diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 213 |
1 files changed, 106 insertions, 107 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 7ad15d9da2..3f344b3a14 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.255 2009/04/28 21:31:16 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.256 2009/06/11 14:48:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -43,7 +43,7 @@ /* GUC parameter */ -double cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION; +double cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION; /* Hook for plugins to get control in planner() */ planner_hook_type planner_hook = NULL; @@ -84,18 +84,18 @@ static void locate_grouping_columns(PlannerInfo *root, static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist); static List *select_active_windows(PlannerInfo *root, WindowFuncLists *wflists); static List *add_volatile_sort_exprs(List *window_tlist, List *tlist, - List *activeWindows); + List *activeWindows); static List *make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, - List *tlist, bool canonicalize); + List *tlist, bool canonicalize); static void get_column_info_for_window(PlannerInfo *root, WindowClause *wc, - List *tlist, - int numSortCols, AttrNumber *sortColIdx, - int *partNumCols, - AttrNumber **partColIdx, - Oid **partOperators, - int *ordNumCols, - AttrNumber **ordColIdx, - Oid **ordOperators); + List *tlist, + int numSortCols, AttrNumber *sortColIdx, + int *partNumCols, + AttrNumber **partColIdx, + Oid **partOperators, + int *ordNumCols, + AttrNumber **ordColIdx, + Oid **ordOperators); /***************************************************************************** @@ -171,10 +171,9 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) tuple_fraction = cursor_tuple_fraction; /* - * We document cursor_tuple_fraction as simply being a fraction, - * which means the edge cases 0 and 1 have to be treated specially - * here. We convert 1 to 0 ("all the tuples") and 0 to a very small - * fraction. + * We document cursor_tuple_fraction as simply being a fraction, which + * means the edge cases 0 and 1 have to be treated specially here. We + * convert 1 to 0 ("all the tuples") and 0 to a very small fraction. */ if (tuple_fraction >= 1.0) tuple_fraction = 0.0; @@ -297,8 +296,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse, root->non_recursive_plan = NULL; /* - * If there is a WITH list, process each WITH query and build an - * initplan SubPlan structure for it. + * If there is a WITH list, process each WITH query and build an initplan + * SubPlan structure for it. */ if (parse->cteList) SS_process_ctes(root); @@ -313,8 +312,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse, pull_up_sublinks(root); /* - * Scan the rangetable for set-returning functions, and inline them - * if possible (producing subqueries that might get pulled up next). + * Scan the rangetable for set-returning functions, and inline them if + * possible (producing subqueries that might get pulled up next). * Recursion issues here are handled in the same way as for SubLinks. */ inline_set_returning_functions(root); @@ -329,8 +328,8 @@ 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(). This must be + * done after we have done pull_up_subqueries, of course. */ root->hasJoinRTEs = false; hasOuterJoins = false; @@ -528,7 +527,7 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind) * Simplify constant expressions. * * Note: one essential effect here is to insert the current actual values - * of any default arguments for functions. To ensure that happens, we + * of any default arguments for functions. To ensure that happens, we * *must* process all expressions here. Previous PG versions sometimes * skipped const-simplification if it didn't seem worth the trouble, but * we can't do that anymore. @@ -797,8 +796,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) /* * If there's a top-level ORDER BY, assume we have to fetch all the * tuples. This might be too simplistic given all the hackery below - * to possibly avoid the sort; but the odds of accurate estimates - * here are pretty low anyway. + * to possibly avoid the sort; but the odds of accurate estimates here + * are pretty low anyway. */ if (parse->sortClause) tuple_fraction = 0.0; @@ -908,9 +907,9 @@ 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 after EquivalenceClasses have been formed. The sortClause - * is certainly sort-able, but GROUP BY and DISTINCT might not be, - * in which case we just leave their pathkeys empty. + * them after EquivalenceClasses have been formed. The sortClause is + * certainly sort-able, but GROUP BY and DISTINCT might not be, in + * which case we just leave their pathkeys empty. */ if (parse->groupClause && grouping_is_sortable(parse->groupClause)) @@ -982,7 +981,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) * Note: if we have both ORDER BY and GROUP BY, and ORDER BY is a * superset of GROUP BY, it would be tempting to request sort by ORDER * BY --- but that might just leave us failing to exploit an available - * sort order at all. Needs more thought. The choice for DISTINCT + * sort order at all. Needs more thought. The choice for DISTINCT * versus ORDER BY is much easier, since we know that the parser * ensured that one is a superset of the other. */ @@ -1012,12 +1011,12 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) */ if (parse->groupClause) { - bool can_hash; - bool can_sort; + bool can_hash; + bool can_sort; /* * Executor doesn't support hashed aggregation with DISTINCT - * aggregates. (Doing so would imply storing *all* the input + * aggregates. (Doing so would imply storing *all* the input * values in the hash table, which seems like a certain loser.) */ can_hash = (agg_counts.numDistinctAggs == 0 && @@ -1079,16 +1078,17 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) * Normal case --- create a plan according to query_planner's * results. */ - bool need_sort_for_grouping = false; + bool need_sort_for_grouping = false; result_plan = create_plan(root, best_path); current_pathkeys = best_path->pathkeys; /* Detect if we'll need an explicit sort for grouping */ if (parse->groupClause && !use_hashed_grouping && - !pathkeys_contained_in(root->group_pathkeys, current_pathkeys)) + !pathkeys_contained_in(root->group_pathkeys, current_pathkeys)) { need_sort_for_grouping = true; + /* * Always override query_planner's tlist, so that we don't * sort useless data from a "physical" tlist. @@ -1275,9 +1275,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) } /* end of non-minmax-aggregate case */ /* - * Since each window function could require a different sort order, - * we stack up a WindowAgg node for each window, with sort steps - * between them as needed. + * Since each window function could require a different sort order, we + * stack up a WindowAgg node for each window, with sort steps between + * them as needed. */ if (activeWindows) { @@ -1286,12 +1286,12 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) /* * If the top-level plan node is one that cannot do expression - * evaluation, we must insert a Result node to project the - * desired tlist. (In some cases this might not really be - * required, but it's not worth trying to avoid it.) Note that - * on second and subsequent passes through the following loop, - * the top-level node will be a WindowAgg which we know can - * project; so we only need to check once. + * evaluation, we must insert a Result node to project the desired + * tlist. (In some cases this might not really be required, but + * it's not worth trying to avoid it.) Note that on second and + * subsequent passes through the following loop, the top-level + * node will be a WindowAgg which we know can project; so we only + * need to check once. */ if (!is_projection_capable_plan(result_plan)) { @@ -1302,21 +1302,20 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) } /* - * The "base" targetlist for all steps of the windowing process - * is a flat tlist of all Vars and Aggs needed in the result. - * (In some cases we wouldn't need to propagate all of these - * all the way to the top, since they might only be needed as - * inputs to WindowFuncs. It's probably not worth trying to - * optimize that though.) We also need any volatile sort - * expressions, because make_sort_from_pathkeys won't add those - * on its own, and anyway we want them evaluated only once at - * the bottom of the stack. As we climb up the stack, we add - * outputs for the WindowFuncs computed at each level. Also, - * each input tlist has to present all the columns needed to - * sort the data for the next WindowAgg step. That's handled - * internally by make_sort_from_pathkeys, but we need the - * copyObject steps here to ensure that each plan node has - * a separately modifiable tlist. + * The "base" targetlist for all steps of the windowing process is + * a flat tlist of all Vars and Aggs needed in the result. (In + * some cases we wouldn't need to propagate all of these all the + * way to the top, since they might only be needed as inputs to + * WindowFuncs. It's probably not worth trying to optimize that + * though.) We also need any volatile sort expressions, because + * make_sort_from_pathkeys won't add those on its own, and anyway + * we want them evaluated only once at the bottom of the stack. + * As we climb up the stack, we add outputs for the WindowFuncs + * computed at each level. Also, each input tlist has to present + * all the columns needed to sort the data for the next WindowAgg + * step. That's handled internally by make_sort_from_pathkeys, + * but we need the copyObject steps here to ensure that each plan + * node has a separately modifiable tlist. */ window_tlist = flatten_tlist(tlist); if (parse->hasAggs) @@ -1392,7 +1391,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) { /* Add the current WindowFuncs to the running tlist */ window_tlist = add_to_flat_tlist(window_tlist, - wflists->windowFuncs[wc->winref]); + wflists->windowFuncs[wc->winref]); } else { @@ -1404,7 +1403,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) result_plan = (Plan *) make_windowagg(root, (List *) copyObject(window_tlist), - list_length(wflists->windowFuncs[wc->winref]), + list_length(wflists->windowFuncs[wc->winref]), wc->winref, partNumCols, partColIdx, @@ -1423,11 +1422,11 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) */ if (parse->distinctClause) { - double dNumDistinctRows; - long numDistinctRows; - bool use_hashed_distinct; - bool can_sort; - bool can_hash; + double dNumDistinctRows; + long numDistinctRows; + bool use_hashed_distinct; + bool can_sort; + bool can_hash; /* * If there was grouping or aggregation, use the current number of @@ -1472,7 +1471,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not implement DISTINCT"), errdetail("Some of the datatypes only support hashing, while others only support sorting."))); - use_hashed_distinct = false; /* keep compiler quiet */ + use_hashed_distinct = false; /* keep compiler quiet */ } } @@ -1483,10 +1482,10 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) result_plan->targetlist, NIL, AGG_HASHED, - list_length(parse->distinctClause), - extract_grouping_cols(parse->distinctClause, - result_plan->targetlist), - extract_grouping_ops(parse->distinctClause), + list_length(parse->distinctClause), + extract_grouping_cols(parse->distinctClause, + result_plan->targetlist), + extract_grouping_ops(parse->distinctClause), numDistinctRows, 0, result_plan); @@ -1502,11 +1501,11 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) * rigorous of DISTINCT and ORDER BY, to avoid a second sort * below. However, for regular DISTINCT, don't sort now if we * don't have to --- sorting afterwards will likely be cheaper, - * and also has the possibility of optimizing via LIMIT. But - * for DISTINCT ON, we *must* force the final sort now, else - * it won't have the desired behavior. + * and also has the possibility of optimizing via LIMIT. But for + * DISTINCT ON, we *must* force the final sort now, else it won't + * have the desired behavior. */ - List *needed_pathkeys; + List *needed_pathkeys; if (parse->hasDistinctOn && list_length(root->distinct_pathkeys) < @@ -1530,7 +1529,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) result_plan = (Plan *) make_sort_from_pathkeys(root, result_plan, - current_pathkeys, + current_pathkeys, -1.0); } @@ -1551,7 +1550,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) { result_plan = (Plan *) make_sort_from_pathkeys(root, result_plan, - root->sort_pathkeys, + root->sort_pathkeys, limit_tuples); current_pathkeys = root->sort_pathkeys; } @@ -1883,12 +1882,12 @@ preprocess_groupclause(PlannerInfo *root) return; /* - * Add any remaining GROUP BY items to the new list, but only if we - * were able to make a complete match. In other words, we only - * rearrange the GROUP BY list if the result is that one list is a - * prefix of the other --- otherwise there's no possibility of a - * common sort. Also, give up if there are any non-sortable GROUP BY - * items, since then there's no hope anyway. + * Add any remaining GROUP BY items to the new list, but only if we were + * able to make a complete match. In other words, we only rearrange the + * GROUP BY list if the result is that one list is a prefix of the other + * --- otherwise there's no possibility of a common sort. Also, give up + * if there are any non-sortable GROUP BY items, since then there's no + * hope anyway. */ foreach(gl, parse->groupClause) { @@ -1962,11 +1961,10 @@ choose_hashed_grouping(PlannerInfo *root, /* * When we have both GROUP BY and DISTINCT, use the more-rigorous of - * DISTINCT and ORDER BY as the assumed required output sort order. - * This is an oversimplification because the DISTINCT might get - * implemented via hashing, but it's not clear that the case is common - * enough (or that our estimates are good enough) to justify trying to - * solve it exactly. + * DISTINCT and ORDER BY as the assumed required output sort order. This + * is an oversimplification because the DISTINCT might get implemented via + * hashing, but it's not clear that the case is common enough (or that our + * estimates are good enough) to justify trying to solve it exactly. */ if (list_length(root->distinct_pathkeys) > list_length(root->sort_pathkeys)) @@ -2056,7 +2054,7 @@ choose_hashed_grouping(PlannerInfo *root, * differences that it doesn't seem worth trying to unify the two functions. * * But note that making the two choices independently is a bit bogus in - * itself. If the two could be combined into a single choice operation + * itself. If the two could be combined into a single choice operation * it'd probably be better, but that seems far too unwieldy to be practical, * especially considering that the combination of GROUP BY and DISTINCT * isn't very common in real queries. By separating them, we are giving @@ -2098,8 +2096,8 @@ choose_hashed_distinct(PlannerInfo *root, * comparison. * * We need to consider input_plan + hashagg [+ final sort] versus - * input_plan [+ sort] + group [+ final sort] where brackets indicate - * a step that may not be needed. + * input_plan [+ sort] + group [+ final sort] where brackets indicate a + * step that may not be needed. * * These path variables are dummies that just hold cost fields; we don't * make actual Paths for these steps. @@ -2108,16 +2106,17 @@ choose_hashed_distinct(PlannerInfo *root, numDistinctCols, dNumDistinctRows, input_plan->startup_cost, input_plan->total_cost, input_plan->plan_rows); + /* - * Result of hashed agg is always unsorted, so if ORDER BY is present - * we need to charge for the final sort. + * Result of hashed agg is always unsorted, so if ORDER BY is present we + * need to charge for the final sort. */ if (root->parse->sortClause) cost_sort(&hashed_p, root, root->sort_pathkeys, hashed_p.total_cost, dNumDistinctRows, input_plan->plan_width, limit_tuples); /* - * Now for the GROUP case. See comments in grouping_planner about the + * Now for the GROUP case. See comments in grouping_planner about the * sorting choices here --- this code should match that code. */ sorted_p.startup_cost = input_plan->startup_cost; @@ -2398,10 +2397,10 @@ select_active_windows(PlannerInfo *root, WindowFuncLists *wflists) * are otherwise distinct (eg, different names or framing clauses). * * There is room to be much smarter here, for example detecting whether - * one window's sort keys are a prefix of another's (so that sorting - * for the latter would do for the former), or putting windows first - * that match a sort order available for the underlying query. For the - * moment we are content with meeting the spec. + * one window's sort keys are a prefix of another's (so that sorting for + * the latter would do for the former), or putting windows first that + * match a sort order available for the underlying query. For the moment + * we are content with meeting the spec. */ result = NIL; while (actives != NIL) @@ -2469,12 +2468,12 @@ add_volatile_sort_exprs(List *window_tlist, List *tlist, List *activeWindows) } /* - * Now scan the original tlist to find the referenced expressions. - * Any that are volatile must be added to window_tlist. + * Now scan the original tlist to find the referenced expressions. Any + * that are volatile must be added to window_tlist. * - * Note: we know that the input window_tlist contains no items marked - * with ressortgrouprefs, so we don't have to worry about collisions - * of the reference numbers. + * Note: we know that the input window_tlist contains no items marked with + * ressortgrouprefs, so we don't have to worry about collisions of the + * reference numbers. */ foreach(lc, tlist) { @@ -2524,7 +2523,7 @@ make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not implement window ORDER BY"), - errdetail("Window ordering columns must be of sortable datatypes."))); + errdetail("Window ordering columns must be of sortable datatypes."))); /* Okay, make the combined pathkeys */ window_sortclauses = list_concat(list_copy(wc->partitionClause), @@ -2545,7 +2544,7 @@ make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, * This depends on the behavior of make_pathkeys_for_window()! * * We are given the target WindowClause and an array of the input column - * numbers associated with the resulting pathkeys. In the easy case, there + * numbers associated with the resulting pathkeys. In the easy case, there * are the same number of pathkey columns as partitioning + ordering columns * and we just have to copy some data around. However, it's possible that * some of the original partitioning + ordering columns were eliminated as @@ -2553,11 +2552,11 @@ make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, * though the parser gets rid of obvious duplicates. A typical scenario is a * window specification "PARTITION BY x ORDER BY y" coupled with a clause * "WHERE x = y" that causes the two sort columns to be recognized as - * redundant.) In that unusual case, we have to work a lot harder to + * redundant.) In that unusual case, we have to work a lot harder to * determine which keys are significant. * * The method used here is a bit brute-force: add the sort columns to a list - * one at a time and note when the resulting pathkey list gets longer. But + * one at a time and note when the resulting pathkey list gets longer. But * it's a sufficiently uncommon case that a faster way doesn't seem worth * the amount of code refactoring that'd be needed. *---------- @@ -2659,7 +2658,7 @@ get_column_info_for_window(PlannerInfo *root, WindowClause *wc, List *tlist, * Currently, we disallow sublinks in standalone expressions, so there's no * real "planning" involved here. (That might not always be true though.) * What we must do is run eval_const_expressions to ensure that any function - * default arguments get inserted. The fact that constant subexpressions + * default arguments get inserted. The fact that constant subexpressions * get simplified is a side-effect that is useful when the expression will * get evaluated more than once. Also, we must fix operator function IDs. * |
