Skip to content

Commit

Permalink
*: fix a bug occurred when insert into time column (pingcap#6451)
Browse files Browse the repository at this point in the history
* *: fix a bug when insert decimal or decimal-like string into time col
  • Loading branch information
XuHuaiyu authored and zimulala committed May 9, 2018
1 parent 96ac1c7 commit 877d0d4
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 107 deletions.
11 changes: 11 additions & 0 deletions executor/write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,17 @@ func (s *testSuite) TestInsert(c *C) {
tk.MustQuery("select * from test use index (id) where id = 2").Check(testkit.Rows("2 2"))
tk.MustExec("insert into test values(2, 3)")
tk.MustQuery("select * from test use index (id) where id = 2").Check(testkit.Rows("2 2", "2 3"))

// issue 6424
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a time(6))")
tk.MustExec("insert into t value('20070219173709.055870'), ('20070219173709.055'), ('-20070219173709.055870'), ('20070219173709.055870123')")
tk.MustQuery("select * from t").Check(testkit.Rows("17:37:09.055870", "17:37:09.055000", "17:37:09.055870", "17:37:09.055870"))
tk.MustExec("truncate table t")
tk.MustExec("insert into t value(20070219173709.055870), (20070219173709.055), (20070219173709.055870123)")
tk.MustQuery("select * from t").Check(testkit.Rows("17:37:09.055870", "17:37:09.055000", "17:37:09.055870"))
_, err = tk.Exec("insert into t value(-20070219173709.055870)")
c.Assert(err.Error(), Equals, "[types:1292]Incorrect time value '-20070219173709.055870'")
}

