@@ -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 );
144154static 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 */
36763681static RelOptInfo *
36773682create_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