diff --git a/go/mysql/datetime/datetime.go b/go/mysql/datetime/datetime.go index 0ca96787962..2db325b5d80 100644 --- a/go/mysql/datetime/datetime.go +++ b/go/mysql/datetime/datetime.go @@ -546,9 +546,9 @@ func (dt DateTime) Compare(dt2 DateTime) int { return dt.Time.Compare(dt2.Time) } -func (dt DateTime) AddInterval(itv *Interval, stradd bool) (DateTime, uint8, bool) { +func (dt DateTime) AddInterval(itv *Interval, prec uint8, stradd bool) (DateTime, uint8, bool) { ok := dt.addInterval(itv) - return dt, itv.precision(stradd), ok + return dt, max(prec, itv.precision(stradd)), ok } func (dt DateTime) Round(p int) (r DateTime) { diff --git a/go/vt/vtgate/evalengine/compiler_asm.go b/go/vt/vtgate/evalengine/compiler_asm.go index 653c0fa3bf4..de856bb4333 100644 --- a/go/vt/vtgate/evalengine/compiler_asm.go +++ b/go/vt/vtgate/evalengine/compiler_asm.go @@ -3286,31 +3286,32 @@ func cmpnum[N interface{ int64 | uint64 | float64 }](a, b N) int { } } -func (asm *assembler) Fn_Now(t querypb.Type, format *datetime.Strftime, prec uint8, utc bool) { +func (asm *assembler) Fn_Now(prec uint8, utc bool) { asm.adjustStack(1) asm.emit(func(env *ExpressionEnv) int { - val := env.vm.arena.newEvalBytesEmpty() - val.tt = int16(t) - val.bytes = format.Format(env.time(utc), prec) - val.col = collationBinary - env.vm.stack[env.vm.sp] = val + env.vm.stack[env.vm.sp] = env.vm.arena.newEvalDateTime(env.time(utc), int(prec)) env.vm.sp++ return 1 - }, "FN NOW") + }, "FN NOW(DATETIME)") +} + +func (asm *assembler) Fn_NowTime(prec uint8, utc bool) { + asm.adjustStack(1) + asm.emit(func(env *ExpressionEnv) int { + env.vm.stack[env.vm.sp] = env.vm.arena.newEvalTime(env.time(utc).Time, int(prec)) + env.vm.sp++ + return 1 + }, "FN NOW(TIME)") } func (asm *assembler) Fn_Sysdate(prec uint8) { asm.adjustStack(1) asm.emit(func(env *ExpressionEnv) int { - val := env.vm.arena.newEvalBytesEmpty() - val.tt = int16(sqltypes.Datetime) now := SystemTime() if tz := env.currentTimezone(); tz != nil { now = now.In(tz) } - val.bytes = datetime.NewDateTimeFromStd(now).Format(prec) - val.col = collationBinary - env.vm.stack[env.vm.sp] = val + env.vm.stack[env.vm.sp] = env.vm.arena.newEvalDateTime(datetime.NewDateTimeFromStd(now), int(prec)) env.vm.sp++ return 1 }, "FN SYSDATE") @@ -3319,11 +3320,7 @@ func (asm *assembler) Fn_Sysdate(prec uint8) { func (asm *assembler) Fn_Curdate() { asm.adjustStack(1) asm.emit(func(env *ExpressionEnv) int { - val := env.vm.arena.newEvalBytesEmpty() - val.tt = int16(sqltypes.Date) - val.bytes = datetime.Date_YYYY_MM_DD.Format(env.time(false), 0) - val.col = collationBinary - env.vm.stack[env.vm.sp] = val + env.vm.stack[env.vm.sp] = env.vm.arena.newEvalDate(env.time(false).Date) env.vm.sp++ return 1 }, "FN CURDATE") @@ -3332,11 +3329,7 @@ func (asm *assembler) Fn_Curdate() { func (asm *assembler) Fn_UtcDate() { asm.adjustStack(1) asm.emit(func(env *ExpressionEnv) int { - val := env.vm.arena.newEvalBytesEmpty() - val.tt = int16(sqltypes.Date) - val.bytes = datetime.Date_YYYY_MM_DD.Format(env.time(true), 0) - val.col = collationBinary - env.vm.stack[env.vm.sp] = val + env.vm.stack[env.vm.sp] = env.vm.arena.newEvalDate(env.time(true).Date) env.vm.sp++ return 1 }, "FN UTC_DATE") diff --git a/go/vt/vtgate/evalengine/compiler_test.go b/go/vt/vtgate/evalengine/compiler_test.go index 351f679a84a..537fc64be3c 100644 --- a/go/vt/vtgate/evalengine/compiler_test.go +++ b/go/vt/vtgate/evalengine/compiler_test.go @@ -603,6 +603,14 @@ func TestCompilerSingle(t *testing.T) { expression: `CAST(time '32:34:58.5' AS TIME)`, result: `TIME("32:34:59")`, }, + { + expression: `now(6) + interval 1 day`, + result: `DATETIME("2023-10-25 12:00:00.123456")`, + }, + { + expression: `now() + interval 654321 microsecond`, + result: `DATETIME("2023-10-24 12:00:00.654321")`, + }, } tz, _ := time.LoadLocation("Europe/Madrid") @@ -629,7 +637,7 @@ func TestCompilerSingle(t *testing.T) { } env := evalengine.NewExpressionEnv(context.Background(), nil, evalengine.NewEmptyVCursor(venv, tz)) - env.SetTime(time.Date(2023, 10, 24, 12, 0, 0, 0, tz)) + env.SetTime(time.Date(2023, 10, 24, 12, 0, 0, 123456000, tz)) env.Row = tc.values expected, err := env.EvaluateAST(converted) diff --git a/go/vt/vtgate/evalengine/eval_temporal.go b/go/vt/vtgate/evalengine/eval_temporal.go index 7952fc5aa5d..fec310f5bf7 100644 --- a/go/vt/vtgate/evalengine/eval_temporal.go +++ b/go/vt/vtgate/evalengine/eval_temporal.go @@ -153,7 +153,7 @@ func (e *evalTemporal) addInterval(interval *datetime.Interval, coll collations. tmp.dt.Time, tmp.prec, ok = e.dt.Time.AddInterval(interval, coll != collations.Unknown) case tt == sqltypes.Datetime || tt == sqltypes.Timestamp || (tt == sqltypes.Date && interval.Unit().HasTimeParts()) || (tt == sqltypes.Time && interval.Unit().HasDateParts()): tmp = e.toDateTime(int(e.prec), now) - tmp.dt, tmp.prec, ok = e.dt.AddInterval(interval, coll != collations.Unknown) + tmp.dt, tmp.prec, ok = e.dt.AddInterval(interval, tmp.prec, coll != collations.Unknown) } if !ok { return nil diff --git a/go/vt/vtgate/evalengine/fn_time.go b/go/vt/vtgate/evalengine/fn_time.go index 538dc59138c..82e38bff9d9 100644 --- a/go/vt/vtgate/evalengine/fn_time.go +++ b/go/vt/vtgate/evalengine/fn_time.go @@ -196,26 +196,22 @@ var _ IR = (*builtinYearWeek)(nil) func (call *builtinNow) eval(env *ExpressionEnv) (eval, error) { now := env.time(call.utc) if call.onlyTime { - buf := datetime.Time_hh_mm_ss.Format(now, call.prec) - return newEvalRaw(sqltypes.Time, buf, collationBinary), nil + return newEvalTime(now.Time, int(call.prec)), nil } else { - buf := datetime.DateTime_YYYY_MM_DD_hh_mm_ss.Format(now, call.prec) - return newEvalRaw(sqltypes.Datetime, buf, collationBinary), nil + return newEvalDateTime(now, int(call.prec), false), nil } } func (call *builtinNow) compile(c *compiler) (ctype, error) { - var format *datetime.Strftime var t sqltypes.Type if call.onlyTime { - format = datetime.Time_hh_mm_ss t = sqltypes.Time + c.asm.Fn_NowTime(call.prec, call.utc) } else { - format = datetime.DateTime_YYYY_MM_DD_hh_mm_ss t = sqltypes.Datetime + c.asm.Fn_Now(call.prec, call.utc) } - c.asm.Fn_Now(t, format, call.prec, call.utc) return ctype{Type: t, Col: collationBinary}, nil } @@ -228,7 +224,7 @@ func (call *builtinSysdate) eval(env *ExpressionEnv) (eval, error) { if tz := env.currentTimezone(); tz != nil { now = now.In(tz) } - return newEvalRaw(sqltypes.Datetime, datetime.NewDateTimeFromStd(now).Format(call.prec), collationBinary), nil + return newEvalDateTime(datetime.NewDateTimeFromStd(now), int(call.prec), false), nil } func (call *builtinSysdate) compile(c *compiler) (ctype, error) { @@ -242,7 +238,7 @@ func (call *builtinSysdate) constant() bool { func (call *builtinCurdate) eval(env *ExpressionEnv) (eval, error) { now := env.time(false) - return newEvalRaw(sqltypes.Date, datetime.Date_YYYY_MM_DD.Format(now, 0), collationBinary), nil + return newEvalDate(now.Date, false), nil } func (*builtinCurdate) compile(c *compiler) (ctype, error) { @@ -256,7 +252,7 @@ func (call *builtinCurdate) constant() bool { func (call *builtinUtcDate) eval(env *ExpressionEnv) (eval, error) { now := env.time(true) - return newEvalRaw(sqltypes.Date, datetime.Date_YYYY_MM_DD.Format(now, 0), collationBinary), nil + return newEvalDate(now.Date, false), nil } func (*builtinUtcDate) compile(c *compiler) (ctype, error) {