func (s *testSuite) TestInsertAutoInc(c *C) {
Expand Down
34 changes: 12 additions & 22 deletions expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -2103,7 +2103,7 @@ func (c *timeLiteralFunctionClass) getFunction(ctx sessionctx.Context, args []Ex
if !isDuration(str) {
return nil, types.ErrIncorrectDatetimeValue.GenByArgs(str)
}
duration, err := types.ParseDuration(str, getFsp(str))
duration, err := types.ParseDuration(str, types.GetFsp(str))
if err != nil {
return nil, errors.Trace(err)
}
Expand Down Expand Up @@ -3508,9 +3508,9 @@ func (b *builtinTimestamp1ArgSig) evalTime(row types.Row) (types.Time, bool, err
var tm types.Time
sc := b.ctx.GetSessionVars().StmtCtx
if b.isFloat {
tm, err = types.ParseTimeFromFloatString(sc, s, mysql.TypeDatetime, getFsp(s))
tm, err = types.ParseTimeFromFloatString(sc, s, mysql.TypeDatetime, types.GetFsp(s))
} else {
tm, err = types.ParseTime(sc, s, mysql.TypeDatetime, getFsp(s))
tm, err = types.ParseTime(sc, s, mysql.TypeDatetime, types.GetFsp(s))
}
if err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
Expand Down Expand Up @@ -3540,9 +3540,9 @@ func (b *builtinTimestamp2ArgsSig) evalTime(row types.Row) (types.Time, bool, er
var tm types.Time
sc := b.ctx.GetSessionVars().StmtCtx
if b.isFloat {
tm, err = types.ParseTimeFromFloatString(sc, arg0, mysql.TypeDatetime, getFsp(arg0))
tm, err = types.ParseTimeFromFloatString(sc, arg0, mysql.TypeDatetime, types.GetFsp(arg0))
} else {
tm, err = types.ParseTime(sc, arg0, mysql.TypeDatetime, getFsp(arg0))
tm, err = types.ParseTime(sc, arg0, mysql.TypeDatetime, types.GetFsp(arg0))
}
if err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
Expand All @@ -3554,7 +3554,7 @@ func (b *builtinTimestamp2ArgsSig) evalTime(row types.Row) (types.Time, bool, er
if !isDuration(arg1) {
return types.Time{}, true, nil
}
duration, err := types.ParseDuration(arg1, getFsp(arg1))
duration, err := types.ParseDuration(arg1, types.GetFsp(arg1))
if err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
Expand Down Expand Up @@ -3588,7 +3588,7 @@ func (c *timestampLiteralFunctionClass) getFunction(ctx sessionctx.Context, args
if !timestampPattern.MatchString(str) {
return nil, types.ErrIncorrectDatetimeValue.GenByArgs(str)
}
tm, err := types.ParseTime(ctx.GetSessionVars().StmtCtx, str, mysql.TypeTimestamp, getFsp(str))
tm, err := types.ParseTime(ctx.GetSessionVars().StmtCtx, str, mysql.TypeTimestamp, types.GetFsp(str))
if err != nil {
return nil, errors.Trace(err)
}
Expand Down Expand Up @@ -3618,16 +3618,6 @@ func (b *builtinTimestampLiteralSig) evalTime(row types.Row) (types.Time, bool,
return b.tm, false, nil
}

func getFsp(s string) (fsp int) {
fsp = len(s) - strings.Index(s, ".") - 1
if fsp == len(s) {
fsp = 0
} else if fsp > 6 {
fsp = 6
}
return
}

// getFsp4TimeAddSub is used to in function 'ADDTIME' and 'SUBTIME' to evaluate `fsp` for the
// second parameter. It's used only if the second parameter is of string type. It's different
// from getFsp in that the result of getFsp4TimeAddSub is either 6 or 0.
Expand Down Expand Up @@ -3727,7 +3717,7 @@ func strDatetimeSubDuration(sc *stmtctx.StatementContext, d string, arg1 types.D
if err != nil {
return "", errors.Trace(err)
}
arg1time, err := arg1.ConvertToTime(sc, uint8(getFsp(arg1.String())))
arg1time, err := arg1.ConvertToTime(sc, uint8(types.GetFsp(arg1.String())))
if err != nil {
return "", errors.Trace(err)
}
Expand Down Expand Up @@ -3876,7 +3866,7 @@ func (b *builtinAddDatetimeAndStringSig) evalTime(row types.Row) (types.Time, bo
if !isDuration(s) {
return types.ZeroDatetime, true, nil
}
arg1, err := types.ParseDuration(s, getFsp(s))
arg1, err := types.ParseDuration(s, types.GetFsp(s))
if err != nil {
return types.ZeroDatetime, true, errors.Trace(err)
}
Expand Down Expand Up @@ -3952,7 +3942,7 @@ func (b *builtinAddDurationAndStringSig) evalDuration(row types.Row) (types.Dura
if !isDuration(s) {
return types.ZeroDuration, true, nil
}
arg1, err := types.ParseDuration(s, getFsp(s))
arg1, err := types.ParseDuration(s, types.GetFsp(s))
if err != nil {
return types.ZeroDuration, true, errors.Trace(err)
}
Expand Down Expand Up @@ -4732,7 +4722,7 @@ func (b *builtinSubDatetimeAndStringSig) evalTime(row types.Row) (types.Time, bo
if !isDuration(s) {
return types.ZeroDatetime, true, nil
}
arg1, err := types.ParseDuration(s, getFsp(s))
arg1, err := types.ParseDuration(s, types.GetFsp(s))
if err != nil {
return types.ZeroDatetime, true, errors.Trace(err)
}
Expand Down Expand Up @@ -4908,7 +4898,7 @@ func (b *builtinSubDurationAndStringSig) evalDuration(row types.Row) (types.Dura
if !isDuration(s) {
return types.ZeroDuration, true, nil
}
arg1, err := types.ParseDuration(s, getFsp(s))
arg1, err := types.ParseDuration(s, types.GetFsp(s))
if err != nil {
return types.ZeroDuration, true, errors.Trace(err)
}
Expand Down
4 changes: 2 additions & 2 deletions expression/builtin_time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ func (s *testEvaluatorSuite) TestAddTimeSig(c *C) {
{"-110:00:00", "1 02:00:00", "-84:00:00"},
}
for _, t := range tbl {
dur, err := types.ParseDuration(t.Input, getFsp(t.Input))
dur, err := types.ParseDuration(t.Input, types.GetFsp(t.Input))
c.Assert(err, IsNil)
tmpInput := types.NewDurationDatum(dur)
tmpInputDuration := types.NewStringDatum(t.InputDuration)
Expand Down Expand Up @@ -849,7 +849,7 @@ func (s *testEvaluatorSuite) TestSubTimeSig(c *C) {
{"235959", "00:00:01", "23:59:58"},
}
for _, t := range tbl {
dur, err := types.ParseDuration(t.Input, getFsp(t.Input))
dur, err := types.ParseDuration(t.Input, types.GetFsp(t.Input))
c.Assert(err, IsNil)
tmpInput := types.NewDurationDatum(dur)
tmpInputDuration := types.NewStringDatum(t.InputDuration)
Expand Down
2 changes: 1 addition & 1 deletion types/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -618,12 +618,12 @@ func (s *testTypeConvertSuite) TestConvert(c *C) {
signedAccept(c, mysql.TypeDuration, "10:11:12", "10:11:12")
signedAccept(c, mysql.TypeDuration, ZeroDatetime, "00:00:00")
signedAccept(c, mysql.TypeDuration, ZeroDuration, "00:00:00")
signedAccept(c, mysql.TypeDuration, 0, "00:00:00")

signedDeny(c, mysql.TypeDate, "2012-08-x", "0000-00-00")
signedDeny(c, mysql.TypeDatetime, "2012-08-x", "0000-00-00 00:00:00")
signedDeny(c, mysql.TypeTimestamp, "2012-08-x", "0000-00-00 00:00:00")
signedDeny(c, mysql.TypeDuration, "2012-08-x", "00:00:00")
signedDeny(c, mysql.TypeDuration, 0, "<nil>")

// string from string
signedAccept(c, mysql.TypeString, "abc", "abc")
Expand Down
13 changes: 13 additions & 0 deletions types/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,19 @@ func (d *Datum) convertToMysqlDuration(sc *stmtctx.StatementContext, target *Fie
if err != nil {
return ret, errors.Trace(err)
}
case KindInt64, KindFloat32, KindFloat64, KindMysqlDecimal:
// TODO: We need a ParseDurationFromNum to avoid the cost of converting a num to string.
timeStr, err := d.ToString()
if err != nil {
return ret, errors.Trace(err)
} else if timeStr[0] == '-' {
return ret, ErrInvalidTimeFormat.Gen("Incorrect time value '%s'", timeStr)
}
t, err := ParseDuration(timeStr, fsp)
ret.SetValue(t)
if err != nil {
return ret, errors.Trace(err)
}
case KindString, KindBytes:
t, err := ParseDuration(d.GetString(), fsp)
ret.SetValue(t)
Expand Down
Loading

0 comments on commit 877d0d4

Please sign in to comment.