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

expression: addition between `datetime` and `interval` is not compatible with Mysql #10329

Merged
merged 21 commits into from May 10, 2019

fix rounding

  • Loading branch information...
erjiaqing committed May 6, 2019
commit 18860bf5b38dc1e38883293549924decebacad51
@@ -1616,7 +1616,7 @@ func ExtractDurationNum(d *Duration, unit string) (int64, error) {
}

func parseSingleTimeValue(unit string, format string) (int64, int64, int64, int64, error) {
// As format is a preformatted number, it format should be A[.[B]].
// Format is a preformatted number, it format should be A[.[B]].
decimalPointPos := strings.IndexRune(format, '.')
if decimalPointPos == -1 {
decimalPointPos = len(format)
@@ -1625,48 +1625,52 @@ func parseSingleTimeValue(unit string, format string) (int64, int64, int64, int6
if err != nil {
return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
}
riv := iv // Rounded integer value

dv := int64(0)
lf := len(format) - 1
// Has fraction part
if decimalPointPos < lf {
if lf-decimalPointPos >= 6 {
if dv, err = strconv.ParseInt(format[decimalPointPos+1:decimalPointPos+7], 10, 64); err != nil {
This conversation was marked as resolved by erjiaqing

This comment has been minimized.

Copy link
@lamxTyler

lamxTyler May 9, 2019

Member

Should we raise a warning for truncated value?

This comment has been minimized.

Copy link
@erjiaqing

erjiaqing May 9, 2019

Author Contributor

MySQL does not raise a warning here, I think it is just a rounding rule instead of truncated value.

This comment has been minimized.

Copy link
@lamxTyler

lamxTyler May 9, 2019

Member
MySQL [(none)]> SELECT 10000101000000 + INTERVAL "111111111111111111.499999999999" MICROSECOND;
+-------------------------------------------------------------------------+
| 10000101000000 + INTERVAL "111111111111111111.499999999999" MICROSECOND |
+-------------------------------------------------------------------------+
| 4520-12-21 05:31:51.111111                                              |
+-------------------------------------------------------------------------+
1 row in set, 1 warning (0.001 sec)

MySQL [(none)]> show warnings;
+---------+------+----------------------------------------------------------------------+
| Level   | Code | Message                                                              |
+---------+------+----------------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect INTEGER value: '111111111111111111.499999999999' |
+---------+------+----------------------------------------------------------------------+
1 row in set (0.000 sec)

This comment has been minimized.

Copy link
@erjiaqing

erjiaqing May 9, 2019

Author Contributor

Resolved, this error should not add here, in fact, when unit is not SECOND and get a decimal, we need raise a warning.

return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
}
} else {
if dv, err = strconv.ParseInt(format[decimalPointPos+1:]+"000000"[:6-(lf-decimalPointPos)], 10, 64); err != nil {
return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
}
}
if dv >= 500000 { // Round up
This conversation was marked as resolved by qw4990

This comment has been minimized.

Copy link
@qw4990

qw4990 May 6, 2019

Contributor

Almost LGTM, and please add more test cases for this round up.

riv++
}
}
switch strings.ToUpper(unit) {
case "MICROSECOND":
dayCount := iv / (3600000000 * 24)
iv %= 3600000000 * 24
return 0, 0, dayCount, iv * int64(gotime.Microsecond), nil
dayCount := riv / (3600000000 * 24)
This conversation was marked as resolved by qw4990

This comment has been minimized.

Copy link
@lamxTyler

lamxTyler May 6, 2019

Member

It is better to use constants for these magic numbers.

riv %= 3600000000 * 24
return 0, 0, dayCount, riv * int64(gotime.Microsecond), nil
case "SECOND":
dayCount := iv / (3600 * 24)
iv %= 3600 * 24
dv := int64(0)
lf := len(format) - 1
// Has fractional part
if decimalPointPos < lf {
if lf-decimalPointPos >= 6 {
if dv, err = strconv.ParseInt(format[decimalPointPos+1:decimalPointPos+7], 10, 64); err != nil {
return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
}
} else {
if dv, err = strconv.ParseInt(format[decimalPointPos+1:]+"000000"[:6-(lf-decimalPointPos)], 10, 64); err != nil {
return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
}
}
}
return 0, 0, dayCount, iv*int64(gotime.Second) + dv*int64(gotime.Microsecond), nil
case "MINUTE":
dayCount := iv / (60 * 24)
iv %= 60 * 24
return 0, 0, dayCount, iv * int64(gotime.Minute), nil
dayCount := riv / (60 * 24)
riv %= 60 * 24
return 0, 0, dayCount, riv * int64(gotime.Minute), nil
case "HOUR":
dayCount := iv / 24
iv %= 24
return 0, 0, dayCount, iv * int64(gotime.Hour), nil
dayCount := riv / 24
riv %= 24
return 0, 0, dayCount, riv * int64(gotime.Hour), nil
case "DAY":
return 0, 0, iv, 0, nil
return 0, 0, riv, 0, nil
case "WEEK":
return 0, 0, 7 * iv, 0, nil
return 0, 0, 7 * riv, 0, nil
case "MONTH":
return 0, iv, 0, 0, nil
return 0, riv, 0, 0, nil
case "QUARTER":
return 0, 3 * iv, 0, 0, nil
return 0, 3 * riv, 0, 0, nil
case "YEAR":
return iv, 0, 0, 0, nil
return riv, 0, 0, 0, nil
}

return 0, 0, 0, 0, errors.Errorf("invalid singel timeunit - %s", unit)
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.