Skip to content

Commit b5827c5

Browse files
ari-eti-chi-bot
authored andcommitted
This is an automated cherry-pick of pingcap#54253
Signed-off-by: ti-chi-bot <[email protected]>
1 parent 5160957 commit b5827c5

File tree

6 files changed

+64
-18
lines changed

6 files changed

+64
-18
lines changed

pkg/planner/core/casetest/index/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ go_test(
99
],
1010
data = glob(["testdata/**"]),
1111
flaky = True,
12+
<<<<<<< HEAD
1213
shard_count = 14,
14+
=======
15+
shard_count = 6,
16+
>>>>>>> 41ed0e508d9 (planner: use ordered index with is null predicate (#54253))
1317
deps = [
1418
"//pkg/sessionctx/variable",
1519
"//pkg/testkit",

pkg/planner/core/casetest/index/index_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ func TestIndexMergeIssue50382(t *testing.T) {
451451
}
452452
}
453453

454+
<<<<<<< HEAD
454455
func TestIndexMergeSingleCaseCouldFeelIndexMergeHint(t *testing.T) {
455456
store := testkit.CreateMockStore(t)
456457
tk := testkit.NewTestKit(t, store)
@@ -472,4 +473,16 @@ func TestIndexMergeSingleCaseCouldFeelIndexMergeHint(t *testing.T) {
472473
" └─Limit(Probe) 1.00 cop[tikv] offset:0, count:1",
473474
" └─Selection 1.00 cop[tikv] json_memberof(cast(\"OC8p1763XTkt.org/s/link\", json BINARY), test.t.nslc)",
474475
" └─TableRowIDScan 1.00 cop[tikv] table:t keep order:false, stats:pseudo"))
476+
=======
477+
func TestOrderedIndexWithIsNull(t *testing.T) {
478+
store := testkit.CreateMockStore(t)
479+
tk := testkit.NewTestKit(t, store)
480+
tk.MustExec("use test")
481+
tk.MustExec("CREATE TABLE t1 (a int key, b int, c int, index (b, c));")
482+
tk.MustQuery("explain select a from t1 where b is null order by c").Check(testkit.Rows(
483+
"Projection_6 10.00 root test.t1.a",
484+
"└─IndexReader_12 10.00 root index:IndexRangeScan_11",
485+
" └─IndexRangeScan_11 10.00 cop[tikv] table:t1, index:b(b, c) range:[NULL,NULL], keep order:true, stats:pseudo",
486+
))
487+
>>>>>>> 41ed0e508d9 (planner: use ordered index with is null predicate (#54253))
475488
}

pkg/util/ranger/detacher.go

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,16 @@ func getPotentialEqOrInColOffset(sctx sessionctx.Context, expr expression.Expres
183183
return i
184184
}
185185
}
186+
case ast.IsNull:
187+
c, ok := f.GetArgs()[0].(*expression.Column)
188+
if !ok {
189+
return -1
190+
}
191+
for i, col := range cols {
192+
if col.EqualColumn(c) {
193+
return i
194+
}
195+
}
186196
}
187197
return -1
188198
}
@@ -575,27 +585,34 @@ func allEqOrIn(expr expression.Expression) bool {
575585
}
576586
}
577587
return true
578-
case ast.EQ, ast.NullEQ, ast.In:
588+
case ast.EQ, ast.NullEQ, ast.In, ast.IsNull:
579589
return true
580590
}
581591
return false
582592
}
583593

