Skip to content

Commit dd052f9

Browse files
committed
sql: add fetch row count assertions in row-by-row index joiner
Assertions have been added to the join reader that ensure that an index join fetches the expected number of rows. Informs #135696 Release note: None
1 parent c117e93 commit dd052f9

File tree

1 file changed

+39
-0
lines changed

1 file changed

+39
-0
lines changed

pkg/sql/rowexec/joinreader.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ type joinReader struct {
209209
// curBatchInputRowCount is the number of input rows in the current batch.
210210
curBatchInputRowCount int64
211211

212+
// lockingWaitPolicy is the wait policy for the underlying rowFetcher.
213+
lockingWaitPolicy descpb.ScanLockingWaitPolicy
214+
212215
// State variables for each batch of input rows.
213216
scratchInputRows rowenc.EncDatumRows
214217
// resetScratchWhenReadingInput tracks whether scratchInputRows needs to be
@@ -377,6 +380,7 @@ func newJoinReader(
377380
outputGroupContinuationForLeftRow: spec.OutputGroupContinuationForLeftRow,
378381
parallelize: parallelize,
379382
readerType: readerType,
383+
lockingWaitPolicy: spec.LockingWaitPolicy,
380384
txn: txn,
381385
usesStreamer: useStreamer,
382386
limitHintHelper: execinfra.MakeLimitHintHelper(spec.LimitHint, post),
@@ -930,6 +934,13 @@ func (jr *joinReader) readInput() (
930934
jr.resetScratchWhenReadingInput = false
931935
}
932936

937+
// Assert that the correct number of rows were fetched in the last batch,
938+
// for index joins.
939+
if err := jr.assertIndexJoinRowCounts(); err != nil {
940+
jr.MoveToDraining(err)
941+
return jrStateUnknown, nil, jr.DrainHelper()
942+
}
943+
933944
// Read the next batch of input rows.
934945
for {
935946
var encDatumRow rowenc.EncDatumRow
@@ -1103,6 +1114,34 @@ func (jr *joinReader) readInput() (
11031114
return jrFetchingLookupRows, outRow, nil
11041115
}
11051116

1117+
// assertIndexJoinRowCounts performs assertions to prevent silently returning
1118+
// incorrect results, e.g., if an index is corrupt. In the common case, the
1119+
// number of fetched rows in an index join should be equal to the number of
1120+
// input rows. The only exception is when the locking wait policy is
1121+
// SKIP LOCKED, in which case the number of fetched rows may be less than
1122+
// the number of input rows, but never greater.
1123+
func (jr *joinReader) assertIndexJoinRowCounts() error {
1124+
if jr.readerType != indexJoinReaderType {
1125+
return nil
1126+
}
1127+
if jr.lockingWaitPolicy == descpb.ScanLockingWaitPolicy_SKIP_LOCKED {
1128+
if jr.curBatchRowsRead > jr.curBatchInputRowCount {
1129+
return errors.AssertionFailedf(
1130+
"expected to fetch no more than %d rows, found %d",
1131+
jr.curBatchInputRowCount, jr.curBatchRowsRead,
1132+
)
1133+
}
1134+
} else {
1135+
if jr.curBatchRowsRead != jr.curBatchInputRowCount {
1136+
return errors.AssertionFailedf(
1137+
"expected to fetch %d rows, found %d",
1138+
jr.curBatchInputRowCount, jr.curBatchRowsRead,
1139+
)
1140+
}
1141+
}
1142+
return nil
1143+
}
1144+
11061145
var noHomeRegionError = pgerror.Newf(pgcode.QueryHasNoHomeRegion,
11071146
"Query has no home region. Try using a lower LIMIT value or running the query from a different region. %s",
11081147
sqlerrors.EnforceHomeRegionFurtherInfo)

0 commit comments

Comments
 (0)