Skip to content

Commit

Permalink
types: fix invalid time cast bug (pingcap#4338)
Browse files Browse the repository at this point in the history
  • Loading branch information
mccxj authored and winoros committed Nov 22, 2017
1 parent 0ff13ce commit 8892bdf
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 3 deletions.
11 changes: 11 additions & 0 deletions expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,13 @@ func (b *builtinCastDecimalAsDurationSig) evalDuration(row types.Row) (res types
return res, false, errors.Trace(err)
}
res, err = types.ParseDuration(string(val.ToString()), b.tp.Decimal)
if types.ErrTruncatedWrongVal.Equal(err) {
err = sc.HandleTruncate(err)
// ZeroDuration of error ErrTruncatedWrongVal needs to be considered NULL.
if res == types.ZeroDuration {
return res, true, errors.Trace(err)
}
}
return res, false, errors.Trace(err)
}

Expand Down Expand Up @@ -1002,6 +1009,10 @@ func (b *builtinCastStringAsDurationSig) evalDuration(row types.Row) (res types.
res, err = types.ParseDuration(val, b.tp.Decimal)
if types.ErrTruncatedWrongVal.Equal(err) {
err = sc.HandleTruncate(err)
// ZeroDuration of error ErrTruncatedWrongVal needs to be considered NULL.
if res == types.ZeroDuration {
return res, true, errors.Trace(err)
}
}
return res, false, errors.Trace(err)
}
Expand Down
35 changes: 35 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1806,6 +1806,41 @@ func (s *testIntegrationSuite) TestBuiltin(c *C) {
result = tk.MustQuery("select cast('-34 100:00:00' as time);")
result.Check(testkit.Rows("-838:59:59"))

// fix issue #4324. cast decimal/int/string to time compability.
invalidTimes := []string{
"10009010",
"239010",
"233070",
"23:90:10",
"23:30:70",
"239010.2",
"233070.8",
}
tk.MustExec("DROP TABLE IF EXISTS t;")
tk.MustExec("CREATE TABLE t (ix TIME);")
tk.MustExec("SET SQL_MODE='';")
for _, invalidTime := range invalidTimes {
msg := fmt.Sprintf("Warning 1292 Truncated incorrect time value: '%s'", invalidTime)
result = tk.MustQuery(fmt.Sprintf("select cast('%s' as time);", invalidTime))
result.Check(testkit.Rows("<nil>"))
result = tk.MustQuery("show warnings")
result.Check(testkit.Rows(msg))
_, err := tk.Exec(fmt.Sprintf("insert into t select cast('%s' as time);", invalidTime))
c.Assert(err, IsNil)
result = tk.MustQuery("show warnings")
result.Check(testkit.Rows(msg))
}
tk.MustExec("set sql_mode = 'STRICT_TRANS_TABLES'")
for _, invalidTime := range invalidTimes {
msg := fmt.Sprintf("Warning 1292 Truncated incorrect time value: '%s'", invalidTime)
result = tk.MustQuery(fmt.Sprintf("select cast('%s' as time);", invalidTime))
result.Check(testkit.Rows("<nil>"))
result = tk.MustQuery("show warnings")
result.Check(testkit.Rows(msg))
_, err := tk.Exec(fmt.Sprintf("insert into t select cast('%s' as time);", invalidTime))
c.Assert(err.Error(), Equals, fmt.Sprintf("[types:1292]Truncated incorrect time value: '%s'", invalidTime))
}

// Fix issue #3691, cast compatibility.
result = tk.MustQuery("select cast('18446744073709551616' as unsigned);")
result.Check(testkit.Rows("18446744073709551615"))
Expand Down
2 changes: 1 addition & 1 deletion terror/terror.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const (
// CodeUnknown is for errors of unknown reason.
CodeUnknown ErrCode = -1
// CodeExecResultIsEmpty indicates execution result is empty.
CodeExecResultIsEmpty = 3
CodeExecResultIsEmpty ErrCode = 3

// Expression error codes.

Expand Down
10 changes: 8 additions & 2 deletions types/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,7 @@ func ParseDuration(str string, fsp int) (Duration, error) {
err error
sign = 0
dayExists = false
origStr = str
)

fsp, err = CheckFsp(fsp)
Expand Down Expand Up @@ -1040,7 +1041,7 @@ func ParseDuration(str string, fsp int) (Duration, error) {
if err1 == nil {
return t.ConvertToDuration()
}
return ZeroDuration, errors.Trace(ErrInvalidTimeFormat)
return ZeroDuration, ErrTruncatedWrongVal.GenByArgs("time", origStr)
}
}
case 2:
Expand All @@ -1055,7 +1056,7 @@ func ParseDuration(str string, fsp int) (Duration, error) {
_, err = fmt.Sscanf(str, "%2d:%2d:%2d", &hour, &minute, &second)
}
default:
return ZeroDuration, errors.Trace(ErrInvalidTimeFormat)
return ZeroDuration, ErrTruncatedWrongVal.GenByArgs("time", origStr)
}

if err != nil {
Expand All @@ -1066,6 +1067,11 @@ func ParseDuration(str string, fsp int) (Duration, error) {
second++
frac = 0
}
// Invalid TIME values are converted to '00:00:00'.
// See https://dev.mysql.com/doc/refman/5.7/en/time.html
if minute >= 60 || second >= 60 {
return ZeroDuration, ErrTruncatedWrongVal.GenByArgs("time", origStr)
}
d := gotime.Duration(day*24*3600+hour*3600+minute*60+second)*gotime.Second + gotime.Duration(frac)*gotime.Microsecond
if sign == -1 {
d = -d
Expand Down

0 comments on commit 8892bdf

Please sign in to comment.