Repository: pingcap/tidb (Go)

Issue:
NATURAL LEFT JOIN with a NOT predicate results in a server panic
Consider the following statements:
```sql
CREATE TABLE t0(c0 INT);
CREATE TABLE t1(c0 INT);
SELECT * FROM t1 NATURAL LEFT JOIN t0 WHERE NOT t1.c0;
```
Unexpectedly, the `SELECT` results in a loss of connection:
```
mysql> CREATE TABLE t0(c0 INT);
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t1(c0 INT);
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM  t1 NATURAL LEFT JOIN t0 WHERE NOT t1.c0;
ERROR 2013 (HY000): Lost connection to MySQL server during query
```
The server logs the following:
```

[2020/04/15 12:09:14.241 +02:00] [ERROR] [conn.go:662] ["connection running loop panic"] [conn=1] [lastSQL="SELECT * FROM  t1 NATURAL LEFT JOIN t0 WHERE NOT t1.c0"] [err="ctx should not be nil"] [stack="goroutine 356 [running]:\ngithub.com/pingcap/tidb/server.(*clientConn).Run.func1(0x2d69d40, 0xc021d26930, 0xc001142340)\n\t/tidb/server/conn.go:660 +0xee\npanic(0x2634780, 0x2cfa0e0)\n\t/usr/lib/go-1.13/src/runtime/panic.go:679 +0x1b2\ngithub.com/pingcap/tidb/expression.newBaseBuiltinFuncWithTp(0x0, 0x0, 0xc0010c38e0, 0x1, 0x1, 0x0, 0xc000b7fe17, 0x1, 0x1, 0x0, ...)\n\t/tidb/expression/builtin.go:116 +0xc8d\ngithub.com/pingcap/tidb/expression.(*isTrueOrFalseFunctionClass).getFunction(0xc000b7ff88, 0x0, 0x0, 0xc0010c38e0, 0x1, 0x1, 0x2854860, 0x1, 0xc001034d10, 0xc000b800d0)\n\t/tidb/expression/builtin_op.go:421 +0x15b\ngithub.com/pingcap/tidb/expression.wrapWithIsTrue(0x0, 0x0, 0x1, 0x2dd2020, 0xc00103e780, 0x1, 0x7f25f01aac78, 0x8, 0xf08826, 0xc0010c37f0)\n\t/tidb/expression/expression.go:1125 +0x187\ngithub.com/pingcap/tidb/expression.pushNotAcrossExpr(0x0, 0x0, 0x2dd23e0, 0xc000a6e050, 0x0, 0x8, 0x1, 0x203000)\n\t/tidb/expression/util.go:398 +0x941\ngithub.com/pingcap/tidb/expression.PushDownNot(...)\n\t/tidb/expression/util.go:444\ngithub.com/pingcap/tidb/planner/core.isNullRejected(0x2da3400, 0xc000556d00, 0xc01ed33230, 0x2dd23e0, 0xc000a6e050, 0x203007)\n\t/tidb/planner/core/rule_predicate_push_down.go:336 +0x4c\ngithub.com/pingcap/tidb/planner/core.simplifyOuterJoin(0xc000537b00, 0xc0010c38b0, 0x1, 0x1)\n\t/tidb/planner/core/rule_predicate_push_down.go:319 +0x154\ngithub.com/pingcap/tidb/planner/core.(*LogicalJoin).PredicatePushDown(0xc000537b00, 0xc0010c38b0, 0x1, 0x1, 0x435b0c0, 0x0, 0x0, 0x0, 0x1)\n\t/tidb/planner/core/rule_predicate_push_down.go:114 +0x6a\ngithub.com/pingcap/tidb/planner/core.(*LogicalSelection).PredicatePushDown(0xc02209d290, 0x435b0c0, 0x0, 0x0, 0xf4300c, 0x0, 0x28e60e0, 0xc00103e701, 0x435b0c0)\n\t/tidb/planner/core/rule_predicate_push_down.go:77 +0x166\ngithub.com/pingcap/tidb/planner/core.(*baseLogicalPlan).PredicatePushDown(0xc001034c80, 0x435b0c0, 0x0, 0x0, 0xc0010c37f0, 0x1, 0x1, 0x1, 0x2da2300)\n\t/tidb/planner/core/rule_predicate_push_down.go:56 +0xa6\ngithub.com/pingcap/tidb/planner/core.(*LogicalProjection).PredicatePushDown(0xc001034c60, 0x0, 0x0, 0x0, 0x435c5a0, 0xc01ed33500, 0xc00126d470, 0x27b5040, 0xc00126d470)\n\t/tidb/planner/core/rule_predicate_push_down.go:371 +0x278\ngithub.com/pingcap/tidb/planner/core.(*ppdSolver).optimize(0x435ab60, 0x2d69d40, 0xc021d26930, 0x2da2200, 0xc001034c60, 0x2da2200, 0xc001034c60, 0x0, 0x0)\n\t/tidb/planner/core/rule_predicate_push_down.go:29 +0x42\ngithub.com/pingcap/tidb/planner/core.logicalOptimize(0x2d69d40, 0xc021d26930, 0x21a2, 0x2da2200, 0xc001034c60, 0xf069aa, 0x28adac0, 0x2984de0, 0x2d25001)\n\t/tidb/planner/core/optimizer.go:155 +0x116\ngithub.com/pingcap/tidb/planner/core.DoOptimize(0x2d69d40, 0xc021d26930, 0x2da3400, 0xc000556d00, 0x21a2, 0x2da2200, 0xc001034c60, 0x0, 0x0, 0x0, ...)\n\t/tidb/planner/core/optimizer.go:124 +0x60\ngithub.com/pingcap/tidb/planner.optimize(0x2d69d40, 0xc021d26930, 0x2da3400, 0xc000556d00, 0x2d6b8c0, 0xc00056c9c0, 0x2d98740, 0xc01ed32900, 0x0, 0x0, ...)\n\t/tidb/planner/optimize.go:189 +0x5a9\ngithub.com/pingcap/tidb/planner.Optimize(0x2d69d40, 0xc021d26930, 0x2da3400, 0xc000556d00, 0x2d6b8c0, 0xc00056c9c0, 0x2d98740, 0xc01ed32900, 0x0, 0x0, ...)\n\t/tidb/planner/optimize.go:63 +0x28f\ngithub.com/pingcap/tidb/executor.(*Compiler).Compile(0xc000b80f30, 0x2d69d40, 0xc021d26930, 0x2d71100, 0xc00056c9c0, 0x0, 0x0, 0x0)\n\t/tidb/executor/compiler.go:61 +0x253\ngithub.com/pingcap/tidb/session.(*session).ExecuteStmt(0xc000556d00, 0x2d69d40, 0xc021d26930, 0x2d71100, 0xc00056c9c0, 0x0, 0x0, 0x0, 0x0)\n\t/tidb/ses"]
```
I found this based on the latest master commit (8f000fc353f858de3148a7857b398380118088c3):
```
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tidb_version()                                                                                                                                                                                                                                                                                          |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Release Version: v4.0.0-beta.2-254-g8f000fc35
Git Commit Hash: 8f000fc353f858de3148a7857b398380118088c3
Git Branch: master
UTC Build Time: 2020-04-15 10:08:36
GoVersion: go1.13.4
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```
The 4.0 RC seems not be affected by this.


