| 1 | #include "duckdb/optimizer/statistics_propagator.hpp" |
|---|---|
| 2 | #include "duckdb/planner/operator/logical_aggregate.hpp" |
| 3 | |
| 4 | namespace duckdb { |
| 5 | |
| 6 | unique_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 |