1#include "duckdb/optimizer/statistics_propagator.hpp"
2#include "duckdb/planner/operator/logical_aggregate.hpp"
3
4namespace duckdb {
5
6unique_ptr<NodeStatistics> StatisticsPropagator::PropagateStatistics(LogicalAggregate &aggr,
7 unique_ptr<LogicalOperator> *node_ptr) {
8 // first propagate statistics in the child node
9 node_stats = PropagateStatistics(node_ptr&: aggr.children[0]);
10
11 // handle the groups: simply propagate statistics and assign the stats to the group binding
12 aggr.group_stats.resize(new_size: aggr.groups.size());
13 for (idx_t group_idx = 0; group_idx < aggr.groups.size(); group_idx++) {
14 auto stats = PropagateExpression(expr&: aggr.groups[group_idx]);
15 aggr.group_stats[group_idx] = stats ? stats->ToUnique() : nullptr;
16 if (!stats) {
17 continue;
18 }
19 if (aggr.grouping_sets.size() > 1) {
20 // aggregates with multiple grouping sets can introduce NULL values to certain groups
21 // FIXME: actually figure out WHICH groups can have null values introduced
22 stats->Set(StatsInfo::CAN_HAVE_NULL_VALUES);
23 continue;
24 }
25 ColumnBinding group_binding(aggr.group_index, group_idx);
26 statistics_map[group_binding] = std::move(stats);
27 }
28 // propagate statistics in the aggregates
29 for (idx_t aggregate_idx = 0; aggregate_idx < aggr.expressions.size(); aggregate_idx++) {
30 auto stats = PropagateExpression(expr&: aggr.expressions[aggregate_idx]);
31 if (!stats) {
32 continue;
33 }
34 ColumnBinding aggregate_binding(aggr.aggregate_index, aggregate_idx);
35 statistics_map[aggregate_binding] = std::move(stats);
36 }
37 // the max cardinality of an aggregate is the max cardinality of the input (i.e. when every row is a unique group)
38 return std::move(node_stats);
39}
40
41} // namespace duckdb
42