Discussion:
fixed in #16430 



Patch:
diff --git a/planner/core/rule_predicate_push_down.go b/planner/core/rule_predicate_push_down.go
index b5d0291ee01fc..d9cd28df5a9bf 100644
--- a/planner/core/rule_predicate_push_down.go
+++ b/planner/core/rule_predicate_push_down.go
@@ -333,7 +333,7 @@ func simplifyOuterJoin(p *LogicalJoin, predicates []expression.Expression) {
 // If it is a conjunction containing a null-rejected condition as a conjunct.
 // If it is a disjunction of null-rejected conditions.
 func isNullRejected(ctx sessionctx.Context, schema *expression.Schema, expr expression.Expression) bool {
-	expr = expression.PushDownNot(nil, expr)
+	expr = expression.PushDownNot(ctx, expr)
 	sc := ctx.GetSessionVars().StmtCtx
 	sc.InNullRejectCheck = true
 	result := expression.EvaluateExprWithNull(ctx, schema, expr)


Test patch:
diff --git a/expression/integration_test.go b/expression/integration_test.go
index f9e758e025104..c5c2b6629bc04 100755
--- a/expression/integration_test.go
+++ b/expression/integration_test.go
@@ -6058,6 +6058,17 @@ func (s *testIntegrationSuite) TestIssue15992(c *C) {
 	tk.MustExec("drop table t0;")
 }
 
+func (s *testIntegrationSuite) TestIssue16419(c *C) {
+	tk := testkit.NewTestKitWithInit(c, s.store)
+	tk.MustExec("use test;")
+	tk.MustExec("drop table if exists t0")
+	tk.MustExec("drop table if exists t1")
+	tk.MustExec("CREATE TABLE t0(c0 INT);")
+	tk.MustExec("CREATE TABLE t1(c0 INT);")
+	tk.MustQuery("SELECT * FROM t1 NATURAL LEFT JOIN t0 WHERE NOT t1.c0;").Check(testkit.Rows())
+	tk.MustExec("drop table t0, t1;")
+}
+
 func (s *testIntegrationSuite) TestIssue16029(c *C) {
 	tk := testkit.NewTestKit(c, s.store)
 	tk.MustExec("use test;")