mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
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.
This commit is contained in:
parent
c44d013835
commit
a54676acad
@ -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)
|
|||||||
* 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)
|
|||||||
*
|
*
|
||||||
* (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)
|
|||||||
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)
|
|||||||
/* 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)
|
||||||
|
{
|
||||||
|
int *tleref_to_colnum_map;
|
||||||
|
List *sets;
|
||||||
|
ListCell *lc;
|
||||||
|
ListCell *lc2;
|
||||||
|
ListCell *lc_set;
|
||||||
|
|
||||||
parse->groupingSets = expand_grouping_sets(parse->groupingSets, -1);
|
parse->groupingSets = expand_grouping_sets(parse->groupingSets, -1);
|
||||||
|
|
||||||
if (parse->groupClause)
|
/* Identify max SortGroupRef in groupClause, for array sizing */
|
||||||
{
|
/* (note this value will be used again later) */
|
||||||
ListCell *lc;
|
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
* (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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
/* 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)
|
|||||||
* 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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user