Skip to content

Commit 75898dd

Browse files
committed
opt: make functional dependency calculation deterministic
We recently added additional logic for inferring functional dependencies for join expressions. However, this logic iterates through a map, which leads to nondeterminism in which order functional dependencies are added to the FD set. Functional dependency calculation is best-effort, so this can lead to a different resulting FD set, which causes flaky tests. This patch makes the calculation deterministic by iterating instead through a `intsets.Fast` set. Fixes cockroachdb#107148 Release note: None
1 parent 06b5ba7 commit 75898dd

File tree

1 file changed

+24
-27
lines changed

1 file changed

+24
-27
lines changed

pkg/sql/opt/memo/logical_props_builder.go

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2526,57 +2526,54 @@ func (h *joinPropsHelper) addSelfJoinImpliedFDs(rel *props.Relational) {
25262526
// There are no equalities between left and right columns.
25272527
return
25282528
}
2529-
// Map from the table ID to the column ordinals within the table.
2530-
getTables := func(cols opt.ColSet) map[opt.TableID]intsets.Fast {
2531-
var tables map[opt.TableID]intsets.Fast
2529+
// Retrieve the tables that originate the given columns.
2530+
getTables := func(cols opt.ColSet) intsets.Fast {
2531+
var tables intsets.Fast
25322532
cols.ForEach(func(col opt.ColumnID) {
25332533
if tab := md.ColumnMeta(col).Table; tab != opt.TableID(0) {
2534-
if tables == nil {
2535-
tables = make(map[opt.TableID]intsets.Fast)
2536-
}
2537-
colOrds := tables[tab]
2538-
colOrds.Add(tab.ColumnOrdinal(col))
2539-
tables[tab] = colOrds
2534+
tables.Add(int(tab))
25402535
}
25412536
})
25422537
return tables
25432538
}
2544-
leftTables := getTables(leftCols)
2545-
if leftTables == nil {
2546-
return
2547-
}
2548-
rightTables := getTables(rightCols)
2549-
if rightTables == nil {
2539+
leftTables, rightTables := getTables(leftCols), getTables(rightCols)
2540+
if leftTables.Empty() || rightTables.Empty() {
25502541
return
25512542
}
2552-
for leftTable, leftTableOrds := range leftTables {
2543+
leftTables.ForEach(func(left int) {
2544+
leftTable := opt.TableID(left)
25532545
baseTabFDs := MakeTableFuncDep(md, leftTable)
2554-
for rightTable, rightTableOrds := range rightTables {
2546+
rightTables.ForEach(func(right int) {
2547+
rightTable := opt.TableID(right)
25552548
if md.TableMeta(leftTable).Table.ID() != md.TableMeta(rightTable).Table.ID() {
2556-
continue
2549+
return
25572550
}
25582551
// This is a self-join. If there are equalities between columns at the
25592552
// same ordinal positions in each (meta) table and those columns form a
25602553
// key on the base table, *every* pair of columns at the same ordinal
25612554
// position is equal.
25622555
var eqCols opt.ColSet
2563-
colOrds := leftTableOrds.Intersection(rightTableOrds)
2564-
for colOrd, ok := colOrds.Next(0); ok; colOrd, ok = colOrds.Next(colOrd + 1) {
2556+
var outColOrds intsets.Fast
2557+
numCols := md.Table(leftTable).ColumnCount()
2558+
for colOrd := 0; colOrd < numCols; colOrd++ {
25652559
leftCol, rightCol := leftTable.ColumnID(colOrd), rightTable.ColumnID(colOrd)
2566-
if rel.FuncDeps.AreColsEquiv(leftCol, rightCol) {
2567-
eqCols.Add(leftCol)
2568-
eqCols.Add(rightCol)
2560+
if rel.OutputCols.Contains(leftCol) && rel.OutputCols.Contains(rightCol) {
2561+
outColOrds.Add(colOrd)
2562+
if rel.FuncDeps.AreColsEquiv(leftCol, rightCol) {
2563+
eqCols.Add(leftCol)
2564+
eqCols.Add(rightCol)
2565+
}
25692566
}
25702567
}
25712568
if !eqCols.Empty() && baseTabFDs.ColsAreStrictKey(eqCols) {
25722569
// Add equalities between each pair of columns at the same ordinal
25732570
// position, ignoring those that aren't part of the output.
2574-
for colOrd, ok := colOrds.Next(0); ok; colOrd, ok = colOrds.Next(colOrd + 1) {
2571+
outColOrds.ForEach(func(colOrd int) {
25752572
rel.FuncDeps.AddEquivalency(leftTable.ColumnID(colOrd), rightTable.ColumnID(colOrd))
2576-
}
2573+
})
25772574
}
2578-
}
2579-
}
2575+
})
2576+
})
25802577
}
25812578

25822579
func (h *joinPropsHelper) cardinality() props.Cardinality {

0 commit comments

Comments
 (0)