Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1466bcf

Browse files
committed
Split create_grouping_paths into degenerate and non-degenerate cases.
There's no functional change here, or at least I hope there isn't, just code rearrangement. The rearrangement is motivated by partition-wise aggregate, which doesn't need to consider the degenerate case but wants to reuse the logic for the ordinary case. Based loosely on a patch from Ashutosh Bapat and Jeevan Chalke, but I whacked it around pretty heavily. The larger patch series of which this patch is a part was also reviewed and tested by Antonin Houska, Rajkumar Raghuwanshi, David Rowley, Dilip Kumar, Konstantin Knizhnik, Pascal Legrand, Rafia Sabih, and me. Discussion: http://postgr.es/m/CAFjFpRewpqCmVkwvq6qrRjmbMDpN0CZvRRzjd8UvncczA3Oz1Q@mail.gmail.com
1 parent a446a1c commit 1466bcf

File tree

1 file changed

+114
-72
lines changed

1 file changed

+114
-72
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 114 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ static RelOptInfo *create_grouping_paths(PlannerInfo *root,
141141
bool target_parallel_safe,
142142
const AggClauseCosts *agg_costs,
143143
grouping_sets_data *gd);
144+
static bool is_degenerate_grouping(PlannerInfo *root);
145+
static void create_degenerate_grouping_paths(PlannerInfo *root,
146+
RelOptInfo *input_rel,
147+
PathTarget *target, RelOptInfo *grouped_rel);
148+
static void create_ordinary_grouping_paths(PlannerInfo *root,
149+
RelOptInfo *input_rel,
150+
PathTarget *target, RelOptInfo *grouped_rel,
151+
RelOptInfo *partially_grouped_rel,
152+
const AggClauseCosts *agg_costs,
153+
grouping_sets_data *gd);
144154
static void consider_groupingsets_paths(PlannerInfo *root,
145155
RelOptInfo *grouped_rel,
146156
Path *path,
@@ -3667,11 +3677,6 @@ estimate_hashagg_tablesize(Path *path, const AggClauseCosts *agg_costs,
36673677
*
36683678
* Note: all Paths in input_rel are expected to return the target computed
36693679
* by make_group_input_target.
3670-
*
3671-
* We need to consider sorted and hashed aggregation in the same function,
3672-
* because otherwise (1) it would be harder to throw an appropriate error
3673-
* message if neither way works, and (2) we should not allow hashtable size
3674-
* considerations to dissuade us from using hashing if sorting is not possible.
36753680
*/
36763681
static RelOptInfo *
36773682
create_grouping_paths(PlannerInfo *root,
@@ -3682,15 +3687,8 @@ create_grouping_paths(PlannerInfo *root,
36823687
grouping_sets_data *gd)
36833688
{
36843689
Query *parse = root->parse;
3685-
Path *cheapest_path = input_rel->cheapest_total_path;
36863690
RelOptInfo *grouped_rel;
36873691
RelOptInfo *partially_grouped_rel;
3688-
AggClauseCosts agg_partial_costs; /* parallel only */
3689-
AggClauseCosts agg_final_costs; /* parallel only */
3690-
double dNumGroups;
3691-
bool can_hash;
3692-
bool can_sort;
3693-
bool try_parallel_aggregation;
36943692

36953693
/*
36963694
* For now, all aggregated paths are added to the (GROUP_AGG, NULL)
@@ -3728,73 +3726,123 @@ create_grouping_paths(PlannerInfo *root,
37283726
partially_grouped_rel->fdwroutine = input_rel->fdwroutine;
37293727

37303728
/*
3731-
* Check for degenerate grouping.
3729+
* Create either paths for a degenerate grouping or paths for ordinary
3730+
* grouping, as appropriate.
37323731
*/
3733-
if ((root->hasHavingQual || parse->groupingSets) &&
3734-
!parse->hasAggs && parse->groupClause == NIL)
3732+
if (is_degenerate_grouping(root))
3733+
create_degenerate_grouping_paths(root, input_rel, target, grouped_rel);
3734+
else
3735+
create_ordinary_grouping_paths(root, input_rel, target, grouped_rel,
3736+
partially_grouped_rel, agg_costs, gd);
3737+
3738+
set_cheapest(grouped_rel);
3739+
return grouped_rel;
3740+
}
3741+
3742+
/*
3743+
* is_degenerate_grouping
3744+
*
3745+
* A degenerate grouping is one in which the query has a HAVING qual and/or
3746+
* grouping sets, but no aggregates and no GROUP BY (which implies that the
3747+
* grouping sets are all empty).
3748+
*/
3749+
static bool
3750+
is_degenerate_grouping(PlannerInfo *root)
3751+
{
3752+
Query *parse = root->parse;
3753+
3754+
return (root->hasHavingQual || parse->groupingSets) &&
3755+
!parse->hasAggs && parse->groupClause == NIL;
3756+
}
3757+
3758+
/*
3759+
* create_degenerate_grouping_paths
3760+
*
3761+
* When the grouping is degenerate (see is_degenerate_grouping), we are
3762+
* supposed to emit either zero or one row for each grouping set depending on
3763+
* whether HAVING succeeds. Furthermore, there cannot be any variables in
3764+
* either HAVING or the targetlist, so we actually do not need the FROM table
3765+
* at all! We can just throw away the plan-so-far and generate a Result node.
3766+
* This is a sufficiently unusual corner case that it's not worth contorting
3767+
* the structure of this module to avoid having to generate the earlier paths
3768+
* in the first place.
3769+
*/
3770+
static void
3771+
create_degenerate_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
3772+
PathTarget *target, RelOptInfo *grouped_rel)
3773+
{
3774+
Query *parse = root->parse;
3775+
int nrows;
3776+
Path *path;
3777+
3778+
nrows = list_length(parse->groupingSets);
3779+
if (nrows > 1)
37353780
{
37363781
/*
3737-
* We have a HAVING qual and/or grouping sets, but no aggregates and
3738-
* no GROUP BY (which implies that the grouping sets are all empty).
3739-
*
3740-
* This is a degenerate case in which we are supposed to emit either
3741-
* zero or one row for each grouping set depending on whether HAVING
3742-
* succeeds. Furthermore, there cannot be any variables in either
3743-
* HAVING or the targetlist, so we actually do not need the FROM table
3744-
* at all! We can just throw away the plan-so-far and generate a
3745-
* Result node. This is a sufficiently unusual corner case that it's
3746-
* not worth contorting the structure of this module to avoid having
3747-
* to generate the earlier paths in the first place.
3782+
* Doesn't seem worthwhile writing code to cons up a generate_series
3783+
* or a values scan to emit multiple rows. Instead just make N clones
3784+
* and append them. (With a volatile HAVING clause, this means you
3785+
* might get between 0 and N output rows. Offhand I think that's
3786+
* desired.)
37483787
*/
3749-
int nrows = list_length(parse->groupingSets);
3750-
Path *path;
3788+
List *paths = NIL;
37513789

3752-
if (nrows > 1)
3790+
while (--nrows >= 0)
37533791
{
3754-
/*
3755-
* Doesn't seem worthwhile writing code to cons up a
3756-
* generate_series or a values scan to emit multiple rows. Instead
3757-
* just make N clones and append them. (With a volatile HAVING
3758-
* clause, this means you might get between 0 and N output rows.
3759-
* Offhand I think that's desired.)
3760-
*/
3761-
List *paths = NIL;
3762-
3763-
while (--nrows >= 0)
3764-
{
3765-
path = (Path *)
3766-
create_result_path(root, grouped_rel,
3767-
target,
3768-
(List *) parse->havingQual);
3769-
paths = lappend(paths, path);
3770-
}
3771-
path = (Path *)
3772-
create_append_path(grouped_rel,
3773-
paths,
3774-
NIL,
3775-
NULL,
3776-
0,
3777-
false,
3778-
NIL,
3779-
-1);
3780-
path->pathtarget = target;
3781-
}
3782-
else
3783-
{
3784-
/* No grouping sets, or just one, so one output row */
37853792
path = (Path *)
37863793
create_result_path(root, grouped_rel,
37873794
target,
37883795
(List *) parse->havingQual);
3796+
paths = lappend(paths, path);
37893797
}
3798+
path = (Path *)
3799+
create_append_path(grouped_rel,
3800+
paths,
3801+
NIL,
3802+
NULL,
3803+
0,
3804+
false,
3805+
NIL,
3806+
-1);
3807+
path->pathtarget = target;
3808+
}
3809+
else
3810+
{
3811+
/* No grouping sets, or just one, so one output row */
3812+
path = (Path *)
3813+
create_result_path(root, grouped_rel,
3814+
target,
3815+
(List *) parse->havingQual);
3816+
}
37903817

3791-
add_path(grouped_rel, path);
3792-
3793-
/* No need to consider any other alternatives. */
3794-
set_cheapest(grouped_rel);
3818+
add_path(grouped_rel, path);
3819+
}
37953820

3796-
return grouped_rel;
3797-
}
3821+
/*
3822+
* create_ordinary_grouping_paths
3823+
*
3824+
* Create grouping paths for the ordinary (that is, non-degenerate) case.
3825+
*
3826+
* We need to consider sorted and hashed aggregation in the same function,
3827+
* because otherwise (1) it would be harder to throw an appropriate error
3828+
* message if neither way works, and (2) we should not allow hashtable size
3829+
* considerations to dissuade us from using hashing if sorting is not possible.
3830+
*/
3831+
static void
3832+
create_ordinary_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
3833+
PathTarget *target, RelOptInfo *grouped_rel,
3834+
RelOptInfo *partially_grouped_rel,
3835+
const AggClauseCosts *agg_costs,
3836+
grouping_sets_data *gd)
3837+
{
3838+
Query *parse = root->parse;
3839+
Path *cheapest_path = input_rel->cheapest_total_path;
3840+
AggClauseCosts agg_partial_costs; /* parallel only */
3841+
AggClauseCosts agg_final_costs; /* parallel only */
3842+
double dNumGroups;
3843+
bool can_hash;
3844+
bool can_sort;
3845+
bool try_parallel_aggregation;
37983846

37993847
/*
38003848
* Estimate number of groups.
@@ -3922,14 +3970,8 @@ create_grouping_paths(PlannerInfo *root,
39223970
if (create_upper_paths_hook)
39233971
(*create_upper_paths_hook) (root, UPPERREL_GROUP_AGG,
39243972
input_rel, grouped_rel);
3925-
3926-
/* Now choose the best path(s) */
3927-
set_cheapest(grouped_rel);
3928-
3929-
return grouped_rel;
39303973
}
39313974

3932-
39333975
/*
39343976
* For a given input path, consider the possible ways of doing grouping sets on
39353977
* it, by combinations of hashing and sorting. This can be called multiple

0 commit comments

Comments
 (0)