Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix evalEngine functions for dates on/before 0000-02-29 #15124

Merged
merged 9 commits into from
Feb 7, 2024
9 changes: 8 additions & 1 deletion go/mysql/datetime/datetime.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 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()
if d.Year() == 0 && d.Month() <= 2 {
wd = (wd + 1) % 7
}
return wd
}

func (d Date) Yearday() int {
Expand Down
2 changes: 1 addition & 1 deletion go/mysql/datetime/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
10 changes: 9 additions & 1 deletion go/vt/vtgate/evalengine/fn_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,10 @@ func convertTz(dt datetime.DateTime, from, to *time.Location) (datetime.DateTime
if err != nil {
return datetime.DateTime{}, false
}

if ts.Unix() < 0 || ts.Unix() >= maxUnixtime {
return dt, true
}
return datetime.NewDateTimeFromStd(ts.In(to)), true
}

Expand Down Expand Up @@ -504,7 +508,7 @@ 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
return newEvalInt64(int64(d.dt.Date.Weekday() + 1)), nil
}

func (call *builtinDayOfWeek) compile(c *compiler) (ctype, error) {
Expand Down Expand Up @@ -1494,6 +1498,10 @@ func dateTimeUnixTimestamp(env *ExpressionEnv, date eval) evalNumeric {
}

ts := dt.dt.ToStdTime(env.now)
if ts.Unix() < 0 || ts.Unix() >= maxUnixtime {
return newEvalInt64(0)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I think testing against unix time stamps is much simpler here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.


if dt.prec == 0 {
return newEvalInt64(ts.Unix())
}
Expand Down
2 changes: 1 addition & 1 deletion go/vt/vtgate/evalengine/testcases/inputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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'", "'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)",
Expand Down
Loading