diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index 466cd29b94bc2..5c73e0e070793 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -382,7 +382,7 @@ func temporalWithDateAsNumEvalType(argTp *types.FieldType) (argEvalType types.Ev return } -// GetCmpTp4MinMax gets compare type for GREATEST and LEAST and BETWEEN (mainly for datetime). +// GetCmpTp4MinMax gets compare type for GREATEST and LEAST and BETWEEN func GetCmpTp4MinMax(args []Expression) (argTp types.EvalType) { datetimeFound, isAllStr := false, true cmpEvalType, isStr, isTemporalWithDate := temporalWithDateAsNumEvalType(args[0].GetType()) diff --git a/expression/integration_test.go b/expression/integration_test.go index 49c43affbc742..4530367f1dba8 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -7560,6 +7560,21 @@ func (s *testIntegrationSerialSuite) TestIssue17063(c *C) { tk.MustQuery(`select coercibility(lag(b, 1, 'B') over w) from t window w as (order by b);`).Check(testkit.Rows("2", "2")) } +func (s *testIntegrationSerialSuite) TestIssue11177(c *C) { + collate.SetNewCollationEnabledForTest(true) + defer collate.SetNewCollationEnabledForTest(false) + + tk := testkit.NewTestKit(c, s.store) + tk.MustQuery("SELECT 'lvuleck' BETWEEN '2008-09-16 22:23:50' AND 0;").Check(testkit.Rows("0")) + tk.MustQuery("show warnings;").Check(testkit.Rows("Warning 1292 Truncated incorrect FLOAT value: 'lvuleck'", "Warning 1292 Truncated incorrect FLOAT value: '2008-09-16 22:23:50'")) + tk.MustQuery("SELECT 'aa' BETWEEN 'bb' AND 0;").Check(testkit.Rows("1")) + tk.MustQuery("show warnings;").Check(testkit.Rows("Warning 1292 Truncated incorrect FLOAT value: 'aa'", "Warning 1292 Truncated incorrect FLOAT value: 'bb'")) + tk.MustQuery("select 1 between 0 and b'110';").Check(testkit.Rows("1")) + tk.MustQuery("show warnings;").Check(testkit.Rows()) + tk.MustQuery("select 'b' between 'a' and b'110';").Check(testkit.Rows("0")) + tk.MustQuery("show warnings;").Check(testkit.Rows()) +} + func (s *testIntegrationSuite) TestIssue19504(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index 4eace01a99479..d61eb5344e985 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -1522,6 +1522,40 @@ func (er *expressionRewriter) rowToScalarFunc(v *ast.RowExpr) { er.ctxStackAppend(function, types.EmptyName) } +func (er *expressionRewriter) wrapExpWithCast() (expr, lexp, rexp expression.Expression) { + stkLen := len(er.ctxStack) + expr, lexp, rexp = er.ctxStack[stkLen-3], er.ctxStack[stkLen-2], er.ctxStack[stkLen-1] + var castFunc func(sessionctx.Context, expression.Expression) expression.Expression + switch expression.GetCmpTp4MinMax([]expression.Expression{expr, lexp, rexp}) { + case types.ETInt: + castFunc = expression.WrapWithCastAsInt + case types.ETReal: + castFunc = expression.WrapWithCastAsReal + case types.ETDecimal: + castFunc = expression.WrapWithCastAsDecimal + case types.ETString: + castFunc = func(ctx sessionctx.Context, e expression.Expression) expression.Expression { + // string kind expression do not need cast + if e.GetType().EvalType().IsStringKind() { + return e + } + return expression.WrapWithCastAsString(ctx, e) + } + case types.ETDatetime: + expr = expression.WrapWithCastAsTime(er.sctx, expr, types.NewFieldType(mysql.TypeDatetime)) + lexp = expression.WrapWithCastAsTime(er.sctx, lexp, types.NewFieldType(mysql.TypeDatetime)) + rexp = expression.WrapWithCastAsTime(er.sctx, rexp, types.NewFieldType(mysql.TypeDatetime)) + return + default: + return + } + + expr = castFunc(er.sctx, expr) + lexp = castFunc(er.sctx, lexp) + rexp = castFunc(er.sctx, rexp) + return +} + func (er *expressionRewriter) betweenToExpression(v *ast.BetweenExpr) { stkLen := len(er.ctxStack) er.err = expression.CheckArgsNotMultiColumnRow(er.ctxStack[stkLen-3:]...) @@ -1529,13 +1563,7 @@ func (er *expressionRewriter) betweenToExpression(v *ast.BetweenExpr) { return } - expr, lexp, rexp := er.ctxStack[stkLen-3], er.ctxStack[stkLen-2], er.ctxStack[stkLen-1] - - if expression.GetCmpTp4MinMax([]expression.Expression{expr, lexp, rexp}) == types.ETDatetime { - expr = expression.WrapWithCastAsTime(er.sctx, expr, types.NewFieldType(mysql.TypeDatetime)) - lexp = expression.WrapWithCastAsTime(er.sctx, lexp, types.NewFieldType(mysql.TypeDatetime)) - rexp = expression.WrapWithCastAsTime(er.sctx, rexp, types.NewFieldType(mysql.TypeDatetime)) - } + expr, lexp, rexp := er.wrapExpWithCast() var op string var l, r expression.Expression