From c3e2963259076649b0ba0f8667efa34988d61c2f Mon Sep 17 00:00:00 2001 From: winkyao Date: Fri, 27 Jul 2018 15:04:21 +0800 Subject: [PATCH] fix a bug that nullable unique index can not find null values using index. (#7163) --- distsql/request_builder.go | 14 ++++++++++++++ executor/distsql_test.go | 25 +++++++++++++++++++++++++ util/ranger/types.go | 4 ++++ 3 files changed, 43 insertions(+) diff --git a/distsql/request_builder.go b/distsql/request_builder.go index 12ea99db6f215..d93233f04bb86 100644 --- a/distsql/request_builder.go +++ b/distsql/request_builder.go @@ -306,8 +306,22 @@ func encodeIndexKey(sc *stmtctx.StatementContext, ran *ranger.NewRange) ([]byte, if err != nil { return nil, nil, errors.Trace(err) } + if !ran.HighExclude { high = []byte(kv.Key(high).PrefixNext()) } + + var hasNull bool + for _, highVal := range ran.HighVal { + if highVal.IsNull() { + hasNull = true + break + } + } + + if hasNull { + // Append 0 to make unique-key range [null, null] to be a scan rather than point-get. + high = []byte(kv.Key(high).Next()) + } return low, high, nil } diff --git a/executor/distsql_test.go b/executor/distsql_test.go index 3dc980dff8c93..6560401ff6ff1 100644 --- a/executor/distsql_test.go +++ b/executor/distsql_test.go @@ -167,3 +167,28 @@ func (s *testSuite) TestBigIntPK(c *C) { tk.MustExec("insert into t values(1, 1, 1), (9223372036854775807, 2, 2)") tk.MustQuery("select * from t use index(idx) order by a").Check(testkit.Rows("1 1 1", "9223372036854775807 2 2")) } + +func (s *testSuite) TestUniqueKeyNullValueSelect(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + // test null in unique-key + tk.MustExec("create table t (id int default null, c varchar(20), unique id (id));") + tk.MustExec("insert t (c) values ('a'), ('b'), ('c');") + res := tk.MustQuery("select * from t where id is null;") + res.Check(testkit.Rows(" a", " b", " c")) + + // test null in mul unique-key + tk.MustExec("drop table t") + tk.MustExec("create table t (id int default null, b int default 1, c varchar(20), unique id_c(id, b));") + tk.MustExec("insert t (c) values ('a'), ('b'), ('c');") + res = tk.MustQuery("select * from t where id is null and b = 1;") + res.Check(testkit.Rows(" 1 a", " 1 b", " 1 c")) + + tk.MustExec("drop table t") + // test null in non-unique-key + tk.MustExec("create table t (id int default null, c varchar(20), key id (id));") + tk.MustExec("insert t (c) values ('a'), ('b'), ('c');") + res = tk.MustQuery("select * from t where id is null;") + res.Check(testkit.Rows(" a", " b", " c")) +} diff --git a/util/ranger/types.go b/util/ranger/types.go index 1db1d8ffdedae..de27ba2d3eabc 100644 --- a/util/ranger/types.go +++ b/util/ranger/types.go @@ -94,6 +94,10 @@ func (ran *NewRange) IsPoint(sc *stmtctx.StatementContext) bool { if cmp != 0 { return false } + + if a.IsNull() { + return false + } } return !ran.LowExclude && !ran.HighExclude }