Skip to content

Commit

Permalink
executor: correct range calculation for CHAR column (#10124) (#10455)
Browse files Browse the repository at this point in the history
  • Loading branch information
zz-jason authored May 14, 2019
1 parent 2222ffa commit 524d6c6
Show file tree
Hide file tree
Showing 5 changed files with 397 additions and 8 deletions.
1 change: 1 addition & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ var _ = Suite(&testContextOptionSuite{})
var _ = Suite(&testBypassSuite{})
var _ = Suite(&testUpdateSuite{})
var _ = Suite(&testOOMSuite{})
var _ = Suite(&testPointGetSuite{})

type testSuite struct {
cluster *mocktikv.Cluster
Expand Down
18 changes: 12 additions & 6 deletions executor/point_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/chunk"
"github.com/pingcap/tidb/util/codec"
"github.com/pingcap/tidb/util/ranger"
"golang.org/x/net/context"
)

Expand Down Expand Up @@ -86,8 +87,8 @@ func (e *PointGetExecutor) Next(ctx context.Context, chk *chunk.Chunk) error {
}
if e.idxInfo != nil {
idxKey, err1 := e.encodeIndexKey()
if err1 != nil {
return errors.Trace(err1)
if err1 != nil && !kv.ErrNotExist.Equal(err1) {
return err1
}

handleVal, err1 := e.get(idxKey)
Expand Down Expand Up @@ -132,16 +133,21 @@ func (e *PointGetExecutor) Next(ctx context.Context, chk *chunk.Chunk) error {
return e.decodeRowValToChunk(val, chk)
}

func (e *PointGetExecutor) encodeIndexKey() ([]byte, error) {
func (e *PointGetExecutor) encodeIndexKey() (_ []byte, err error) {
sc := e.ctx.GetSessionVars().StmtCtx
for i := range e.idxVals {
colInfo := e.tblInfo.Columns[e.idxInfo.Columns[i].Offset]
casted, err := table.CastValue(e.ctx, e.idxVals[i], colInfo)
if colInfo.Tp == mysql.TypeString || colInfo.Tp == mysql.TypeVarString || colInfo.Tp == mysql.TypeVarchar {
e.idxVals[i], err = ranger.HandlePadCharToFullLength(sc, &colInfo.FieldType, e.idxVals[i])
} else {
e.idxVals[i], err = table.CastValue(e.ctx, e.idxVals[i], colInfo)
}
if err != nil {
return nil, errors.Trace(err)
}
e.idxVals[i] = casted
}
encodedIdxVals, err := codec.EncodeKey(e.ctx.GetSessionVars().StmtCtx, nil, e.idxVals...)

encodedIdxVals, err := codec.EncodeKey(sc, nil, e.idxVals...)
if err != nil {
return nil, errors.Trace(err)
}
Expand Down
287 changes: 286 additions & 1 deletion executor/point_get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,57 @@
package executor_test

import (
"fmt"

. "github.com/pingcap/check"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/session"
"github.com/pingcap/tidb/store/mockstore"
"github.com/pingcap/tidb/store/tikv"
"github.com/pingcap/tidb/util/testkit"
)

func (s *testSuite) TestPointGet(c *C) {
type testPointGetSuite struct {
store kv.Storage
dom *domain.Domain
cli *checkRequestClient
}

func (s *testPointGetSuite) SetUpSuite(c *C) {
cli := &checkRequestClient{}
hijackClient := func(c tikv.Client) tikv.Client {
cli.Client = c
return cli
}
s.cli = cli

var err error
s.store, err = mockstore.NewMockTikvStore(
mockstore.WithHijackClient(hijackClient),
)
c.Assert(err, IsNil)
s.dom, err = session.BootstrapSession(s.store)
c.Assert(err, IsNil)
s.dom.SetStatsUpdating(true)
}

func (s *testPointGetSuite) TearDownSuite(c *C) {
s.dom.Close()
s.store.Close()
}

func (s *testPointGetSuite) TearDownTest(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
r := tk.MustQuery("show tables")
for _, tb := range r.Rows() {
tableName := tb[0]
tk.MustExec(fmt.Sprintf("drop table %v", tableName))
}
}

func (s *testPointGetSuite) TestPointGet(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
tk.MustExec("create table point (id int primary key, c int, d varchar(10), unique c_d (c, d))")
Expand Down Expand Up @@ -55,3 +101,242 @@ func (s *testSuite) TestPointGet(c *C) {
`5 5 6 5 6 7 6 7 7`,
))
}

func (s *testPointGetSuite) TestPointGetCharPK(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test;`)
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t(a char(2) primary key, b char(2));`)
tk.MustExec(`insert into t values("aa", "bb");`)

// Test truncate without sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="";`)
tk.MustPointGet(`select * from t where a = "aa";`).Check(testkit.Rows(`aa bb`))
tk.MustPointGet(`select * from t where a = "aab";`).Check(testkit.Rows())

// Test truncate with sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustPointGet(`select * from t where a = "aa";`).Check(testkit.Rows(`aa bb`))
tk.MustPointGet(`select * from t where a = "aab";`).Check(testkit.Rows())

tk.MustExec(`truncate table t;`)
tk.MustExec(`insert into t values("a ", "b ");`)

// Test trailing spaces without sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows(`a b`))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())

// Test trailing spaces with sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())

// // Test CHAR BINARY.
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t(a char(2) binary primary key, b char(2));`)
tk.MustExec(`insert into t values(" ", " ");`)
tk.MustExec(`insert into t values("a ", "b ");`)

// Test trailing spaces without sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows(`a b`))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))

// Test trailing spaces with sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows(`a b`))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
}

func (s *testPointGetSuite) TestIndexLookupCharPK(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test;`)
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t(a char(2) primary key, b char(2));`)
tk.MustExec(`insert into t values("aa", "bb");`)

// Test truncate without sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="";`)
tk.MustIndexLookup(`select * from t tmp where a = "aa";`).Check(testkit.Rows(`aa bb`))
tk.MustIndexLookup(`select * from t tmp where a = "aab";`).Check(testkit.Rows())

// Test truncate with sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustIndexLookup(`select * from t tmp where a = "aa";`).Check(testkit.Rows(`aa bb`))
tk.MustIndexLookup(`select * from t tmp where a = "aab";`).Check(testkit.Rows())

tk.MustExec(`truncate table t;`)
tk.MustExec(`insert into t values("a ", "b ");`)

// Test trailing spaces without sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="";`)
tk.MustIndexLookup(`select * from t tmp where a = "a";`).Check(testkit.Rows(`a b`))
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows())

// Test trailing spaces with sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustIndexLookup(`select * from t tmp where a = "a";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows())

// Test CHAR BINARY.
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t(a char(2) binary primary key, b char(2));`)
tk.MustExec(`insert into t values(" ", " ");`)
tk.MustExec(`insert into t values("a ", "b ");`)

// Test trailing spaces without sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="";`)
tk.MustIndexLookup(`select * from t tmp where a = "a";`).Check(testkit.Rows(`a b`))
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustIndexLookup(`select * from t tmp where a = " ";`).Check(testkit.Rows(` `))
tk.MustIndexLookup(`select * from t tmp where a = " ";`).Check(testkit.Rows(` `))
tk.MustIndexLookup(`select * from t tmp where a = " ";`).Check(testkit.Rows(` `))

// Test trailing spaces with sql mode `PAD_CHAR_TO_FULL_LENGTH`.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustIndexLookup(`select * from t tmp where a = "a";`).Check(testkit.Rows(`a b`))
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows(`a b`))
tk.MustIndexLookup(`select * from t tmp where a = " ";`).Check(testkit.Rows(` `))
tk.MustIndexLookup(`select * from t tmp where a = " ";`).Check(testkit.Rows(` `))
tk.MustIndexLookup(`select * from t tmp where a = " ";`).Check(testkit.Rows(` `))
}

