Coverage Report

Created: 2025-09-05 08:05

/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "duckdb/optimizer/common_aggregate_optimizer.hpp"
2
3
#include "duckdb/parser/expression_map.hpp"
4
#include "duckdb/planner/expression/bound_columnref_expression.hpp"
5
#include "duckdb/planner/operator/logical_aggregate.hpp"
6
7
namespace duckdb {
8
9
529k
void CommonAggregateOptimizer::StandardVisitOperator(LogicalOperator &op) {
10
529k
  VisitOperatorChildren(op);
11
529k
  if (!aggregate_map.empty()) {
12
2.97k
    VisitOperatorExpressions(op);
13
2.97k
  }
14
529k
}
15
16
529k
void CommonAggregateOptimizer::VisitOperator(LogicalOperator &op) {
17
529k
  switch (op.type) {
18
24.9k
  case LogicalOperatorType::LOGICAL_UNION:
19
29.8k
  case LogicalOperatorType::LOGICAL_EXCEPT:
20
29.8k
  case LogicalOperatorType::LOGICAL_INTERSECT:
21
29.8k
  case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE:
22
229k
  case LogicalOperatorType::LOGICAL_PROJECTION: {
23
229k
    CommonAggregateOptimizer common_aggregate;
24
229k
    common_aggregate.StandardVisitOperator(op);
25
229k
    return;
26
29.8k
  }
27
300k
  default:
28
300k
    break;
29
529k
  }
30
31
300k
  StandardVisitOperator(op);
32
300k
  if (op.type == LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY) {
33
58.5k
    ExtractCommonAggregates(op.Cast<LogicalAggregate>());
34
58.5k
  }
35
300k
}
36
37
unique_ptr<Expression> CommonAggregateOptimizer::VisitReplace(BoundColumnRefExpression &expr,
38
55.9k
                                                              unique_ptr<Expression> *expr_ptr) {
39
  // check if this column ref points to an aggregate that was remapped; if it does we remap it
40
55.9k
  auto entry = aggregate_map.find(expr.binding);
41
55.9k
  if (entry != aggregate_map.end()) {
42
3.23k
    expr.binding = entry->second;
43
3.23k
  }
44
55.9k
  return nullptr;
45
55.9k
}
46
47
58.5k
void CommonAggregateOptimizer::ExtractCommonAggregates(LogicalAggregate &aggr) {
48
58.5k
  expression_map_t<idx_t> aggregate_remap;
49
58.5k
  idx_t total_erased = 0;
50
222k
  for (idx_t i = 0; i < aggr.expressions.size(); i++) {
51
163k
    idx_t original_index = i + total_erased;
52
163k
    auto entry = aggregate_remap.find(*aggr.expressions[i]);
53
163k
    if (entry == aggregate_remap.end()) {
54
      // aggregate does not exist yet: add it to the map
55
160k
      aggregate_remap[*aggr.expressions[i]] = i;
56
160k
      if (i != original_index) {
57
        // this aggregate is not erased, however an aggregate BEFORE it has been erased
58
        // so we need to remap this aggregate
59
7
        ColumnBinding original_binding(aggr.aggregate_index, original_index);
60
7
        ColumnBinding new_binding(aggr.aggregate_index, i);
61
7
        aggregate_map[original_binding] = new_binding;
62
7
      }
63
160k
    } else {
64
      // aggregate already exists! we can remove this entry
65
3.12k
      total_erased++;
66
3.12k
      aggr.expressions.erase_at(i);
67
3.12k
      i--;
68
      // we need to remap any references to this aggregate so they point to the other aggregate
69
3.12k
      ColumnBinding original_binding(aggr.aggregate_index, original_index);
70
3.12k
      ColumnBinding new_binding(aggr.aggregate_index, entry->second);
71
3.12k
      aggregate_map[original_binding] = new_binding;
72
3.12k
    }
73
163k
  }
74
58.5k
}
75
76
} // namespace duckdb