29 lines
1.3 KiB
Diff
29 lines
1.3 KiB
Diff
# UNDF: UNDF-2026-000000766
|
||
# 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;
|
||
}
|
||
}
|