From a0b97b0c962de646f05f42f67ca7d53d630eb9ad Mon Sep 17 00:00:00 2001 From: Yuanjia Zhang Date: Tue, 29 Jun 2021 16:07:25 +0800 Subject: [PATCH] planner: handle other-conditions from subqueries correctly when constructing IndexJoin (#25817) --- planner/core/exhaust_physical_plans.go | 5 +++++ planner/core/integration_test.go | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/planner/core/exhaust_physical_plans.go b/planner/core/exhaust_physical_plans.go index ebc998b037b5c..b4d3198fba7b1 100644 --- a/planner/core/exhaust_physical_plans.go +++ b/planner/core/exhaust_physical_plans.go @@ -469,6 +469,11 @@ func (p *LogicalJoin) constructIndexJoin( lhs, ok1 := c.GetArgs()[0].(*expression.Column) rhs, ok2 := c.GetArgs()[1].(*expression.Column) if ok1 && ok2 { + if lhs.InOperand || rhs.InOperand { + // if this other-cond is from a `[not] in` sub-query, do not convert it into eq-cond since + // IndexJoin cannot deal with NULL correctly in this case; please see #25799 for more details. + continue + } outerSchema, innerSchema := p.Children()[outerIdx].Schema(), p.Children()[1-outerIdx].Schema() if outerSchema.Contains(lhs) && innerSchema.Contains(rhs) { outerHashKeys = append(outerHashKeys, lhs) diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index 280de2107fe9d..7a882a85ba8f9 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -3772,6 +3772,18 @@ func (s *testIntegrationSuite) TestIssue24281(c *C) { "UNION select 1 as v1, 2 as v2") } +func (s *testIntegrationSuite) TestIssue25799(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2") + tk.MustExec(`create table t1 (a float default null, b smallint(6) DEFAULT NULL)`) + tk.MustExec(`insert into t1 values (1, 1)`) + tk.MustExec(`create table t2 (a float default null, b tinyint(4) DEFAULT NULL, key b (b))`) + tk.MustExec(`insert into t2 values (null, 1)`) + tk.HasPlan(`select /*+ TIDB_INLJ(t2@sel_2) */ t1.a, t1.b from t1 where t1.a not in (select t2.a from t2 where t1.b=t2.b)`, `IndexJoin`) + tk.MustQuery(`select /*+ TIDB_INLJ(t2@sel_2) */ t1.a, t1.b from t1 where t1.a not in (select t2.a from t2 where t1.b=t2.b)`).Check(testkit.Rows()) +} + func (s *testIntegrationSuite) TestLimitWindowColPrune(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test")