DuckDB (C++ query engine): - duckdb-0001: Binder::AddCorrelatedColumn vector dedup O(C²) MEDIUM 200x - duckdb-0002: HasCorrelatedExpressions vector scan O(N×M) MEDIUM 100x - duckdb-0003: ComputeOverlappingBindings vector scan O(N×H) MEDIUM 219x - duckdb-0004: Deliminator group-join binding check O(G×J) MEDIUM 125x Apache Arrow (C++ analytics): - arrow-0001: AsofJoin IsTimeOrKeyColumn vector scan O(F×K) MEDIUM 114x - arrow-0002: Scanner AddFieldsNeededForFilter vector dedup O(F×C) MEDIUM 250x All 6/6 unit tests PASS.
28 lines
1.3 KiB
Diff
28 lines
1.3 KiB
Diff
# UNDF: (leave blank)
|
||
# DuckDB CWE-407: Deliminator aggregate group vs join binding check O(G×J)
|
||
# File: src/optimizer/deliminator.cpp
|
||
# Severity: MEDIUM — optimizer path for delim-join elimination
|
||
# Ratio: ~125x at G=J=250 (wide GROUP BY with many join conditions)
|
||
#
|
||
# The deliminator optimization checks whether all aggregate groups appear in
|
||
# the join bindings. It loops over aggr.groups (G) and calls std::find on
|
||
# join_bindings vector (J) for each — O(G×J).
|
||
# Fix: convert join_bindings to unordered_set for O(1) lookup.
|
||
--- a/src/optimizer/deliminator.cpp
|
||
+++ b/src/optimizer/deliminator.cpp
|
||
@@ -434,12 +434,14 @@
|
||
D_ASSERT(current_op.get().type == LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY);
|
||
const auto &aggr = current_op.get().Cast<LogicalAggregate>();
|
||
if (!aggr.grouping_functions.empty()) {
|
||
return;
|
||
}
|
||
|
||
+ std::unordered_set<ColumnBinding, ColumnBindingHashFunction> join_binding_set(join_bindings.begin(), join_bindings.end());
|
||
+
|
||
for (idx_t group_idx = 0; group_idx < aggr.groups.size(); group_idx++) {
|
||
- if (std::find(join_bindings.begin(), join_bindings.end(),
|
||
- ColumnBinding(aggr.group_index, ProjectionIndex(group_idx))) == join_bindings.end()) {
|
||
+ if (join_binding_set.find(ColumnBinding(aggr.group_index, ProjectionIndex(group_idx))) == join_binding_set.end()) {
|
||
return;
|
||
}
|
||
}
|