summaryrefslogtreecommitdiff
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.c191
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;
}