Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: fix bug that UnionScan can't keep order caused wrong result #33218

Merged
merged 10 commits into from
Mar 22, 2022
29 changes: 29 additions & 0 deletions executor/mem_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ func (m *memIndexReader) getMemRows(ctx context.Context) ([][]types.Datum, error
}

mutableRow := chunk.MutRowFromTypes(m.retFieldTypes)

// TODO: `IterReverse` is not used... to get the same effect, reverse the kv ranges first,
// Then reverse the whole added rows.
// [99, 100] [44, 45] [1, 3] => [1, 3] [44, 45] [99, 100] => [100, 99] [45, 44] [3 1]
if m.desc {
Copy link
Collaborator

@lcwangchao lcwangchao Mar 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may still cause bugs when the int is signed, try the following:

create global temporary table `tmp2` (id bigint primary key) on commit delete rows;
begin;
insert into tmp2 values(-2),(-1),(0),(1),(2);
-- The following  query will give a wrong result: 
-- expected 2, 1, 0, -1, -2 , actual: -1, -2, 2, 1
select * from tmp2 where id <= -1 or id > 0 order by id desc; 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update, PTAL @lcwangchao

reverseKVRanges(m.kvRanges)
}

err := iterTxnMemBuffer(m.ctx, m.cacheTable, m.kvRanges, func(key, value []byte) error {
data, err := m.decodeIndexKeyValue(key, value, tps)
if err != nil {
Expand Down Expand Up @@ -239,6 +247,13 @@ func (m *memTableReader) getMemRows(ctx context.Context) ([][]types.Datum, error
defer span1.Finish()
opentracing.ContextWithSpan(ctx, span1)
}

tiancaiamao marked this conversation as resolved.
Show resolved Hide resolved
// TODO: `IterReverse` is not used... to get the same effect, reverse the kv ranges first,
// Then reverse the whole added rows.
if m.desc {
reverseKVRanges(m.kvRanges)
}

mutableRow := chunk.MutRowFromTypes(m.retFieldTypes)
err := iterTxnMemBuffer(m.ctx, m.cacheTable, m.kvRanges, func(key, value []byte) error {
row, err := m.decodeRecordKeyValue(key, value)
Expand Down Expand Up @@ -407,6 +422,7 @@ func iterTxnMemBuffer(ctx sessionctx.Context, cacheTable kv.MemBuffer, kvRanges
if len(iter.Value()) == 0 {
continue
}

err = fn(iter.Key(), iter.Value())
if err != nil {
return err
Expand Down Expand Up @@ -435,6 +451,12 @@ func getSnapIter(ctx sessionctx.Context, cacheTable kv.MemBuffer, rg kv.KeyRange
return snapCacheIter, nil
}

func reverseKVRanges(rows []kv.KeyRange) {
for i, j := 0, len(rows)-1; i < j; i, j = i+1, j-1 {
rows[i], rows[j] = rows[j], rows[i]
}
}

func reverseDatumSlice(rows [][]types.Datum) {
for i, j := 0, len(rows)-1; i < j; i, j = i+1, j-1 {
rows[i], rows[j] = rows[j], rows[i]
Expand Down Expand Up @@ -540,6 +562,13 @@ func (m *memIndexLookUpReader) getMemRows(ctx context.Context) ([][]types.Datum,
numHandles := 0
for i, tbl := range tbls {
m.idxReader.kvRanges = kvRanges[i]
// TODO: `IterReverse` is not used... to get the same effect, reverse the kv ranges first,
// Then reverse the whole added rows.
// [99, 100] [44, 45] [1, 3] => [1, 3] [44, 45] [99, 100] => [100, 99] [45, 44] [3 1]
if m.desc {
reverseKVRanges(m.idxReader.kvRanges)
}

handles, err := m.idxReader.getMemRowsHandle()
if err != nil {
return nil, err
Expand Down
12 changes: 3 additions & 9 deletions planner/core/handle_cols.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,9 @@ func (ib *IntHandleCols) NumCols() int {

// Compare implements the kv.HandleCols interface.
func (ib *IntHandleCols) Compare(a, b []types.Datum, ctors []collate.Collator) (int, error) {
aInt := a[ib.col.Index].GetInt64()
bInt := b[ib.col.Index].GetInt64()
if aInt == bInt {
return 0, nil
}
if aInt < bInt {
return -1, nil
}
return 1, nil
aVal := &a[ib.col.Index]
bVal := &b[ib.col.Index]
return aVal.Compare(nil, bVal, ctors[ib.col.Index])
}

// GetFieldsTypes implements the kv.HandleCols interface.
Expand Down
72 changes: 72 additions & 0 deletions planner/core/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6243,3 +6243,75 @@ func TestTiFlashPartitionTableScan(t *testing.T) {
tk.MustExec("drop table rp_t;")
tk.MustExec("drop table hp_t;")
}

func TestIssue33175(t *testing.T) {
store, _, clean := testkit.CreateMockStoreAndDomain(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table t (id bigint(45) unsigned not null, c varchar(20), primary key(id));")
tk.MustExec("insert into t values (9734095886065816707, 'a'), (10353107668348738101, 'b'), (0, 'c');")
tk.MustExec("begin")
tk.MustExec("insert into t values (33, 'd');")
tk.MustQuery("select max(id) from t;").Check(testkit.Rows("10353107668348738101"))
tk.MustExec("rollback")

tk.MustExec("alter table t cache")
for {
tk.MustQuery("select max(id) from t;").Check(testkit.Rows("10353107668348738101"))
if tk.Session().GetSessionVars().StmtCtx.ReadFromTableCache {
break
}
}

// // With subquery, like the original issue case.
for {
tk.MustQuery("select * from t where id > (select max(id) from t where t.id > 0);").Check(testkit.Rows())
if tk.Session().GetSessionVars().StmtCtx.ReadFromTableCache {
break
}
}

// Test order by desc / asc.
tk.MustQuery("select id from t order by id desc;").Check(testkit.Rows(
"10353107668348738101",
"9734095886065816707",
"0"))

tk.MustQuery("select id from t order by id asc;").Check(testkit.Rows(
"0",
"9734095886065816707",
"10353107668348738101"))

tk.MustExec("alter table t nocache")
tk.MustExec("drop table t")

// Cover more code that use union scan
// TableReader/IndexReader/IndexLookup
for idx, q := range []string{
"create temporary table t (id bigint unsigned, c int default null, index(id))",
"create temporary table t (id bigint unsigned primary key)",
} {
tk.MustExec(q)
tk.MustExec("insert into t(id) values (1), (3), (9734095886065816707), (9734095886065816708)")
tk.MustQuery("select min(id) from t").Check(testkit.Rows("1"))
tk.MustQuery("select max(id) from t").Check(testkit.Rows("9734095886065816708"))
tk.MustQuery("select id from t order by id asc").Check(testkit.Rows(
"1", "3", "9734095886065816707", "9734095886065816708"))
tk.MustQuery("select id from t order by id desc").Check(testkit.Rows(
"9734095886065816708", "9734095886065816707", "3", "1"))
if idx == 0 {
tk.MustQuery("select * from t order by id asc").Check(testkit.Rows(
"1 <nil>",
"3 <nil>",
"9734095886065816707 <nil>",
"9734095886065816708 <nil>"))
tk.MustQuery("select * from t order by id desc").Check(testkit.Rows(
"9734095886065816708 <nil>",
"9734095886065816707 <nil>",
"3 <nil>",
"1 <nil>"))
}
tk.MustExec("drop table t")
}
}