584594
func extractValueInfo(expr expression.Expression) *valueInfo {
585-
if f, ok := expr.(*expression.ScalarFunction); ok && (f.FuncName.L == ast.EQ || f.FuncName.L == ast.NullEQ) {
586-
getValueInfo := func(c *expression.Constant) *valueInfo {
587-
mutable := c.ParamMarker != nil || c.DeferredExpr != nil
588-
var value *types.Datum
589-
if !mutable {
590-
value = &c.Value
595+
if f, ok := expr.(*expression.ScalarFunction); ok {
596+
if f.FuncName.L == ast.IsNull {
597+
val := &types.Datum{}
598+
val.SetNull()
599+
return &valueInfo{value: val, mutable: false}
600+
}
601+
if f.FuncName.L == ast.EQ || f.FuncName.L == ast.NullEQ {
602+
getValueInfo := func(c *expression.Constant) *valueInfo {
603+
mutable := c.ParamMarker != nil || c.DeferredExpr != nil
604+
var value *types.Datum
605+
if !mutable {
606+
value = &c.Value
607+
}
608+
return &valueInfo{value, mutable}
609+
}
610+
if c, ok := f.GetArgs()[0].(*expression.Constant); ok {
611+
return getValueInfo(c)
612+
}
613+
if c, ok := f.GetArgs()[1].(*expression.Constant); ok {
614+
return getValueInfo(c)
591615
}
592-
return &valueInfo{value, mutable}
593-
}
594-
if c, ok := f.GetArgs()[0].(*expression.Constant); ok {
595-
return getValueInfo(c)
596-
}
597-
if c, ok := f.GetArgs()[1].(*expression.Constant); ok {
598-
return getValueInfo(c)
599616
}
600617
}
601618
return nil
@@ -654,8 +671,12 @@ func ExtractEqAndInCondition(sctx sessionctx.Context, conditions []expression.Ex
654671
if ma == nil {
655672
if accesses[i] != nil {
656673
if allEqOrIn(accesses[i]) {
657-
newConditions = append(newConditions, accesses[i])
658674
columnValues[i] = extractValueInfo(accesses[i])
675+
if columnValues[i] != nil && columnValues[i].value != nil && columnValues[i].value.IsNull() {
676+
accesses[i] = nil
677+
} else {
678+
newConditions = append(newConditions, accesses[i])
679+
}
659680
} else {
660681
accesses[i] = nil
661682
}

tests/integrationtest/r/planner/core/casetest/integration.result

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,13 @@ explain format = 'brief' select * from t3 where a >= 'a' and a <= 'a' and b = 'b
607607
id estRows task access object operator info
608608
IndexReader 0.33 root index:IndexRangeScan
609609
└─IndexRangeScan 0.33 cop[tikv] table:t3, index:a(a, b, c) range:("a" "b" "c","a" "b" +inf], keep order:false, stats:pseudo
610+
explain format = 'brief' select * from t1 where a is null or a in (1, 2, 3);
611+
id estRows task access object operator info
612+
IndexReader 260.00 root index:IndexRangeScan
613+
└─IndexRangeScan 260.00 cop[tikv] table:t1, index:a(a, b, c) range:[NULL,NULL], [1,3], keep order:false, stats:pseudo
614+
explain format = 'brief' select * from t1 where a is null and a = 1;
615+
id estRows task access object operator info
616+
TableDual 0.00 root rows:0
610617
drop table if exists t1;
611618
CREATE TABLE t1 (
612619
key1 int(11) NOT NULL,

tests/integrationtest/r/util/ranger.result

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,9 +483,8 @@ a b c
483483
1 2 2
484484
explain format='brief' select * from t where a = 1 and (b is null or b = 2) and c > 1;
485485
id estRows task access object operator info
486-
IndexReader 0.07 root index:Selection
487-
└─Selection 0.07 cop[tikv] gt(util__ranger.t.c, 1)
488-
└─IndexRangeScan 0.20 cop[tikv] table:t, index:a(a, b, c) range:[1 NULL,1 NULL], [1 2,1 2], keep order:false, stats:pseudo
486+
IndexReader 0.67 root index:IndexRangeScan
487+
└─IndexRangeScan 0.67 cop[tikv] table:t, index:a(a, b, c) range:(1 NULL 1,1 NULL +inf], (1 2 1,1 2 +inf], keep order:false, stats:pseudo
489488
select * from t where a = 1 and (b is null or b = 2) and c > 1;
490489
a b c
491490
1 2 2

tests/integrationtest/t/planner/core/casetest/integration.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ explain format = 'brief' select * from t0 where a > 1 and a < 3 order by b limit
173173
explain format = 'brief' select * from t1 where a >= 2 and a <= 2 and b = 2 and c > 2;
174174
explain format = 'brief' select * from t2 where a >= 2.5 and a <= 2.5 order by b limit 2;
175175
explain format = 'brief' select * from t3 where a >= 'a' and a <= 'a' and b = 'b' and c > 'c';
176+
explain format = 'brief' select * from t1 where a is null or a in (1, 2, 3);
177+
explain format = 'brief' select * from t1 where a is null and a = 1;
176178

177179
# TestIssue22105
178180
drop table if exists t1;

0 commit comments

Comments
 (0)