@@ -141,6 +141,16 @@ static RelOptInfo *create_grouping_paths(PlannerInfo *root,
141
141
bool target_parallel_safe ,
142
142
const AggClauseCosts * agg_costs ,
143
143
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 );
144
154
static void consider_groupingsets_paths (PlannerInfo * root ,
145
155
RelOptInfo * grouped_rel ,
146
156
Path * path ,
@@ -3667,11 +3677,6 @@ estimate_hashagg_tablesize(Path *path, const AggClauseCosts *agg_costs,
3667
3677
*
3668
3678
* Note: all Paths in input_rel are expected to return the target computed
3669
3679
* 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.
3675
3680
*/
3676
3681
static RelOptInfo *
3677
3682
create_grouping_paths (PlannerInfo * root ,
@@ -3682,15 +3687,8 @@ create_grouping_paths(PlannerInfo *root,
3682
3687
grouping_sets_data * gd )
3683
3688
{
3684
3689
Query * parse = root -> parse ;
3685
- Path * cheapest_path = input_rel -> cheapest_total_path ;
3686
3690
RelOptInfo * grouped_rel ;
3687
3691
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 ;
3694
3692
3695
3693
/*
3696
3694
* For now, all aggregated paths are added to the (GROUP_AGG, NULL)
@@ -3728,73 +3726,123 @@ create_grouping_paths(PlannerInfo *root,
3728
3726
partially_grouped_rel -> fdwroutine = input_rel -> fdwroutine ;
3729
3727
3730
3728
/*
3731
- * Check for degenerate grouping.
3729
+ * Create either paths for a degenerate grouping or paths for ordinary
3730
+ * grouping, as appropriate.
3732
3731
*/
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 )
3735
3780
{
3736
3781
/*
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.)
3748
3787
*/
3749
- int nrows = list_length (parse -> groupingSets );
3750
- Path * path ;
3788
+ List * paths = NIL ;
3751
3789
3752
- if ( nrows > 1 )
3790
+ while ( -- nrows >= 0 )
3753
3791
{
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 */
3785
3792
path = (Path * )
3786
3793
create_result_path (root , grouped_rel ,
3787
3794
target ,
3788
3795
(List * ) parse -> havingQual );
3796
+ paths = lappend (paths , path );
3789
3797
}
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
+ }
3790
3817
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
+ }
3795
3820
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 ;
3798
3846
3799
3847
/*
3800
3848
* Estimate number of groups.
@@ -3922,14 +3970,8 @@ create_grouping_paths(PlannerInfo *root,
3922
3970
if (create_upper_paths_hook )
3923
3971
(* create_upper_paths_hook ) (root , UPPERREL_GROUP_AGG ,
3924
3972
input_rel , grouped_rel );
3925
-
3926
- /* Now choose the best path(s) */
3927
- set_cheapest (grouped_rel );
3928
-
3929
- return grouped_rel ;
3930
3973
}
3931
3974
3932
-
3933
3975
/*
3934
3976
* For a given input path, consider the possible ways of doing grouping sets on
3935
3977
* it, by combinations of hashing and sorting. This can be called multiple
0 commit comments