Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1466bcf

Browse filesBrowse 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
Copy full SHA for 1466bcf

File tree

Expand file treeCollapse file tree

1 file changed

+114
-72
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+114
-72
lines changed

‎src/backend/optimizer/plan/planner.c

Copy file name to clipboardExpand all lines: src/backend/optimizer/plan/planner.c
+114-72Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.