From f0c716b4e138b1c3107909d83c99dfc99c74c135 Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Mon, 29 Jan 2024 01:22:39 +0530 Subject: [PATCH] evalengine: Implement TO_DAYS Signed-off-by: Noble Mittal --- go/vt/vtgate/evalengine/cached_size.go | 12 ++++++ go/vt/vtgate/evalengine/compiler_asm.go | 16 ++++++++ go/vt/vtgate/evalengine/fn_time.go | 40 ++++++++++++++++++++ go/vt/vtgate/evalengine/testcases/cases.go | 22 +++++++++++ go/vt/vtgate/evalengine/translate_builtin.go | 5 +++ 5 files changed, 95 insertions(+) diff --git a/go/vt/vtgate/evalengine/cached_size.go b/go/vt/vtgate/evalengine/cached_size.go index 077fcf0c2da..aab83effb05 100644 --- a/go/vt/vtgate/evalengine/cached_size.go +++ b/go/vt/vtgate/evalengine/cached_size.go @@ -1567,6 +1567,18 @@ func (cached *builtinToBase64) CachedSize(alloc bool) int64 { size += cached.CallExpr.CachedSize(false) return size } +func (cached *builtinToDays) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(48) + } + // field CallExpr vitess.io/vitess/go/vt/vtgate/evalengine.CallExpr + size += cached.CallExpr.CachedSize(false) + return size +} func (cached *builtinTrim) CachedSize(alloc bool) int64 { if cached == nil { return int64(0) diff --git a/go/vt/vtgate/evalengine/compiler_asm.go b/go/vt/vtgate/evalengine/compiler_asm.go index 1a750ed7d0e..ecae7a69b84 100644 --- a/go/vt/vtgate/evalengine/compiler_asm.go +++ b/go/vt/vtgate/evalengine/compiler_asm.go @@ -3795,6 +3795,22 @@ func (asm *assembler) Fn_LAST_DAY() { }, "FN LAST_DAY DATETIME(SP-1)") } +func (asm *assembler) Fn_TO_DAYS() { + asm.emit(func(env *ExpressionEnv) int { + if env.vm.stack[env.vm.sp-1] == nil { + return 1 + } + arg := env.vm.stack[env.vm.sp-1].(*evalTemporal) + if arg.dt.Date.IsZero() { + env.vm.stack[env.vm.sp-1] = nil + } else { + numDays := datetime.MysqlDayNumber(arg.dt.Date.Year(), arg.dt.Date.Month(), arg.dt.Date.Day()) + env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalInt64(int64(numDays)) + } + return 1 + }, "FN TO_DAYS DATE(SP-1)") +} + func (asm *assembler) Fn_QUARTER() { asm.emit(func(env *ExpressionEnv) int { if env.vm.stack[env.vm.sp-1] == nil { diff --git a/go/vt/vtgate/evalengine/fn_time.go b/go/vt/vtgate/evalengine/fn_time.go index de1b7259aff..f801d3d6b46 100644 --- a/go/vt/vtgate/evalengine/fn_time.go +++ b/go/vt/vtgate/evalengine/fn_time.go @@ -111,6 +111,10 @@ type ( CallExpr } + builtinToDays struct { + CallExpr + } + builtinQuarter struct { CallExpr } @@ -173,6 +177,7 @@ var _ IR = (*builtinMinute)(nil) var _ IR = (*builtinMonth)(nil) var _ IR = (*builtinMonthName)(nil) var _ IR = (*builtinLastDay)(nil) +var _ IR = (*builtinToDays)(nil) var _ IR = (*builtinQuarter)(nil) var _ IR = (*builtinSecond)(nil) var _ IR = (*builtinTime)(nil) @@ -1249,6 +1254,41 @@ func (call *builtinLastDay) compile(c *compiler) (ctype, error) { return ctype{Type: sqltypes.Date, Flag: arg.Flag | flagNullable}, nil } +func (b *builtinToDays) eval(env *ExpressionEnv) (eval, error) { + date, err := b.arg1(env) + if err != nil { + return nil, err + } + if date == nil { + return nil, nil + } + dt := evalToDateTime(date, -1, env.now, env.sqlmode.AllowZeroDate()) + if dt == nil || dt.isZero() { + return nil, nil + } + + numDays := datetime.MysqlDayNumber(dt.dt.Date.Year(), dt.dt.Date.Month(), dt.dt.Date.Day()) + return newEvalInt64(int64(numDays)), nil +} + +func (call *builtinToDays) compile(c *compiler) (ctype, error) { + arg, err := call.Arguments[0].compile(c) + if err != nil { + return ctype{}, err + } + + skip := c.compileNullCheck1(arg) + + switch arg.Type { + case sqltypes.Date, sqltypes.Datetime: + default: + c.asm.Convert_xD(1, true) + } + c.asm.Fn_TO_DAYS() + c.asm.jumpDestination(skip) + return ctype{Type: sqltypes.Int64, Col: collationNumeric, Flag: arg.Flag | flagNullable}, nil +} + func (b *builtinQuarter) eval(env *ExpressionEnv) (eval, error) { date, err := b.arg1(env) if err != nil { diff --git a/go/vt/vtgate/evalengine/testcases/cases.go b/go/vt/vtgate/evalengine/testcases/cases.go index 59ba6591a6d..9d8ac5f69a9 100644 --- a/go/vt/vtgate/evalengine/testcases/cases.go +++ b/go/vt/vtgate/evalengine/testcases/cases.go @@ -131,6 +131,7 @@ var Cases = []TestCase{ {Run: FnMonth}, {Run: FnMonthName}, {Run: FnLastDay}, + {Run: FnToDays}, {Run: FnQuarter}, {Run: FnSecond}, {Run: FnTime}, @@ -1766,6 +1767,27 @@ func FnLastDay(yield Query) { } } +func FnToDays(yield Query) { + for _, d := range inputConversions { + yield(fmt.Sprintf("TO_DAYS(%s)", d), nil) + } + + dates := []string{ + `DATE'0000-00-00'`, + `0`, + `'0000-00-00'`, + `DATE'2023-09-03 00:00:00'`, + `DATE'2023-09-03 07:00:00'`, + `DATE'0000-00-00 00:00:00'`, + `950501`, + `'2007-10-07'`, + } + + for _, d := range dates { + yield(fmt.Sprintf("TO_DAYS(%s)", d), nil) + } +} + func FnQuarter(yield Query) { for _, d := range inputConversions { yield(fmt.Sprintf("QUARTER(%s)", d), nil) diff --git a/go/vt/vtgate/evalengine/translate_builtin.go b/go/vt/vtgate/evalengine/translate_builtin.go index 1546a6e2610..66a62a36c7d 100644 --- a/go/vt/vtgate/evalengine/translate_builtin.go +++ b/go/vt/vtgate/evalengine/translate_builtin.go @@ -419,6 +419,11 @@ func (ast *astCompiler) translateFuncExpr(fn *sqlparser.FuncExpr) (IR, error) { return nil, argError(method) } return &builtinLastDay{CallExpr: call}, nil + case "to_days": + if len(args) != 1 { + return nil, argError(method) + } + return &builtinToDays{CallExpr: call}, nil case "quarter": if len(args) != 1 { return nil, argError(method)