diff --git a/executor/join_test.go b/executor/join_test.go index 2aa0ae2f6ec34..ca51a648a6b22 100644 --- a/executor/join_test.go +++ b/executor/join_test.go @@ -1878,6 +1878,15 @@ func (s *testSuiteJoin2) TestNullEmptyAwareSemiJoin(c *C) { result.Check(results[i].result) } } + + tk.MustExec("drop table if exists t1, t2") + tk.MustExec("create table t1(a int)") + tk.MustExec("create table t2(a int)") + tk.MustExec("insert into t1 values(1),(2)") + tk.MustExec("insert into t2 values(1),(null)") + tk.MustQuery("select * from t1 where a not in (select a from t2 where t1.a = t2.a)").Check(testkit.Rows( + "2", + )) } func (s *testSuiteJoin1) TestScalarFuncNullSemiJoin(c *C) { diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index 344eda3fa353d..c09a2a2856d8b 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -787,12 +787,12 @@ func (er *expressionRewriter) handleInSubquery(ctx context.Context, v *ast.Patte // For AntiSemiJoin/LeftOuterSemiJoin/AntiLeftOuterSemiJoin, we cannot treat `in` expression as // normal column equal condition, so we specially mark the inner operand here. if v.Not || asScalar { - rCol.InOperand = true // If both input columns of `in` expression are not null, we can treat the expression // as normal column equal condition instead. - lCol, ok := lexpr.(*expression.Column) - if ok && mysql.HasNotNullFlag(lCol.GetType().Flag) && mysql.HasNotNullFlag(rCol.GetType().Flag) { - rCol.InOperand = false + if !mysql.HasNotNullFlag(lexpr.GetType().Flag) || !mysql.HasNotNullFlag(rCol.GetType().Flag) { + rColCopy := *rCol + rColCopy.InOperand = true + rexpr = &rColCopy } } } else {