diff --git a/expression/constant_fold.go b/expression/constant_fold.go index 76d1255dceaf5..c8997b1906539 100644 --- a/expression/constant_fold.go +++ b/expression/constant_fold.go @@ -117,7 +117,10 @@ func foldConstant(expr Expression) (Expression, bool) { constArgs[i] = One } } - dummyScalarFunc := NewFunctionInternal(x.GetCtx(), x.FuncName.L, x.GetType(), constArgs...) + dummyScalarFunc, err := NewFunctionBase(x.GetCtx(), x.FuncName.L, x.GetType(), constArgs...) + if err != nil { + return expr, isDeferredConst + } value, err := dummyScalarFunc.Eval(chunk.Row{}) if err != nil { return expr, isDeferredConst diff --git a/expression/integration_test.go b/expression/integration_test.go index 4d30385860b6d..c3503a2b836a7 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -3875,3 +3875,25 @@ func (s *testIntegrationSuite) TestIssue9325(c *C) { result = tk.MustQuery("select * from t where a < timestamp'2019-02-16 14:21:00'") result.Check(testkit.Rows("2019-02-16 14:19:59", "2019-02-16 14:20:01")) } + +func (s *testIntegrationSuite) TestIssue10156(c *C) { + tk := testkit.NewTestKit(c, s.store) + defer s.cleanEnv(c) + + tk.MustExec("use test") + tk.MustExec("CREATE TABLE `t1` (`period_name` varchar(24) DEFAULT NULL ,`period_id` bigint(20) DEFAULT NULL ,`starttime` bigint(20) DEFAULT NULL)") + tk.MustExec("CREATE TABLE `t2` (`bussid` bigint(20) DEFAULT NULL,`ct` bigint(20) DEFAULT NULL)") + q := ` +select + a.period_name, + b.date8 +from + (select * from t1) a +left join + (select bussid,date(from_unixtime(ct)) date8 from t2) b +on + a.period_id = b.bussid +where + datediff(b.date8, date(from_unixtime(a.starttime))) >= 0` + tk.MustQuery(q) +} diff --git a/expression/scalar_function.go b/expression/scalar_function.go index e0c1a13b8ea00..bd357b227f12e 100644 --- a/expression/scalar_function.go +++ b/expression/scalar_function.go @@ -72,6 +72,15 @@ func (sf *ScalarFunction) MarshalJSON() ([]byte, error) { // NewFunction creates a new scalar function or constant. func NewFunction(ctx sessionctx.Context, funcName string, retType *types.FieldType, args ...Expression) (Expression, error) { + return newFunctionImpl(ctx, true, funcName, retType, args...) +} + +// NewFunctionBase creates a new scalar function or constant without constant fold +func NewFunctionBase(ctx sessionctx.Context, funcName string, retType *types.FieldType, args ...Expression) (Expression, error) { + return newFunctionImpl(ctx, false, funcName, retType, args...) +} + +func newFunctionImpl(ctx sessionctx.Context, fold bool, funcName string, retType *types.FieldType, args ...Expression) (Expression, error) { if retType == nil { return nil, errors.Errorf("RetType cannot be nil for ScalarFunction.") } @@ -96,7 +105,10 @@ func NewFunction(ctx sessionctx.Context, funcName string, retType *types.FieldTy RetType: retType, Function: f, } - return FoldConstant(sf), nil + if fold { + return FoldConstant(sf), nil + } + return sf, nil } // NewFunctionInternal is similar to NewFunction, but do not returns error, should only be used internally.