func (s *testPointGetSuite) TestPointGetVarcharPK(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test;`)
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t(a varchar(2) primary key, b varchar(2));`)
tk.MustExec(`insert into t values("aa", "bb");`)

// Test truncate without sql mode `PAD_CHAR_TO_FULL_LENGTH`.
// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustExec(`set @@sql_mode="";`)
tk.MustPointGet(`select * from t where a = "aa";`).Check(testkit.Rows(`aa bb`))
tk.MustPointGet(`select * from t where a = "aab";`).Check(testkit.Rows())

// Test truncate with sql mode `PAD_CHAR_TO_FULL_LENGTH`.
// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustPointGet(`select * from t where a = "aa";`).Check(testkit.Rows(`aa bb`))
tk.MustPointGet(`select * from t where a = "aab";`).Check(testkit.Rows())

tk.MustExec(`truncate table t;`)
tk.MustExec(`insert into t values("a ", "b ");`)

// Test trailing spaces without sql mode `PAD_CHAR_TO_FULL_LENGTH`.
// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustExec(`set @@sql_mode="";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())

// Test trailing spaces with sql mode `PAD_CHAR_TO_FULL_LENGTH`.
// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())

// // Test VARCHAR BINARY.
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t(a varchar(2) binary primary key, b varchar(2));`)
tk.MustExec(`insert into t values(" ", " ");`)
tk.MustExec(`insert into t values("a ", "b ");`)

// Test trailing spaces without sql mode `PAD_CHAR_TO_FULL_LENGTH`.
// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustExec(`set @@sql_mode="";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))

// Test trailing spaces with sql mode `PAD_CHAR_TO_FULL_LENGTH`.
// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
tk.MustPointGet(`select * from t where a = " ";`).Check(testkit.Rows(` `))
}

func (s *testPointGetSuite) TestPointGetBinaryPK(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test;`)
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t(a binary(2) primary key, b binary(2));`)
tk.MustExec(`insert into t values("a", "b");`)

tk.MustExec(`set @@sql_mode="";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a\0";`).Check(testkit.Rows("a\x00 b\x00"))

// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a\0";`).Check(testkit.Rows("a\x00 b\x00"))

tk.MustExec(`insert into t values("a ", "b ");`)
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())

// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustPointGet(`select * from t where a = "a";`).Check(testkit.Rows())
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustPointGet(`select * from t where a = "a ";`).Check(testkit.Rows())
}

func (s *testPointGetSuite) TestIndexLookupBinaryPK(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test;`)
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t(a binary(2) primary key, b binary(2));`)
tk.MustExec(`insert into t values("a", "b");`)

tk.MustExec(`set @@sql_mode="";`)
tk.MustIndexLookup(`select * from t tmp where a = "a";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a\0";`).Check(testkit.Rows("a\x00 b\x00"))

// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustExec(`set @@sql_mode="PAD_CHAR_TO_FULL_LENGTH";`)
tk.MustIndexLookup(`select * from t tmp where a = "a";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a\0";`).Check(testkit.Rows("a\x00 b\x00"))

tk.MustExec(`insert into t values("a ", "b ");`)
tk.MustIndexLookup(`select * from t tmp where a = "a";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows())

// `PAD_CHAR_TO_FULL_LENGTH` should not affect the result.
tk.MustIndexLookup(`select * from t tmp where a = "a";`).Check(testkit.Rows())
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows(`a b `))
tk.MustIndexLookup(`select * from t tmp where a = "a ";`).Check(testkit.Rows())
}
Loading

0 comments on commit 524d6c6

Please sign in to comment.