executor: always decode the value first and then the handle (#22073)
This commit is contained in:
@ -963,7 +963,7 @@ func (b *executorBuilder) buildUnionScanFromReader(reader Executor, v *plannerco
|
||||
}
|
||||
return x
|
||||
}
|
||||
// If reader is union, it means a partitiont table and we should transfer as above.
|
||||
// If reader is union, it means a partition table and we should transfer as above.
|
||||
if x, ok := reader.(*UnionExec); ok {
|
||||
for i, child := range x.children {
|
||||
x.children[i] = b.buildUnionScanFromReader(child, v)
|
||||
|
||||
@ -17,10 +17,12 @@ import (
|
||||
. "github.com/pingcap/check"
|
||||
"github.com/pingcap/tidb/errno"
|
||||
"github.com/pingcap/tidb/store/tikv"
|
||||
"github.com/pingcap/tidb/util/collate"
|
||||
"github.com/pingcap/tidb/util/testkit"
|
||||
)
|
||||
|
||||
type testClusteredSuite struct{ *baseTestSuite }
|
||||
type testClusteredSerialSuite struct{ *testClusteredSuite }
|
||||
|
||||
func (s *testClusteredSuite) SetUpTest(c *C) {
|
||||
}
|
||||
@ -184,6 +186,28 @@ func (s *testClusteredSuite) TestClusteredPrefixingPrimaryKey(c *C) {
|
||||
tk.MustExec("admin check table t;")
|
||||
}
|
||||
|
||||
// Test for union scan in prefixed clustered index table.
|
||||
// See https://github.com/pingcap/tidb/issues/22069.
|
||||
func (s *testClusteredSerialSuite) TestClusteredUnionScanOnPrefixingPrimaryKey(c *C) {
|
||||
originCollate := collate.NewCollationEnabled()
|
||||
collate.SetNewCollationEnabledForTest(false)
|
||||
defer collate.SetNewCollationEnabledForTest(originCollate)
|
||||
tk := s.newTK(c)
|
||||
tk.MustExec("drop table if exists t;")
|
||||
tk.MustExec("create table t (col_1 varchar(255), col_2 tinyint, primary key idx_1 (col_1(1)));")
|
||||
tk.MustExec("insert into t values ('aaaaa', -38);")
|
||||
tk.MustExec("insert into t values ('bbbbb', -48);")
|
||||
|
||||
tk.MustExec("begin PESSIMISTIC;")
|
||||
tk.MustExec("update t set col_2 = 47 where col_1 in ('aaaaa') order by col_1,col_2;")
|
||||
tk.MustQuery("select * from t;").Check(testkit.Rows("aaaaa 47", "bbbbb -48"))
|
||||
tk.MustGetErrCode("insert into t values ('bb', 0);", errno.ErrDupEntry)
|
||||
tk.MustGetErrCode("insert into t values ('aa', 0);", errno.ErrDupEntry)
|
||||
tk.MustExec("commit;")
|
||||
tk.MustQuery("select * from t;").Check(testkit.Rows("aaaaa 47", "bbbbb -48"))
|
||||
tk.MustExec("admin check table t;")
|
||||
}
|
||||
|
||||
func (s *testClusteredSuite) TestClusteredWithOldRowFormat(c *C) {
|
||||
tk := s.newTK(c)
|
||||
tk.Se.GetSessionVars().RowEncoder.Enable = false
|
||||
|
||||
@ -119,6 +119,7 @@ var _ = Suite(&testSuite6{&baseTestSuite{}})
|
||||
var _ = Suite(&testSuite7{&baseTestSuite{}})
|
||||
var _ = Suite(&testSuite8{&baseTestSuite{}})
|
||||
var _ = Suite(&testClusteredSuite{&baseTestSuite{}})
|
||||
var _ = SerialSuites(&testClusteredSerialSuite{&testClusteredSuite{&baseTestSuite{}}})
|
||||
var _ = SerialSuites(&testShowStatsSuite{&baseTestSuite{}})
|
||||
var _ = Suite(&testBypassSuite{})
|
||||
var _ = Suite(&testUpdateSuite{})
|
||||
|
||||
@ -222,6 +222,9 @@ func (decoder *ChunkDecoder) DecodeToChunk(rowData []byte, handle kv.Handle, chk
|
||||
continue
|
||||
}
|
||||
|
||||
// Only try to decode handle when there is no corresponding column in the value.
|
||||
// This is because the information in handle may be incomplete in some cases.
|
||||
// For example, prefixed clustered index like 'primary key(col1(1))' only store the leftmost 1 char in the handle.
|
||||
if decoder.tryAppendHandleColumn(colIdx, col, handle, chk) {
|
||||
continue
|
||||
}
|
||||
@ -385,10 +388,6 @@ func (decoder *BytesDecoder) decodeToBytesInternal(outputOffset map[int64]int, h
|
||||
tp := fieldType2Flag(col.Ft.Tp, col.Ft.Flag&mysql.UnsignedFlag == 0)
|
||||
colID := col.ID
|
||||
offset := outputOffset[colID]
|
||||
if decoder.tryDecodeHandle(values, offset, col, handle, cacheBytes) {
|
||||
continue
|
||||
}
|
||||
|
||||
idx, isNil, notFound := r.findColID(colID)
|
||||
if !notFound && !isNil {
|
||||
val := r.getData(idx)
|
||||
@ -396,6 +395,13 @@ func (decoder *BytesDecoder) decodeToBytesInternal(outputOffset map[int64]int, h
|
||||
continue
|
||||
}
|
||||
|
||||
// Only try to decode handle when there is no corresponding column in the value.
|
||||
// This is because the information in handle may be incomplete in some cases.
|
||||
// For example, prefixed clustered index like 'primary key(col1(1))' only store the leftmost 1 char in the handle.
|
||||
if decoder.tryDecodeHandle(values, offset, col, handle, cacheBytes) {
|
||||
continue
|
||||
}
|
||||
|
||||
if isNil {
|
||||
values[offset] = []byte{NilFlag}
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user