duckdb/arrow: CWE-407 scan — 4 DuckDB defects, 2 Arrow defects

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.
This commit is contained in:
russell@unturf.com 2026-03-30 10:10:27 -04:00
parent 0772cf539a
commit 6b975a3b9e
13 changed files with 959 additions and 184 deletions

View file

@ -0,0 +1,39 @@
# UNDF: (leave blank)
--- a/pkg/planner/core/rule/rule_predicate_simplification.go
+++ b/pkg/planner/core/rule/rule_predicate_simplification.go
@@ -228,7 +228,6 @@ func mergeInAndNotEQLists(sctx base.PlanContext, predicates []expression.Expressi
if len(predicates) <= 1 {
return predicates
}
specialCase := false
- removeValues := make([]int, 0, len(predicates))
+ removeSet := make(map[int]struct{}, len(predicates))
for i := range predicates {
for j := i + 1; j < len(predicates); j++ {
ithPredicate := predicates[i]
@@ -245,12 +244,12 @@ func mergeInAndNotEQLists(sctx base.PlanContext, predicates []expression.Expressi
if !specialCase {
- removeValues = append(removeValues, i)
+ removeSet[i] = struct{}{}
}
} else if iType == inListPredicate && jType == notEqualPredicate {
predicates[i], specialCase = updateInPredicate(sctx, ithPredicate, jthPredicate)
if maybeOverOptimized4PlanCache {
sctx.GetSessionVars().StmtCtx.SetSkipPlanCache("NE/INList simplification is triggered")
}
if !specialCase {
- removeValues = append(removeValues, j)
+ removeSet[j] = struct{}{}
}
}
}
}
newValues := make([]expression.Expression, 0, len(predicates))
for i, value := range predicates {
- if !(slices.Contains(removeValues, i)) {
+ if _, remove := removeSet[i]; !remove {
newValues = append(newValues, value)
}
}
return newValues
}

View file

@ -0,0 +1,31 @@
# UNDF: (leave blank)
--- a/pkg/table/tables/partition.go
+++ b/pkg/table/tables/partition.go
@@ -640,13 +640,18 @@ func (pg *ListPartitionGroup) intersect(otherPg ListPartitionGroup) bool {
if pg.PartIdx != otherPg.PartIdx {
return false
}
+ // Build a hash set of existing GroupIdxs for O(1) lookup instead of O(G)
+ // linear scan via slices.Contains, making the overall intersect O(G) not O(G²).
+ existing := make(map[int]struct{}, len(pg.GroupIdxs))
+ for _, gidx := range pg.GroupIdxs {
+ existing[gidx] = struct{}{}
+ }
var groupIdxs []int
for _, gidx := range otherPg.GroupIdxs {
- if pg.findGroupIdx(gidx) {
+ if _, ok := existing[gidx]; ok {
groupIdxs = append(groupIdxs, gidx)
}
}
pg.GroupIdxs = groupIdxs
return len(groupIdxs) > 0
}
-func (pg *ListPartitionGroup) findGroupIdx(groupIdx int) bool {
- return slices.Contains(pg.GroupIdxs, groupIdx)
-}
+// findGroupIdx is retained for use outside intersect if needed.
+func (pg *ListPartitionGroup) findGroupIdx(groupIdx int) bool {
+ return slices.Contains(pg.GroupIdxs, groupIdx)
+}