Skip to content

Commit

Permalink
Merge #105931
Browse files Browse the repository at this point in the history
105931: colexec: don't infinite loop cross-join with zero-column left input r=DrewKimball a=DrewKimball

Previously, the cross-joiner wouldn't advance its internal state when its left input projected no columns. This would result in an infinite loop as the right rows were repeatedly emitted. This patch advances the state when there are no left columns as if values from the left side were emitted.

Fixes #105882

Release note (bug fix): Fixed a bug introduced in v22.1 that could cause a join to infinite-loop in rare cases when (1) the join filter is not an equality and (2) no columns from the left input are returned.

Co-authored-by: Drew Kimball <[email protected]>
  • Loading branch information
craig[bot] and DrewKimball committed Jul 15, 2023
2 parents 3c9131b + 72c8fa1 commit b4dfdc0
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
50 changes: 50 additions & 0 deletions pkg/sql/colexec/colexecjoin/crossjoiner.eg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions pkg/sql/colexec/colexecjoin/crossjoiner_tmpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,32 @@ func buildFromLeftBatch(b *crossJoinerBase, currentBatch coldata.Batch, sel []in
colexecerror.InternalError(errors.AssertionFailedf("unhandled type %s", b.left.types[colIdx].String()))
}
}
// If there are no columns projected from the left input, simply advance the
// cross-joiner state according to the number of input rows.
if len(b.left.types) == 0 {
outStartIdx := destStartIdx
for bs.curSrcStartIdx < leftSrcEndIdx && outStartIdx < outputCapacity {
// Repeat each row leftNumRepeats times.
// {{/* toAppend will always be positive. */}}
toAppend := leftNumRepeats - bs.numRepeatsIdx
if outStartIdx+toAppend > outputCapacity {
// We don't have enough space to repeat the current
// value the required number of times, so we'll have
// to continue from here on the next call.
toAppend = outputCapacity - outStartIdx
bs.numRepeatsIdx += toAppend
} else {
// We fully processed the current tuple for the
// current column, and before moving on to the next
// one, we need to reset numRepeatsIdx (so that the
// next tuple would be repeated leftNumRepeats
// times).
bs.curSrcStartIdx++
bs.numRepeatsIdx = 0
}
outStartIdx += toAppend
}
}
}

// buildFromLeftInput builds part of the output of a cross join that comes from
Expand Down
15 changes: 15 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/cross_join
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,18 @@ SELECT *
)
WHERE r < .01
LIMIT 1

# Regression test for #105882 - don't infinite loop when the left input has
# no columns.
statement ok
CREATE TABLE t105882 (c0 INT);
UPSERT INTO t105882 (c0) VALUES(1);

query I
SELECT (
SELECT count(t2.rowid) FROM t105882 t2
WHERE ((t1.rowid) IN (SELECT max(t3.rowid) FROM t105882 t3))
)
FROM t105882 t1;
----
1

0 comments on commit b4dfdc0

Please sign in to comment.