@@ -93,6 +93,25 @@ typedef struct
9393 List * groupClause ; /* overrides parse->groupClause */
9494} standard_qp_extra ;
9595
96+ /*
97+ * Various flags indicating what kinds of grouping are possible.
98+ *
99+ * GROUPING_CAN_USE_SORT should be set if it's possible to perform
100+ * sort-based implementations of grouping. When grouping sets are in use,
101+ * this will be true if sorting is potentially usable for any of the grouping
102+ * sets, even if it's not usable for all of them.
103+ *
104+ * GROUPING_CAN_USE_HASH should be set if it's possible to perform
105+ * hash-based implementations of grouping.
106+ *
107+ * GROUPING_CAN_PARTIAL_AGG should be set if the aggregation is of a type
108+ * for which we support partial aggregation (not, for example, grouping sets).
109+ * It says nothing about parallel-safety or the availability of suitable paths.
110+ */
111+ #define GROUPING_CAN_USE_SORT 0x0001
112+ #define GROUPING_CAN_USE_HASH 0x0002
113+ #define GROUPING_CAN_PARTIAL_AGG 0x0004
114+
96115/*
97116 * Data specific to grouping sets
98117 */
@@ -149,7 +168,7 @@ static void create_ordinary_grouping_paths(PlannerInfo *root,
149168 RelOptInfo * input_rel ,
150169 PathTarget * target , RelOptInfo * grouped_rel ,
151170 const AggClauseCosts * agg_costs ,
152- grouping_sets_data * gd );
171+ grouping_sets_data * gd , int flags );
153172static void consider_groupingsets_paths (PlannerInfo * root ,
154173 RelOptInfo * grouped_rel ,
155174 Path * path ,
@@ -215,8 +234,8 @@ static RelOptInfo *create_partial_grouping_paths(PlannerInfo *root,
215234 bool can_hash ,
216235 AggClauseCosts * agg_final_costs );
217236static void gather_grouping_paths (PlannerInfo * root , RelOptInfo * rel );
218- static bool can_parallel_agg (PlannerInfo * root , RelOptInfo * input_rel ,
219- RelOptInfo * grouped_rel , const AggClauseCosts * agg_costs );
237+ static bool can_partial_agg (PlannerInfo * root ,
238+ const AggClauseCosts * agg_costs );
220239
221240
222241/*****************************************************************************
@@ -3720,8 +3739,58 @@ create_grouping_paths(PlannerInfo *root,
37203739 if (is_degenerate_grouping (root ))
37213740 create_degenerate_grouping_paths (root , input_rel , target , grouped_rel );
37223741 else
3742+ {
3743+ int flags = 0 ;
3744+
3745+ /*
3746+ * Determine whether it's possible to perform sort-based
3747+ * implementations of grouping. (Note that if groupClause is empty,
3748+ * grouping_is_sortable() is trivially true, and all the
3749+ * pathkeys_contained_in() tests will succeed too, so that we'll
3750+ * consider every surviving input path.)
3751+ *
3752+ * If we have grouping sets, we might be able to sort some but not all
3753+ * of them; in this case, we need can_sort to be true as long as we
3754+ * must consider any sorted-input plan.
3755+ */
3756+ if ((gd && gd -> rollups != NIL )
3757+ || grouping_is_sortable (parse -> groupClause ))
3758+ flags |= GROUPING_CAN_USE_SORT ;
3759+
3760+ /*
3761+ * Determine whether we should consider hash-based implementations of
3762+ * grouping.
3763+ *
3764+ * Hashed aggregation only applies if we're grouping. If we have
3765+ * grouping sets, some groups might be hashable but others not; in
3766+ * this case we set can_hash true as long as there is nothing globally
3767+ * preventing us from hashing (and we should therefore consider plans
3768+ * with hashes).
3769+ *
3770+ * Executor doesn't support hashed aggregation with DISTINCT or ORDER
3771+ * BY aggregates. (Doing so would imply storing *all* the input
3772+ * values in the hash table, and/or running many sorts in parallel,
3773+ * either of which seems like a certain loser.) We similarly don't
3774+ * support ordered-set aggregates in hashed aggregation, but that case
3775+ * is also included in the numOrderedAggs count.
3776+ *
3777+ * Note: grouping_is_hashable() is much more expensive to check than
3778+ * the other gating conditions, so we want to do it last.
3779+ */
3780+ if ((parse -> groupClause != NIL &&
3781+ agg_costs -> numOrderedAggs == 0 &&
3782+ (gd ? gd -> any_hashable : grouping_is_hashable (parse -> groupClause ))))
3783+ flags |= GROUPING_CAN_USE_HASH ;
3784+
3785+ /*
3786+ * Determine whether partial aggregation is possible.
3787+ */
3788+ if (can_partial_agg (root , agg_costs ))
3789+ flags |= GROUPING_CAN_PARTIAL_AGG ;
3790+
37233791 create_ordinary_grouping_paths (root , input_rel , target , grouped_rel ,
3724- agg_costs , gd );
3792+ agg_costs , gd , flags );
3793+ }
37253794
37263795 set_cheapest (grouped_rel );
37273796 return grouped_rel ;
@@ -3820,15 +3889,15 @@ static void
38203889create_ordinary_grouping_paths (PlannerInfo * root , RelOptInfo * input_rel ,
38213890 PathTarget * target , RelOptInfo * grouped_rel ,
38223891 const AggClauseCosts * agg_costs ,
3823- grouping_sets_data * gd )
3892+ grouping_sets_data * gd , int flags )
38243893{
38253894 Query * parse = root -> parse ;
38263895 Path * cheapest_path = input_rel -> cheapest_total_path ;
38273896 RelOptInfo * partially_grouped_rel = NULL ;
38283897 AggClauseCosts agg_final_costs ; /* parallel only */
38293898 double dNumGroups ;
3830- bool can_hash ;
3831- bool can_sort ;
3899+ bool can_hash = ( flags & GROUPING_CAN_USE_HASH ) != 0 ;
3900+ bool can_sort = ( flags & GROUPING_CAN_USE_SORT ) != 0 ;
38323901
38333902 /*
38343903 * Estimate number of groups.
@@ -3838,50 +3907,14 @@ create_ordinary_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
38383907 gd ,
38393908 parse -> targetList );
38403909
3841- /*
3842- * Determine whether it's possible to perform sort-based implementations
3843- * of grouping. (Note that if groupClause is empty,
3844- * grouping_is_sortable() is trivially true, and all the
3845- * pathkeys_contained_in() tests will succeed too, so that we'll consider
3846- * every surviving input path.)
3847- *
3848- * If we have grouping sets, we might be able to sort some but not all of
3849- * them; in this case, we need can_sort to be true as long as we must
3850- * consider any sorted-input plan.
3851- */
3852- can_sort = (gd && gd -> rollups != NIL )
3853- || grouping_is_sortable (parse -> groupClause );
3854-
3855- /*
3856- * Determine whether we should consider hash-based implementations of
3857- * grouping.
3858- *
3859- * Hashed aggregation only applies if we're grouping. If we have grouping
3860- * sets, some groups might be hashable but others not; in this case we set
3861- * can_hash true as long as there is nothing globally preventing us from
3862- * hashing (and we should therefore consider plans with hashes).
3863- *
3864- * Executor doesn't support hashed aggregation with DISTINCT or ORDER BY
3865- * aggregates. (Doing so would imply storing *all* the input values in
3866- * the hash table, and/or running many sorts in parallel, either of which
3867- * seems like a certain loser.) We similarly don't support ordered-set
3868- * aggregates in hashed aggregation, but that case is also included in the
3869- * numOrderedAggs count.
3870- *
3871- * Note: grouping_is_hashable() is much more expensive to check than the
3872- * other gating conditions, so we want to do it last.
3873- */
3874- can_hash = (parse -> groupClause != NIL &&
3875- agg_costs -> numOrderedAggs == 0 &&
3876- (gd ? gd -> any_hashable : grouping_is_hashable (parse -> groupClause )));
3877-
38783910 /*
38793911 * Before generating paths for grouped_rel, we first generate any possible
38803912 * partially grouped paths; that way, later code can easily consider both
38813913 * parallel and non-parallel approaches to grouping.
38823914 */
38833915 MemSet (& agg_final_costs , 0 , sizeof (AggClauseCosts ));
3884- if (can_parallel_agg (root , input_rel , grouped_rel , agg_costs ))
3916+ if (grouped_rel -> consider_parallel && input_rel -> partial_pathlist != NIL
3917+ && (flags & GROUPING_CAN_PARTIAL_AGG ) != 0 )
38853918 {
38863919 partially_grouped_rel =
38873920 create_partial_grouping_paths (root ,
@@ -6490,28 +6523,17 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel)
64906523}
64916524
64926525/*
6493- * can_parallel_agg
6526+ * can_partial_agg
64946527 *
6495- * Determines whether or not parallel grouping and/or aggregation is possible.
6528+ * Determines whether or not partial grouping and/or aggregation is possible.
64966529 * Returns true when possible, false otherwise.
64976530 */
64986531static bool
6499- can_parallel_agg (PlannerInfo * root , RelOptInfo * input_rel ,
6500- RelOptInfo * grouped_rel , const AggClauseCosts * agg_costs )
6532+ can_partial_agg (PlannerInfo * root , const AggClauseCosts * agg_costs )
65016533{
65026534 Query * parse = root -> parse ;
65036535
6504- if (!grouped_rel -> consider_parallel )
6505- {
6506- /* Not even parallel-safe. */
6507- return false;
6508- }
6509- else if (input_rel -> partial_pathlist == NIL )
6510- {
6511- /* Nothing to use as input for partial aggregate. */
6512- return false;
6513- }
6514- else if (!parse -> hasAggs && parse -> groupClause == NIL )
6536+ if (!parse -> hasAggs && parse -> groupClause == NIL )
65156537 {
65166538 /*
65176539 * We don't know how to do parallel aggregation unless we have either
0 commit comments