Commit a54676ac authored by Tom Lane's avatar Tom Lane

Marginal cleanup of GROUPING SETS code in grouping_planner().

Improve comments and make it a shade less messy.  I think we might want
to move all of this somewhere else later, but it needs to be more
readable first.

In passing, re-pgindent the file, affecting some recently-added comments
concerning parallel query planning.
parent c44d0138
...@@ -202,14 +202,14 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) ...@@ -202,14 +202,14 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
glob->hasRowSecurity = false; glob->hasRowSecurity = false;
/* /*
* Assess whether it's feasible to use parallel mode for this query. * Assess whether it's feasible to use parallel mode for this query. We
* We can't do this in a standalone backend, or if the command will * can't do this in a standalone backend, or if the command will try to
* try to modify any data, or if this is a cursor operation, or if * modify any data, or if this is a cursor operation, or if GUCs are set
* GUCs are set to values that don't permit parallelism, or if * to values that don't permit parallelism, or if parallel-unsafe
* parallel-unsafe functions are present in the query tree. * functions are present in the query tree.
* *
* For now, we don't try to use parallel mode if we're running inside * For now, we don't try to use parallel mode if we're running inside a
* a parallel worker. We might eventually be able to relax this * parallel worker. We might eventually be able to relax this
* restriction, but for now it seems best not to have parallel workers * restriction, but for now it seems best not to have parallel workers
* trying to create their own parallel workers. * trying to create their own parallel workers.
* *
...@@ -218,8 +218,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) ...@@ -218,8 +218,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
* tries to run a parallel plan in serializable mode; it just won't get * tries to run a parallel plan in serializable mode; it just won't get
* any workers and will run serially. But it seems like a good heuristic * any workers and will run serially. But it seems like a good heuristic
* to assume that the same serialization level will be in effect at plan * to assume that the same serialization level will be in effect at plan
* time and execution time, so don't generate a parallel plan if we're * time and execution time, so don't generate a parallel plan if we're in
* in serializable mode. * serializable mode.
*/ */
glob->parallelModeOK = (cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 && glob->parallelModeOK = (cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
IsUnderPostmaster && dynamic_shared_memory_type != DSM_IMPL_NONE && IsUnderPostmaster && dynamic_shared_memory_type != DSM_IMPL_NONE &&
...@@ -239,9 +239,9 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) ...@@ -239,9 +239,9 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
* *
* (It's been suggested that we should always impose these restrictions * (It's been suggested that we should always impose these restrictions
* whenever glob->parallelModeOK is true, so that it's easier to notice * whenever glob->parallelModeOK is true, so that it's easier to notice
* incorrectly-labeled functions sooner. That might be the right thing * incorrectly-labeled functions sooner. That might be the right thing to
* to do, but for now I've taken this approach. We could also control * do, but for now I've taken this approach. We could also control this
* this with a GUC.) * with a GUC.)
* *
* FIXME: It's assumed that code further down will set parallelModeNeeded * FIXME: It's assumed that code further down will set parallelModeNeeded
* to true if a parallel path is actually chosen. Since the core * to true if a parallel path is actually chosen. Since the core
...@@ -1425,7 +1425,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) ...@@ -1425,7 +1425,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
List *activeWindows = NIL; List *activeWindows = NIL;
OnConflictExpr *onconfl; OnConflictExpr *onconfl;
int maxref = 0; int maxref = 0;
int *tleref_to_colnum_map;
List *rollup_lists = NIL; List *rollup_lists = NIL;
List *rollup_groupclauses = NIL; List *rollup_groupclauses = NIL;
standard_qp_extra qp_extra; standard_qp_extra qp_extra;
...@@ -1439,14 +1438,19 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) ...@@ -1439,14 +1438,19 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
/* A recursive query should always have setOperations */ /* A recursive query should always have setOperations */
Assert(!root->hasRecursion); Assert(!root->hasRecursion);
/* Preprocess Grouping set, if any */ /* Preprocess grouping sets, if any */
if (parse->groupingSets) if (parse->groupingSets)
parse->groupingSets = expand_grouping_sets(parse->groupingSets, -1);
if (parse->groupClause)
{ {
int *tleref_to_colnum_map;
List *sets;
ListCell *lc; ListCell *lc;
ListCell *lc2;
ListCell *lc_set;
parse->groupingSets = expand_grouping_sets(parse->groupingSets, -1);
/* Identify max SortGroupRef in groupClause, for array sizing */
/* (note this value will be used again later) */
foreach(lc, parse->groupClause) foreach(lc, parse->groupClause)
{ {
SortGroupClause *gc = lfirst(lc); SortGroupClause *gc = lfirst(lc);
...@@ -1454,25 +1458,38 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) ...@@ -1454,25 +1458,38 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
if (gc->tleSortGroupRef > maxref) if (gc->tleSortGroupRef > maxref)
maxref = gc->tleSortGroupRef; maxref = gc->tleSortGroupRef;
} }
}
tleref_to_colnum_map = palloc((maxref + 1) * sizeof(int)); /* Allocate workspace array for remapping */
tleref_to_colnum_map = (int *) palloc((maxref + 1) * sizeof(int));
if (parse->groupingSets) /* Examine the rollup sets */
{ sets = extract_rollup_sets(parse->groupingSets);
ListCell *lc;
ListCell *lc2;
ListCell *lc_set;
List *sets = extract_rollup_sets(parse->groupingSets);
foreach(lc_set, sets) foreach(lc_set, sets)
{ {
List *current_sets = reorder_grouping_sets(lfirst(lc_set), List *current_sets = (List *) lfirst(lc_set);
List *groupclause;
int ref;
/*
* Reorder the current list of grouping sets into correct
* prefix order. If only one aggregation pass is needed, try
* to make the list match the ORDER BY clause; if more than
* one pass is needed, we don't bother with that.
*/
current_sets = reorder_grouping_sets(current_sets,
(list_length(sets) == 1 (list_length(sets) == 1
? parse->sortClause ? parse->sortClause
: NIL)); : NIL));
List *groupclause = preprocess_groupclause(root, linitial(current_sets));
int ref = 0; /*
* Order the groupClause appropriately. If the first grouping
* set is empty, this can match regular GROUP BY
* preprocessing, otherwise we have to force the groupClause
* to match that grouping set's order.
*/
groupclause = preprocess_groupclause(root,
linitial(current_sets));
/* /*
* Now that we've pinned down an order for the groupClause for * Now that we've pinned down an order for the groupClause for
...@@ -1481,7 +1498,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) ...@@ -1481,7 +1498,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
* (0-based) into the groupClause for this collection of * (0-based) into the groupClause for this collection of
* grouping sets. * grouping sets.
*/ */
ref = 0;
foreach(lc, groupclause) foreach(lc, groupclause)
{ {
SortGroupClause *gc = lfirst(lc); SortGroupClause *gc = lfirst(lc);
...@@ -1497,6 +1514,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) ...@@ -1497,6 +1514,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
} }
} }
/* Save the reordered sets and corresponding groupclauses */
rollup_lists = lcons(current_sets, rollup_lists); rollup_lists = lcons(current_sets, rollup_lists);
rollup_groupclauses = lcons(groupclause, rollup_groupclauses); rollup_groupclauses = lcons(groupclause, rollup_groupclauses);
} }
...@@ -1953,10 +1971,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) ...@@ -1953,10 +1971,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
/* /*
* groupColIdx is now cast in stone, so record a mapping from * groupColIdx is now cast in stone, so record a mapping from
* tleSortGroupRef to column index. setrefs.c needs this to * tleSortGroupRef to column index. setrefs.c will need this to
* finalize GROUPING() operations. * finalize GROUPING() operations.
*/ */
if (parse->groupingSets) if (parse->groupingSets)
{ {
AttrNumber *grouping_map = palloc0(sizeof(AttrNumber) * (maxref + 1)); AttrNumber *grouping_map = palloc0(sizeof(AttrNumber) * (maxref + 1));
...@@ -1996,9 +2013,12 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) ...@@ -1996,9 +2013,12 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
/* Hashed aggregation produces randomly-ordered results */ /* Hashed aggregation produces randomly-ordered results */
current_pathkeys = NIL; current_pathkeys = NIL;
} }
else if (parse->hasAggs || (parse->groupingSets && parse->groupClause)) else if (parse->hasAggs ||
(parse->groupingSets && parse->groupClause))
{ {
/* /*
* Aggregation and/or non-degenerate grouping sets.
*
* Output is in sorted order by group_pathkeys if, and only * Output is in sorted order by group_pathkeys if, and only
* if, there is a single rollup operation on a non-empty list * if, there is a single rollup operation on a non-empty list
* of grouping expressions. * of grouping expressions.
...@@ -3473,7 +3493,8 @@ extract_rollup_sets(List *groupingSets) ...@@ -3473,7 +3493,8 @@ extract_rollup_sets(List *groupingSets)
* prefix relationships. * prefix relationships.
* *
* The input must be ordered with smallest sets first; the result is returned * The input must be ordered with smallest sets first; the result is returned
* with largest sets first. * with largest sets first. Note that the result shares no list substructure
* with the input, so it's safe for the caller to modify it later.
* *
* If we're passed in a sortclause, we follow its order of columns to the * If we're passed in a sortclause, we follow its order of columns to the
* extent possible, to minimize the chance that we add unnecessary sorts. * extent possible, to minimize the chance that we add unnecessary sorts.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment