From a606ada4ed6392e78103a87c5feeee23cee9f90b Mon Sep 17 00:00:00 2001 From: ruoxi Date: Thu, 17 Dec 2020 14:52:04 +0800 Subject: [PATCH 1/3] cherry pick #21806 to release-4.0 Signed-off-by: ti-srebot --- expression/builtin_cast.go | 45 ++++++++++++++++++++++++--------- expression/builtin_cast_vec.go | 12 +++++++++ expression/expression.go | 46 +++++++++++++++++++++++++++++++++- expression/integration_test.go | 15 +++++++++++ 4 files changed, 105 insertions(+), 13 deletions(-) diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index a7bd79ebaacb9..b2a8886f27525 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -1134,6 +1134,12 @@ func (b *builtinCastStringAsIntSig) evalInt(row chunk.Row) (res int64, isNull bo if b.args[0].GetType().Hybrid() || IsBinaryLiteral(b.args[0]) { return b.args[0].EvalInt(b.ctx, row) } + + // Take the implicit evalInt path if possible. + if CanImplicitEvalInt(b.args[0]) { + return b.args[0].EvalInt(b.ctx, row) + } + val, isNull, err := b.args[0].EvalString(b.ctx, row) if isNull || err != nil { return res, isNull, err @@ -1182,6 +1188,12 @@ func (b *builtinCastStringAsRealSig) evalReal(row chunk.Row) (res float64, isNul if IsBinaryLiteral(b.args[0]) { return b.args[0].EvalReal(b.ctx, row) } + + // Take the implicit evalReal path if possible. + if CanImplicitEvalReal(b.args[0]) { + return b.args[0].EvalReal(b.ctx, row) + } + val, isNull, err := b.args[0].EvalString(b.ctx, row) if isNull || err != nil { return res, isNull, err @@ -1746,18 +1758,31 @@ func (i inCastContext) String() string { // @see BuildCastFunction4Union const inUnionCastContext inCastContext = 0 -// hasSpecialCast checks if this expr has its own special cast function. -// for example(#9713): when doing arithmetic using results of function DayName, -// "Monday" should be regarded as 0, "Tuesday" should be regarded as 1 and so on. -func hasSpecialCast(ctx sessionctx.Context, expr Expression, tp *types.FieldType) bool { +// CanImplicitEvalInt represents the builtin functions that have an implicit path to evaluate as integer, +// regardless of the type that type inference decides it to be. +// This is a nasty way to match the weird behavior of MySQL functions like `dayname()` being implicitly evaluated as integer. +// See https://github.com/mysql/mysql-server/blob/ee4455a33b10f1b1886044322e4893f587b319ed/sql/item_timefunc.h#L423 for details. +func CanImplicitEvalInt(expr Expression) bool { switch f := expr.(type) { case *ScalarFunction: switch f.FuncName.L { case ast.DayName: - switch tp.EvalType() { - case types.ETInt, types.ETReal: - return true - } + return true + } + } + return false +} + +// CanImplicitEvalReal represents the builtin functions that have an implicit path to evaluate as real, +// regardless of the type that type inference decides it to be. +// This is a nasty way to match the weird behavior of MySQL functions like `dayname()` being implicitly evaluated as real. +// See https://github.com/mysql/mysql-server/blob/ee4455a33b10f1b1886044322e4893f587b319ed/sql/item_timefunc.h#L423 for details. +func CanImplicitEvalReal(expr Expression) bool { + switch f := expr.(type) { + case *ScalarFunction: + switch f.FuncName.L { + case ast.DayName: + return true } } return false @@ -1775,10 +1800,6 @@ func BuildCastFunction4Union(ctx sessionctx.Context, expr Expression, tp *types. // BuildCastFunction builds a CAST ScalarFunction from the Expression. func BuildCastFunction(ctx sessionctx.Context, expr Expression, tp *types.FieldType) (res Expression) { - if hasSpecialCast(ctx, expr, tp) { - return expr - } - var fc functionClass switch tp.EvalType() { case types.ETInt: diff --git a/expression/builtin_cast_vec.go b/expression/builtin_cast_vec.go index 40bab4d432af4..6e7e30ef8e72e 100644 --- a/expression/builtin_cast_vec.go +++ b/expression/builtin_cast_vec.go @@ -847,6 +847,12 @@ func (b *builtinCastStringAsIntSig) vecEvalInt(input *chunk.Chunk, result *chunk if b.args[0].GetType().Hybrid() || IsBinaryLiteral(b.args[0]) { return b.args[0].VecEvalInt(b.ctx, input, result) } + + // Take the implicit evalInt path if possible. + if CanImplicitEvalInt(b.args[0]) { + return b.args[0].VecEvalInt(b.ctx, input, result) + } + result.ResizeInt64(n, false) buf, err := b.bufAllocator.get(types.ETString, n) if err != nil { @@ -1552,6 +1558,12 @@ func (b *builtinCastStringAsRealSig) vecEvalReal(input *chunk.Chunk, result *chu if IsBinaryLiteral(b.args[0]) { return b.args[0].VecEvalReal(b.ctx, input, result) } + + // Take the implicit evalReal path if possible. + if CanImplicitEvalReal(b.args[0]) { + return b.args[0].VecEvalReal(b.ctx, input, result) + } + n := input.NumRows() buf, err := b.bufAllocator.get(types.ETString, n) if err != nil { diff --git a/expression/expression.go b/expression/expression.go index f8abe0a7a78c2..23b8aae39873d 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -331,20 +331,36 @@ func VecEvalBool(ctx sessionctx.Context, exprList CNFExprs, input *chunk.Chunk, isZero := allocZeroSlice(n) defer deallocateZeroSlice(isZero) for _, expr := range exprList { +<<<<<<< HEAD eType := expr.GetType().EvalType() if expr.GetType().Hybrid() { eType = types.ETInt +======= + tp := expr.GetType() + eType := tp.EvalType() + if CanImplicitEvalReal(expr) { + eType = types.ETReal +>>>>>>> 556ccccde... expression: add implicit eval int and real for function dayname (#21806) } buf, err := globalColumnAllocator.get(eType, n) if err != nil { return nil, nil, err } - if err := EvalExpr(ctx, expr, eType, input, buf); err != nil { + // Take the implicit evalReal path if possible. + if CanImplicitEvalReal(expr) { + if err := implicitEvalReal(ctx, expr, input, buf); err != nil { + return nil, nil, err + } + } else if err := EvalExpr(ctx, expr, eType, input, buf); err != nil { return nil, nil, err } +<<<<<<< HEAD err = toBool(ctx.GetSessionVars().StmtCtx, eType, buf, sel, isZero) +======= + err = toBool(ctx.GetSessionVars().StmtCtx, tp, eType, buf, sel, isZero) +>>>>>>> 556ccccde... expression: add implicit eval int and real for function dayname (#21806) if err != nil { return nil, nil, err } @@ -384,7 +400,11 @@ func VecEvalBool(ctx sessionctx.Context, exprList CNFExprs, input *chunk.Chunk, return selected, nulls, nil } +<<<<<<< HEAD func toBool(sc *stmtctx.StatementContext, eType types.EvalType, buf *chunk.Column, sel []int, isZero []int8) error { +======= +func toBool(sc *stmtctx.StatementContext, tp *types.FieldType, eType types.EvalType, buf *chunk.Column, sel []int, isZero []int8) error { +>>>>>>> 556ccccde... expression: add implicit eval int and real for function dayname (#21806) switch eType { case types.ETInt: i64s := buf.Int64s() @@ -473,6 +493,30 @@ func toBool(sc *stmtctx.StatementContext, eType types.EvalType, buf *chunk.Colum return nil } +func implicitEvalReal(ctx sessionctx.Context, expr Expression, input *chunk.Chunk, result *chunk.Column) (err error) { + if expr.Vectorized() && ctx.GetSessionVars().EnableVectorizedExpression { + err = expr.VecEvalReal(ctx, input, result) + } else { + ind, n := 0, input.NumRows() + iter := chunk.NewIterator4Chunk(input) + result.ResizeFloat64(n, false) + f64s := result.Float64s() + for it := iter.Begin(); it != iter.End(); it = iter.Next() { + value, isNull, err := expr.EvalReal(ctx, it) + if err != nil { + return err + } + if isNull { + result.SetNull(ind, isNull) + } else { + f64s[ind] = value + } + ind++ + } + } + return +} + // EvalExpr evaluates this expr according to its type. // And it selects the method for evaluating expression based on // the environment variables and whether the expression can be vectorized. diff --git a/expression/integration_test.go b/expression/integration_test.go index d047ae5ae8521..4b0a2b895f98a 100755 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -1907,6 +1907,21 @@ func (s *testIntegrationSuite2) TestTimeBuiltin(c *C) { "Warning|1292|Incorrect datetime value: '0000-00-00 00:00:00.000000'", "Warning|1292|Incorrect datetime value: '0000-01-00 00:00:00.000000'", "Warning|1292|Incorrect datetime value: '0000-01-00 00:00:00.000000'")) + // for dayname implicit cast to boolean and real + result = tk.MustQuery(`select 1 from dual where dayname('2016-03-07')`) + result.Check(testkit.Rows()) + result = tk.MustQuery(`select 1 from dual where dayname('2016-03-07') is true`) + result.Check(testkit.Rows()) + result = tk.MustQuery(`select 1 from dual where dayname('2016-03-07') is false`) + result.Check(testkit.Rows("1")) + result = tk.MustQuery(`select 1 from dual where dayname('2016-03-08')`) + result.Check(testkit.Rows("1")) + result = tk.MustQuery(`select 1 from dual where dayname('2016-03-08') is true`) + result.Check(testkit.Rows("1")) + result = tk.MustQuery(`select 1 from dual where dayname('2016-03-08') is false`) + result.Check(testkit.Rows()) + result = tk.MustQuery(`select cast(dayname("2016-03-07") as double), cast(dayname("2016-03-08") as double)`) + result.Check(testkit.Rows("0 1")) // for sec_to_time result = tk.MustQuery("select sec_to_time(NULL)") From 562808456e7ad4adea8805d78b25a1479efc170b Mon Sep 17 00:00:00 2001 From: Yuanjia Zhang Date: Wed, 27 Jan 2021 14:45:42 +0800 Subject: [PATCH 2/3] fix CI --- expression/expression.go | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/expression/expression.go b/expression/expression.go index 23b8aae39873d..fad2e5ca02d46 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -331,16 +331,13 @@ func VecEvalBool(ctx sessionctx.Context, exprList CNFExprs, input *chunk.Chunk, isZero := allocZeroSlice(n) defer deallocateZeroSlice(isZero) for _, expr := range exprList { -<<<<<<< HEAD - eType := expr.GetType().EvalType() - if expr.GetType().Hybrid() { - eType = types.ETInt -======= tp := expr.GetType() eType := tp.EvalType() + if expr.GetType().Hybrid() { + eType = types.ETInt + } if CanImplicitEvalReal(expr) { eType = types.ETReal ->>>>>>> 556ccccde... expression: add implicit eval int and real for function dayname (#21806) } buf, err := globalColumnAllocator.get(eType, n) if err != nil { @@ -356,11 +353,7 @@ func VecEvalBool(ctx sessionctx.Context, exprList CNFExprs, input *chunk.Chunk, return nil, nil, err } -<<<<<<< HEAD - err = toBool(ctx.GetSessionVars().StmtCtx, eType, buf, sel, isZero) -======= err = toBool(ctx.GetSessionVars().StmtCtx, tp, eType, buf, sel, isZero) ->>>>>>> 556ccccde... expression: add implicit eval int and real for function dayname (#21806) if err != nil { return nil, nil, err } @@ -400,11 +393,7 @@ func VecEvalBool(ctx sessionctx.Context, exprList CNFExprs, input *chunk.Chunk, return selected, nulls, nil } -<<<<<<< HEAD -func toBool(sc *stmtctx.StatementContext, eType types.EvalType, buf *chunk.Column, sel []int, isZero []int8) error { -======= func toBool(sc *stmtctx.StatementContext, tp *types.FieldType, eType types.EvalType, buf *chunk.Column, sel []int, isZero []int8) error { ->>>>>>> 556ccccde... expression: add implicit eval int and real for function dayname (#21806) switch eType { case types.ETInt: i64s := buf.Int64s() From 4ef1598eeda4c3ec83f08ef51e382e6f1636ff9e Mon Sep 17 00:00:00 2001 From: Yuanjia Zhang Date: Wed, 27 Jan 2021 15:04:10 +0800 Subject: [PATCH 3/3] fix CI --- expression/expression.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/expression/expression.go b/expression/expression.go index a7af4b4b6a042..f5fcbbf44d95f 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -333,9 +333,6 @@ func VecEvalBool(ctx sessionctx.Context, exprList CNFExprs, input *chunk.Chunk, for _, expr := range exprList { tp := expr.GetType() eType := tp.EvalType() - if expr.GetType().Hybrid() { - eType = types.ETInt - } if CanImplicitEvalReal(expr) { eType = types.ETReal }