From 118f518e4f04d433dbef3e81b3ea0d03a1a68b14 Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Wed, 31 Jan 2024 01:23:23 +0530 Subject: [PATCH 1/9] Fix isLeap() for 0000 year Signed-off-by: Noble Mittal --- go/mysql/datetime/helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/mysql/datetime/helpers.go b/go/mysql/datetime/helpers.go index c199844df19..b91114fd791 100644 --- a/go/mysql/datetime/helpers.go +++ b/go/mysql/datetime/helpers.go @@ -245,7 +245,7 @@ func daysIn(m time.Month, year int) int { } func isLeap(year int) bool { - return year%4 == 0 && (year%100 != 0 || year%400 == 0) + return year%4 == 0 && (year%100 != 0 || year%400 == 0) && (year != 0) } func daysInYear(year int) int { From b13ea7085bec124e7c963e2cb2e0a16cefc97187 Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Wed, 31 Jan 2024 01:25:24 +0530 Subject: [PATCH 2/9] Add 0000 year in testcases Signed-off-by: Noble Mittal --- go/vt/vtgate/evalengine/testcases/inputs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/vtgate/evalengine/testcases/inputs.go b/go/vt/vtgate/evalengine/testcases/inputs.go index f5fa75854e0..c4ab5a685ee 100644 --- a/go/vt/vtgate/evalengine/testcases/inputs.go +++ b/go/vt/vtgate/evalengine/testcases/inputs.go @@ -108,7 +108,7 @@ var inputConversions = []string{ "'20000101103458foo'", "'20000101103458.1234foo'", "'20000101103458.123456foo'", "'20000101foo'", "'103458foo'", "'103458.123456foo'", "time '-10:04:58'", "time '-31:34:58'", "time '-32:34:58'", "time '-101:34:58'", "time '-5 10:34:58'", - "'10:04:58'", "'101:34:58'", "'5 10:34:58'", "'2000-01-01'", "'2000-01-01 12:34:58'", + "'10:04:58'", "'101:34:58'", "'5 10:34:58'", "'2000-01-01'", "'2000-01-01 12:34:58'", "'0000-02-29'", "'0000-01-03'", "'1969-02-18'", "cast(0 as json)", "cast(1 as json)", "cast(true as json)", "cast(false as json)", "cast('{}' as json)", "cast('[]' as json)", From 0495fe9b340719c2be7413fcb485f7b2be5eb910 Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Wed, 31 Jan 2024 01:25:56 +0530 Subject: [PATCH 3/9] Fix WEEKOFDAY and UNIX_TIMESTAMP Signed-off-by: Noble Mittal --- go/vt/vtgate/evalengine/compiler_asm.go | 9 +++++++-- go/vt/vtgate/evalengine/fn_time.go | 10 +++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/go/vt/vtgate/evalengine/compiler_asm.go b/go/vt/vtgate/evalengine/compiler_asm.go index 868ec6322b9..2bdb32aacce 100644 --- a/go/vt/vtgate/evalengine/compiler_asm.go +++ b/go/vt/vtgate/evalengine/compiler_asm.go @@ -3524,8 +3524,13 @@ func (asm *assembler) Fn_DAYOFWEEK() { if env.vm.stack[env.vm.sp-1] == nil { return 1 } - arg := env.vm.stack[env.vm.sp-1].(*evalTemporal) - env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalInt64(int64(arg.dt.Date.Weekday() + 1)) + d := env.vm.stack[env.vm.sp-1].(*evalTemporal) + + wd := d.dt.Date.ToStdTime(env.currentTimezone()).Weekday() + 1 + if d.dt.Date.Year() == 0 && d.dt.Date.Month() <= 2 { + wd += 1 + } + env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalInt64(int64(wd)) return 1 }, "FN DAYOFWEEK DATE(SP-1)") } diff --git a/go/vt/vtgate/evalengine/fn_time.go b/go/vt/vtgate/evalengine/fn_time.go index ecb1fedc135..427ad00771c 100644 --- a/go/vt/vtgate/evalengine/fn_time.go +++ b/go/vt/vtgate/evalengine/fn_time.go @@ -504,7 +504,12 @@ func (b *builtinDayOfWeek) eval(env *ExpressionEnv) (eval, error) { if d == nil || d.isZero() { return nil, nil } - return newEvalInt64(int64(d.dt.Date.ToStdTime(env.currentTimezone()).Weekday() + 1)), nil + + wd := d.dt.Date.ToStdTime(env.currentTimezone()).Weekday() + 1 + if d.dt.Date.Year() == 0 && d.dt.Date.Month() <= 2 { + wd += 1 + } + return newEvalInt64(int64(wd)), nil } func (call *builtinDayOfWeek) compile(c *compiler) (ctype, error) { @@ -1494,6 +1499,9 @@ func dateTimeUnixTimestamp(env *ExpressionEnv, date eval) evalNumeric { } ts := dt.dt.ToStdTime(env.now) + if ts.Before(time.Date(1970, 01, 01, 0, 0, 0, 0, time.UTC)) || ts.After(time.Date(3001, 1, 19, 3, 14, 7, 99999, time.UTC)) { + return newEvalInt64(0) + } if dt.prec == 0 { return newEvalInt64(ts.Unix()) } From 6629182027d2dae8dec4155fd7cd5446b134ed42 Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Fri, 2 Feb 2024 19:01:49 +0530 Subject: [PATCH 4/9] Fix Weekday for dates before 0000-02-29 Signed-off-by: Noble Mittal --- go/mysql/datetime/datetime.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/go/mysql/datetime/datetime.go b/go/mysql/datetime/datetime.go index 7a532818cc8..035ba010bb8 100644 --- a/go/mysql/datetime/datetime.go +++ b/go/mysql/datetime/datetime.go @@ -245,7 +245,14 @@ func (d Date) Hash(h *vthash.Hasher) { } func (d Date) Weekday() time.Weekday { - return d.ToStdTime(time.Local).Weekday() + // Go considers 0000-01-01 day as Saturaday, while + // MySQL considers it to be Sunday, now 0000-02-29 exists in + // Go but not in MySQL so it balances out after that + wd := d.ToStdTime(time.Local).Weekday() + if d.Year() == 0 && d.Month() <= 2 { + wd = (wd + 1) % 7 + } + return wd } func (d Date) Yearday() int { From 00a18822506eb79f3824f00c8c51876f04b046cb Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Fri, 2 Feb 2024 19:03:36 +0530 Subject: [PATCH 5/9] Add mysql limits to Timestamp and Convert_Tz Signed-off-by: Noble Mittal --- go/vt/vtgate/evalengine/compiler_asm.go | 8 ++------ go/vt/vtgate/evalengine/fn_time.go | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/go/vt/vtgate/evalengine/compiler_asm.go b/go/vt/vtgate/evalengine/compiler_asm.go index 2bdb32aacce..fa641210521 100644 --- a/go/vt/vtgate/evalengine/compiler_asm.go +++ b/go/vt/vtgate/evalengine/compiler_asm.go @@ -3496,7 +3496,7 @@ func (asm *assembler) Fn_CONVERT_TZ() { return 1 } - dt, ok := convertTz(n.dt, fromTz, toTz) + dt, ok := convertTz(n.dt, fromTz, toTz, env.now) if !ok { env.vm.stack[env.vm.sp-3] = nil env.vm.sp -= 2 @@ -3526,11 +3526,7 @@ func (asm *assembler) Fn_DAYOFWEEK() { } d := env.vm.stack[env.vm.sp-1].(*evalTemporal) - wd := d.dt.Date.ToStdTime(env.currentTimezone()).Weekday() + 1 - if d.dt.Date.Year() == 0 && d.dt.Date.Month() <= 2 { - wd += 1 - } - env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalInt64(int64(wd)) + env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalInt64(int64(d.dt.Date.Weekday() + 1)) return 1 }, "FN DAYOFWEEK DATE(SP-1)") } diff --git a/go/vt/vtgate/evalengine/fn_time.go b/go/vt/vtgate/evalengine/fn_time.go index 427ad00771c..285b0cdef88 100644 --- a/go/vt/vtgate/evalengine/fn_time.go +++ b/go/vt/vtgate/evalengine/fn_time.go @@ -335,7 +335,14 @@ type builtinConvertTz struct { var _ IR = (*builtinConvertTz)(nil) -func convertTz(dt datetime.DateTime, from, to *time.Location) (datetime.DateTime, bool) { +func convertTz(dt datetime.DateTime, from, to *time.Location, now time.Time) (datetime.DateTime, bool) { + t := dt.ToStdTime(now) + lowerBoundTz := time.Date(1970, 01, 01, 0, 0, 0, 0, time.UTC) + upperBoundTz := time.Date(3001, 1, 19, 3, 14, 7, 99999, time.UTC) + if t.Before(lowerBoundTz) || t.After(upperBoundTz) { + return dt, true + } + buf := datetime.DateTime_YYYY_MM_DD_hh_mm_ss.Format(dt, datetime.DefaultPrecision) ts, err := time.ParseInLocation(time.DateTime, hack.String(buf), from) if err != nil { @@ -380,7 +387,7 @@ func (call *builtinConvertTz) eval(env *ExpressionEnv) (eval, error) { return nil, nil } - out, ok := convertTz(dt.dt, fromTz, toTz) + out, ok := convertTz(dt.dt, fromTz, toTz, env.now) if !ok { return nil, nil } @@ -504,12 +511,7 @@ func (b *builtinDayOfWeek) eval(env *ExpressionEnv) (eval, error) { if d == nil || d.isZero() { return nil, nil } - - wd := d.dt.Date.ToStdTime(env.currentTimezone()).Weekday() + 1 - if d.dt.Date.Year() == 0 && d.dt.Date.Month() <= 2 { - wd += 1 - } - return newEvalInt64(int64(wd)), nil + return newEvalInt64(int64(d.dt.Date.Weekday() + 1)), nil } func (call *builtinDayOfWeek) compile(c *compiler) (ctype, error) { @@ -1499,9 +1501,12 @@ func dateTimeUnixTimestamp(env *ExpressionEnv, date eval) evalNumeric { } ts := dt.dt.ToStdTime(env.now) - if ts.Before(time.Date(1970, 01, 01, 0, 0, 0, 0, time.UTC)) || ts.After(time.Date(3001, 1, 19, 3, 14, 7, 99999, time.UTC)) { + lowerBoundTimestamp := time.Date(1970, 01, 01, 0, 0, 0, 0, time.UTC) + upperBoundTimestamp := time.Date(3001, 1, 19, 3, 14, 7, 99999, time.UTC) + if ts.Before(lowerBoundTimestamp) || ts.After(upperBoundTimestamp) { return newEvalInt64(0) } + if dt.prec == 0 { return newEvalInt64(ts.Unix()) } From da89a402993a79b05297e0112f02799bed902dcb Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Fri, 2 Feb 2024 19:06:34 +0530 Subject: [PATCH 6/9] Fix typo Signed-off-by: Noble Mittal --- go/mysql/datetime/datetime.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/mysql/datetime/datetime.go b/go/mysql/datetime/datetime.go index 035ba010bb8..1673a71d662 100644 --- a/go/mysql/datetime/datetime.go +++ b/go/mysql/datetime/datetime.go @@ -245,7 +245,7 @@ func (d Date) Hash(h *vthash.Hasher) { } func (d Date) Weekday() time.Weekday { - // Go considers 0000-01-01 day as Saturaday, while + // Go considers 0000-01-01 day as Saturday, while // MySQL considers it to be Sunday, now 0000-02-29 exists in // Go but not in MySQL so it balances out after that wd := d.ToStdTime(time.Local).Weekday() From 33ff855edbc3f32df17f0ab6ac2706417281ce69 Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Fri, 2 Feb 2024 19:25:05 +0530 Subject: [PATCH 7/9] Remove unnecessary change Signed-off-by: Noble Mittal --- go/vt/vtgate/evalengine/compiler_asm.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/go/vt/vtgate/evalengine/compiler_asm.go b/go/vt/vtgate/evalengine/compiler_asm.go index fa641210521..a43aacb2a63 100644 --- a/go/vt/vtgate/evalengine/compiler_asm.go +++ b/go/vt/vtgate/evalengine/compiler_asm.go @@ -3524,9 +3524,8 @@ func (asm *assembler) Fn_DAYOFWEEK() { if env.vm.stack[env.vm.sp-1] == nil { return 1 } - d := env.vm.stack[env.vm.sp-1].(*evalTemporal) - - env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalInt64(int64(d.dt.Date.Weekday() + 1)) + arg := env.vm.stack[env.vm.sp-1].(*evalTemporal) + env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalInt64(int64(arg.dt.Date.Weekday() + 1)) return 1 }, "FN DAYOFWEEK DATE(SP-1)") } From cb27206c4921bb535a01f7c7e6af6847af12f294 Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Tue, 6 Feb 2024 13:01:37 +0530 Subject: [PATCH 8/9] evalEngine: Fix the UNIX_TIMESTAMP and CONVERT_TZ func limits Signed-off-by: Noble Mittal --- go/vt/vtgate/evalengine/fn_time.go | 15 +++++---------- go/vt/vtgate/evalengine/testcases/inputs.go | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/go/vt/vtgate/evalengine/fn_time.go b/go/vt/vtgate/evalengine/fn_time.go index 285b0cdef88..ee9204c9d2b 100644 --- a/go/vt/vtgate/evalengine/fn_time.go +++ b/go/vt/vtgate/evalengine/fn_time.go @@ -336,18 +336,15 @@ type builtinConvertTz struct { var _ IR = (*builtinConvertTz)(nil) func convertTz(dt datetime.DateTime, from, to *time.Location, now time.Time) (datetime.DateTime, bool) { - t := dt.ToStdTime(now) - lowerBoundTz := time.Date(1970, 01, 01, 0, 0, 0, 0, time.UTC) - upperBoundTz := time.Date(3001, 1, 19, 3, 14, 7, 99999, time.UTC) - if t.Before(lowerBoundTz) || t.After(upperBoundTz) { - return dt, true - } - buf := datetime.DateTime_YYYY_MM_DD_hh_mm_ss.Format(dt, datetime.DefaultPrecision) ts, err := time.ParseInLocation(time.DateTime, hack.String(buf), from) if err != nil { return datetime.DateTime{}, false } + + if ts.Unix() < 0 || ts.Unix() >= maxUnixtime { + return dt, true + } return datetime.NewDateTimeFromStd(ts.In(to)), true } @@ -1501,9 +1498,7 @@ func dateTimeUnixTimestamp(env *ExpressionEnv, date eval) evalNumeric { } ts := dt.dt.ToStdTime(env.now) - lowerBoundTimestamp := time.Date(1970, 01, 01, 0, 0, 0, 0, time.UTC) - upperBoundTimestamp := time.Date(3001, 1, 19, 3, 14, 7, 99999, time.UTC) - if ts.Before(lowerBoundTimestamp) || ts.After(upperBoundTimestamp) { + if ts.Unix() < 0 || ts.Unix() >= maxUnixtime { return newEvalInt64(0) } diff --git a/go/vt/vtgate/evalengine/testcases/inputs.go b/go/vt/vtgate/evalengine/testcases/inputs.go index c4ab5a685ee..b4a558d1145 100644 --- a/go/vt/vtgate/evalengine/testcases/inputs.go +++ b/go/vt/vtgate/evalengine/testcases/inputs.go @@ -108,7 +108,7 @@ var inputConversions = []string{ "'20000101103458foo'", "'20000101103458.1234foo'", "'20000101103458.123456foo'", "'20000101foo'", "'103458foo'", "'103458.123456foo'", "time '-10:04:58'", "time '-31:34:58'", "time '-32:34:58'", "time '-101:34:58'", "time '-5 10:34:58'", - "'10:04:58'", "'101:34:58'", "'5 10:34:58'", "'2000-01-01'", "'2000-01-01 12:34:58'", "'0000-02-29'", "'0000-01-03'", "'1969-02-18'", + "'10:04:58'", "'101:34:58'", "'5 10:34:58'", "'2000-01-01'", "'2000-01-01 12:34:58'", "'0000-02-29'", "'0000-01-03'", "'1969-02-18'", "'1970-01-01 00:00:01'", "'3001-02-19 00:00:00'", "'3001-02-18 23:59:59'", "cast(0 as json)", "cast(1 as json)", "cast(true as json)", "cast(false as json)", "cast('{}' as json)", "cast('[]' as json)", From 46e6b4c290b38e8a12540402faeeb7e898adef01 Mon Sep 17 00:00:00 2001 From: Noble Mittal Date: Tue, 6 Feb 2024 16:28:04 +0530 Subject: [PATCH 9/9] Remove the unnecessary argument from convertTz Signed-off-by: Noble Mittal --- go/vt/vtgate/evalengine/compiler_asm.go | 2 +- go/vt/vtgate/evalengine/fn_time.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go/vt/vtgate/evalengine/compiler_asm.go b/go/vt/vtgate/evalengine/compiler_asm.go index a43aacb2a63..868ec6322b9 100644 --- a/go/vt/vtgate/evalengine/compiler_asm.go +++ b/go/vt/vtgate/evalengine/compiler_asm.go @@ -3496,7 +3496,7 @@ func (asm *assembler) Fn_CONVERT_TZ() { return 1 } - dt, ok := convertTz(n.dt, fromTz, toTz, env.now) + dt, ok := convertTz(n.dt, fromTz, toTz) if !ok { env.vm.stack[env.vm.sp-3] = nil env.vm.sp -= 2 diff --git a/go/vt/vtgate/evalengine/fn_time.go b/go/vt/vtgate/evalengine/fn_time.go index ee9204c9d2b..319f8d1b328 100644 --- a/go/vt/vtgate/evalengine/fn_time.go +++ b/go/vt/vtgate/evalengine/fn_time.go @@ -335,7 +335,7 @@ type builtinConvertTz struct { var _ IR = (*builtinConvertTz)(nil) -func convertTz(dt datetime.DateTime, from, to *time.Location, now time.Time) (datetime.DateTime, bool) { +func convertTz(dt datetime.DateTime, from, to *time.Location) (datetime.DateTime, bool) { buf := datetime.DateTime_YYYY_MM_DD_hh_mm_ss.Format(dt, datetime.DefaultPrecision) ts, err := time.ParseInLocation(time.DateTime, hack.String(buf), from) if err != nil { @@ -384,7 +384,7 @@ func (call *builtinConvertTz) eval(env *ExpressionEnv) (eval, error) { return nil, nil } - out, ok := convertTz(dt.dt, fromTz, toTz, env.now) + out, ok := convertTz(dt.dt, fromTz, toTz) if !ok { return nil, nil }