Skip to content

Commit

Permalink
expression: add implicit eval int and real for function dayname (ping…
Browse files Browse the repository at this point in the history
  • Loading branch information
zanmato1984 authored Dec 17, 2020
1 parent 46fa162 commit 556cccc
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 16 deletions.
45 changes: 33 additions & 12 deletions expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,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
Expand Down Expand Up @@ -1185,6 +1191,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
Expand Down Expand Up @@ -1745,18 +1757,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
Expand All @@ -1774,10 +1799,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:
Expand Down
12 changes: 12 additions & 0 deletions expression/builtin_cast_vec.go
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,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 {
Expand Down Expand Up @@ -1557,6 +1563,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 {
Expand Down
39 changes: 35 additions & 4 deletions expression/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,24 @@ func VecEvalBool(ctx sessionctx.Context, exprList CNFExprs, input *chunk.Chunk,
for _, expr := range exprList {
tp := expr.GetType()
eType := tp.EvalType()
if CanImplicitEvalReal(expr) {
eType = types.ETReal
}
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
}

err = toBool(ctx.GetSessionVars().StmtCtx, tp, buf, sel, isZero)
err = toBool(ctx.GetSessionVars().StmtCtx, tp, eType, buf, sel, isZero)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -382,8 +390,7 @@ func VecEvalBool(ctx sessionctx.Context, exprList CNFExprs, input *chunk.Chunk,
return selected, nulls, nil
}

func toBool(sc *stmtctx.StatementContext, tp *types.FieldType, buf *chunk.Column, sel []int, isZero []int8) error {
eType := tp.EvalType()
func toBool(sc *stmtctx.StatementContext, tp *types.FieldType, eType types.EvalType, buf *chunk.Column, sel []int, isZero []int8) error {
switch eType {
case types.ETInt:
i64s := buf.Int64s()
Expand Down Expand Up @@ -499,6 +506,30 @@ func toBool(sc *stmtctx.StatementContext, tp *types.FieldType, buf *chunk.Column
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.
Expand Down
15 changes: 15 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1965,6 +1965,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)")
Expand Down

0 comments on commit 556cccc

Please sign in to comment.