From efa487eddc1fd3dafca86a310200fe5d317332c0 Mon Sep 17 00:00:00 2001 From: ti-srebot <66930949+ti-srebot@users.noreply.github.com> Date: Thu, 14 Jan 2021 15:50:35 +0800 Subject: [PATCH] expression: fix unexpected panic when doing isNullRejected check (#22173) (#22327) --- expression/constant_fold.go | 14 ++++++++------ expression/constant_test.go | 27 --------------------------- expression/integration_test.go | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/expression/constant_fold.go b/expression/constant_fold.go index c5810c8570387..6f84eefeaefb9 100644 --- a/expression/constant_fold.go +++ b/expression/constant_fold.go @@ -191,15 +191,17 @@ func foldConstant(expr Expression) (Expression, bool) { return expr, isDeferredConst } if value.IsNull() { - if isDeferredConst { - return &Constant{Value: value, RetType: x.RetType, DeferredExpr: x}, true - } + // This Constant is created to compose the result expression of EvaluateExprWithNull when InNullRejectCheck + // is true. We just check whether the result expression is null or false and then let it die. Basically, + // the constant is used once briefly and will not be retained for a long time. Hence setting DeferredExpr + // of Constant to nil is ok. return &Constant{Value: value, RetType: x.RetType}, false } if isTrue, err := value.ToBool(sc); err == nil && isTrue == 0 { - if isDeferredConst { - return &Constant{Value: value, RetType: x.RetType, DeferredExpr: x}, true - } + // This Constant is created to compose the result expression of EvaluateExprWithNull when InNullRejectCheck + // is true. We just check whether the result expression is null or false and then let it die. Basically, + // the constant is used once briefly and will not be retained for a long time. Hence setting DeferredExpr + // of Constant to nil is ok. return &Constant{Value: value, RetType: x.RetType}, false } return expr, isDeferredConst diff --git a/expression/constant_test.go b/expression/constant_test.go index 64ae35e70c308..50ea87d010f7b 100644 --- a/expression/constant_test.go +++ b/expression/constant_test.go @@ -234,33 +234,6 @@ func (*testExpressionSuite) TestConstantFolding(c *C) { } } -func (*testExpressionSuite) TestDeferredExprNullConstantFold(c *C) { - nullConst := &Constant{ - Value: types.NewDatum(nil), - RetType: types.NewFieldType(mysql.TypeTiny), - DeferredExpr: NewNull(), - } - tests := []struct { - condition Expression - deferred string - }{ - { - condition: newFunction(ast.LT, newColumn(0), nullConst), - deferred: "lt(Column#0, )", - }, - } - for _, tt := range tests { - comment := Commentf("different for expr %s", tt.condition) - sf, ok := tt.condition.(*ScalarFunction) - c.Assert(ok, IsTrue, comment) - sf.GetCtx().GetSessionVars().StmtCtx.InNullRejectCheck = true - newConds := FoldConstant(tt.condition) - newConst, ok := newConds.(*Constant) - c.Assert(ok, IsTrue, comment) - c.Assert(newConst.DeferredExpr.String(), Equals, tt.deferred, comment) - } -} - func (*testExpressionSuite) TestDeferredParamNotNull(c *C) { ctx := mock.NewContext() testTime := time.Now() diff --git a/expression/integration_test.go b/expression/integration_test.go index de33b1c0d9593..fac2606eb690e 100755 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -7336,3 +7336,28 @@ func (s *testIntegrationSuite) TestDatetimeUserVariable(c *C) { tk.MustExec("set @@tidb_enable_vectorized_expression = true") c.Check(tk.MustQuery("select @p").Rows()[0][0] != "", IsTrue) } + +func (s *testIntegrationSuite) TestIssue22098(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("CREATE TABLE `ta` (" + + " `k` varchar(32) NOT NULL DEFAULT ' '," + + " `c0` varchar(32) NOT NULL DEFAULT ' '," + + " `c` varchar(18) NOT NULL DEFAULT ' '," + + " `e0` varchar(1) NOT NULL DEFAULT ' '," + + " PRIMARY KEY (`k`,`c0`,`c`)," + + " KEY `idx` (`c`,`e0`)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin") + tk.MustExec("CREATE TABLE `tb` (" + + " `k` varchar(32) NOT NULL DEFAULT ' '," + + " `e` int(11) NOT NULL DEFAULT '0'," + + " `i` int(11) NOT NULL DEFAULT '0'," + + " `s` varchar(1) NOT NULL DEFAULT ' '," + + " `c` varchar(50) NOT NULL DEFAULT ' '," + + " PRIMARY KEY (`k`)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin") + tk.MustExec("prepare stmt from \"select a.* from ta a left join tb b on a.k = b.k where (a.k <> '000000' and ((b.s = ? and i = ? ) or (b.s = ? and e = ?) or (b.s not in(?, ?))) and b.c like '%1%') or (a.c <> '000000' and a.k = '000000')\"") + tk.MustExec("set @a=3;set @b=20200414;set @c='a';set @d=20200414;set @e=3;set @f='a';") + tk.MustQuery("execute stmt using @a,@b,@c,@d,@e,@f").Check(testkit.Rows()) +}