+ if (parse->groupClause)
+ {
+ List *groupExprs;
+
+ groupExprs = get_sortgrouplist_exprs(parse->groupClause,
+ parse->targetList);
+ *num_groups = estimate_num_groups(root,
+ groupExprs,
+ final_rel->rows);
+
+ /*
+ * In GROUP BY mode, an absolute LIMIT is relative to the number
+ * of groups not the number of tuples. If the caller gave us
+ * a fraction, keep it as-is. (In both cases, we are effectively
+ * assuming that all the groups are about the same size.)
+ */
+ if (tuple_fraction >= 1.0)
+ tuple_fraction /= *num_groups;
+
+ /*
+ * If both GROUP BY and ORDER BY are specified, we will need two
+ * levels of sort --- and, therefore, certainly need to read all
+ * the tuples --- unless ORDER BY is a subset of GROUP BY.
+ */
+ if (parse->groupClause && parse->sortClause &&
+ !pathkeys_contained_in(root->sort_pathkeys, root->group_pathkeys))
+ tuple_fraction = 0.0;
+ }
+ else if (parse->hasAggs || root->hasHavingQual)
+ {
+ /*
+ * Ungrouped aggregate will certainly want to read all the tuples,
+ * and it will deliver a single result row (so leave *num_groups 1).
+ */
+ tuple_fraction = 0.0;
+ }
+ else if (parse->distinctClause)
+ {
+ /*
+ * Since there was no grouping or aggregation, it's reasonable to
+ * assume the UNIQUE filter has effects comparable to GROUP BY.
+ * Return the estimated number of output rows for use by caller.
+ * (If DISTINCT is used with grouping, we ignore its effects for
+ * rowcount estimation purposes; this amounts to assuming the grouped
+ * rows are distinct already.)
+ */
+ List *distinctExprs;
+
+ distinctExprs = get_sortgrouplist_exprs(parse->distinctClause,
+ parse->targetList);
+ *num_groups = estimate_num_groups(root,
+ distinctExprs,
+ final_rel->rows);
+
+ /*
+ * Adjust tuple_fraction the same way as for GROUP BY, too.
+ */
+ if (tuple_fraction >= 1.0)
+ tuple_fraction /= *num_groups;
+ }
+ else
+ {
+ /*
+ * Plain non-grouped, non-aggregated query: an absolute tuple
+ * fraction can be divided by the number of tuples.
+ */
+ if (tuple_fraction >= 1.0)
+ tuple_fraction /= final_rel->rows;
+ }