diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 191 |
1 files changed, 107 insertions, 84 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index f2eb62a4e34..789af4e9f98 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -55,7 +55,14 @@ planner_hook_type planner_hook = NULL; #define EXPRKIND_LIMIT 4 #define EXPRKIND_APPINFO 5 +/* Passthrough data for standard_qp_callback */ +typedef struct +{ + List *tlist; /* preprocessed query targetlist */ + List *activeWindows; /* active windows, if any */ +} standard_qp_extra; +/* Local functions */ 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); @@ -65,6 +72,7 @@ static double preprocess_limit(PlannerInfo *root, double tuple_fraction, int64 *offset_est, int64 *count_est); static void preprocess_groupclause(PlannerInfo *root); +static void standard_qp_callback(PlannerInfo *root, void *extra); static bool choose_hashed_grouping(PlannerInfo *root, double tuple_fraction, double limit_tuples, double path_rows, int path_width, @@ -89,7 +97,7 @@ static List *select_active_windows(PlannerInfo *root, WindowFuncLists *wflists); static List *make_windowInputTargetList(PlannerInfo *root, List *tlist, List *activeWindows); static List *make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, - List *tlist, bool canonicalize); + List *tlist); static void get_column_info_for_window(PlannerInfo *root, WindowClause *wc, List *tlist, int numSortCols, AttrNumber *sortColIdx, @@ -1046,6 +1054,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) double sub_limit_tuples; AttrNumber *groupColIdx = NULL; bool need_tlist_eval = true; + standard_qp_extra qp_extra; Path *cheapest_path; Path *sorted_path; Path *best_path; @@ -1122,82 +1131,6 @@ 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. - */ - if (parse->groupClause && - grouping_is_sortable(parse->groupClause)) - root->group_pathkeys = - make_pathkeys_for_sortclauses(root, - parse->groupClause, - tlist, - false); - else - root->group_pathkeys = NIL; - - /* We consider only the first (bottom) window in pathkeys logic */ - if (activeWindows != NIL) - { - WindowClause *wc = (WindowClause *) linitial(activeWindows); - - root->window_pathkeys = make_pathkeys_for_window(root, - wc, - tlist, - false); - } - else - root->window_pathkeys = NIL; - - if (parse->distinctClause && - grouping_is_sortable(parse->distinctClause)) - root->distinct_pathkeys = - make_pathkeys_for_sortclauses(root, - parse->distinctClause, - tlist, - false); - else - root->distinct_pathkeys = NIL; - - root->sort_pathkeys = - make_pathkeys_for_sortclauses(root, - parse->sortClause, - tlist, - false); - - /* - * Figure out whether we want a sorted result from query_planner. - * - * If we have a sortable GROUP BY clause, then we want a result sorted - * properly for grouping. Otherwise, if we have window functions to - * evaluate, we try to sort for the first window. Otherwise, if - * there's a sortable DISTINCT clause that's more rigorous than the - * ORDER BY clause, we try to produce output that's sufficiently well - * sorted for the DISTINCT. Otherwise, if there is an ORDER BY - * clause, we want to sort by the ORDER BY clause. - * - * 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 - * versus ORDER BY is much easier, since we know that the parser - * ensured that one is a superset of the other. - */ - if (root->group_pathkeys) - root->query_pathkeys = root->group_pathkeys; - else if (root->window_pathkeys) - root->query_pathkeys = root->window_pathkeys; - else if (list_length(root->distinct_pathkeys) > - list_length(root->sort_pathkeys)) - root->query_pathkeys = root->distinct_pathkeys; - else if (root->sort_pathkeys) - root->query_pathkeys = root->sort_pathkeys; - else - root->query_pathkeys = NIL; - - /* * Figure out whether there's a hard limit on the number of rows that * query_planner's result subplan needs to return. Even if we know a * hard limit overall, it doesn't apply if the query has any @@ -1212,13 +1145,19 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) else sub_limit_tuples = limit_tuples; + /* Set up data needed by standard_qp_callback */ + qp_extra.tlist = tlist; + qp_extra.activeWindows = activeWindows; + /* * Generate the best unsorted and presorted paths for this Query (but - * note there may not be any presorted path). query_planner will also - * estimate the number of groups in the query, and canonicalize all - * the pathkeys. + * note there may not be any presorted path). We also generate (in + * standard_qp_callback) pathkey representations of the query's sort + * clause, distinct clause, etc. query_planner will also estimate the + * number of groups in the query. */ query_planner(root, sub_tlist, tuple_fraction, sub_limit_tuples, + standard_qp_callback, &qp_extra, &cheapest_path, &sorted_path, &dNumGroups); /* @@ -1546,8 +1485,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) window_pathkeys = make_pathkeys_for_window(root, wc, - tlist, - true); + tlist); /* * This is a bit tricky: we build a sort node even if we don't @@ -2315,6 +2253,91 @@ preprocess_groupclause(PlannerInfo *root) } /* + * Compute query_pathkeys and other pathkeys during plan generation + */ +static void +standard_qp_callback(PlannerInfo *root, void *extra) +{ + Query *parse = root->parse; + standard_qp_extra *qp_extra = (standard_qp_extra *) extra; + List *tlist = qp_extra->tlist; + List *activeWindows = qp_extra->activeWindows; + + /* + * Calculate pathkeys that represent grouping/ordering requirements. 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)) + root->group_pathkeys = + make_pathkeys_for_sortclauses(root, + parse->groupClause, + tlist, + true); + else + root->group_pathkeys = NIL; + + /* We consider only the first (bottom) window in pathkeys logic */ + if (activeWindows != NIL) + { + WindowClause *wc = (WindowClause *) linitial(activeWindows); + + root->window_pathkeys = make_pathkeys_for_window(root, + wc, + tlist); + } + else + root->window_pathkeys = NIL; + + if (parse->distinctClause && + grouping_is_sortable(parse->distinctClause)) + root->distinct_pathkeys = + make_pathkeys_for_sortclauses(root, + parse->distinctClause, + tlist, + true); + else + root->distinct_pathkeys = NIL; + + root->sort_pathkeys = + make_pathkeys_for_sortclauses(root, + parse->sortClause, + tlist, + true); + + /* + * Figure out whether we want a sorted result from query_planner. + * + * If we have a sortable GROUP BY clause, then we want a result sorted + * properly for grouping. Otherwise, if we have window functions to + * evaluate, we try to sort for the first window. Otherwise, if there's a + * sortable DISTINCT clause that's more rigorous than the ORDER BY clause, + * we try to produce output that's sufficiently well sorted for the + * DISTINCT. Otherwise, if there is an ORDER BY clause, we want to sort + * by the ORDER BY clause. + * + * 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 versus ORDER BY is + * much easier, since we know that the parser ensured that one is a + * superset of the other. + */ + if (root->group_pathkeys) + root->query_pathkeys = root->group_pathkeys; + else if (root->window_pathkeys) + root->query_pathkeys = root->window_pathkeys; + else if (list_length(root->distinct_pathkeys) > + list_length(root->sort_pathkeys)) + root->query_pathkeys = root->distinct_pathkeys; + else if (root->sort_pathkeys) + root->query_pathkeys = root->sort_pathkeys; + else + root->query_pathkeys = NIL; +} + +/* * choose_hashed_grouping - should we use hashed grouping? * * Returns TRUE to select hashing, FALSE to select sorting. @@ -3110,7 +3133,7 @@ make_windowInputTargetList(PlannerInfo *root, */ static List * make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, - List *tlist, bool canonicalize) + List *tlist) { List *window_pathkeys; List *window_sortclauses; @@ -3133,7 +3156,7 @@ make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, window_pathkeys = make_pathkeys_for_sortclauses(root, window_sortclauses, tlist, - canonicalize); + true); list_free(window_sortclauses); return window_pathkeys; } |