Skip to content

Commit

Permalink
Function SUBTIME should return NULL with a warning if its argument is…
Browse files Browse the repository at this point in the history
… an invalid time value. (pingcap#11175)
  • Loading branch information
kanchairen authored and root committed Jul 19, 2019
1 parent ffe55b8 commit 214f77c
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 7 deletions.
64 changes: 58 additions & 6 deletions expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -4801,6 +4801,10 @@ func (b *builtinAddDatetimeAndStringSig) evalTime(row chunk.Row) (types.Time, bo
sc := b.ctx.GetSessionVars().StmtCtx
arg1, err := types.ParseDuration(sc, s, types.GetFsp(s))
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return types.ZeroDatetime, true, nil
}
return types.ZeroDatetime, true, err
}
result, err := arg0.Add(sc, arg1)
Expand Down Expand Up @@ -4875,8 +4879,13 @@ func (b *builtinAddDurationAndStringSig) evalDuration(row chunk.Row) (types.Dura
if !isDuration(s) {
return types.ZeroDuration, true, nil
}
arg1, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, s, types.GetFsp(s))
sc := b.ctx.GetSessionVars().StmtCtx
arg1, err := types.ParseDuration(sc, s, types.GetFsp(s))
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return types.ZeroDuration, true, nil
}
return types.ZeroDuration, true, err
}
result, err := arg0.Add(arg1)
Expand Down Expand Up @@ -4931,6 +4940,10 @@ func (b *builtinAddStringAndDurationSig) evalString(row chunk.Row) (result strin
if isDuration(arg0) {
result, err = strDurationAddDuration(sc, arg0, arg1)
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return "", true, nil
}
return "", true, err
}
return result, false, nil
Expand Down Expand Up @@ -4971,11 +4984,19 @@ func (b *builtinAddStringAndStringSig) evalString(row chunk.Row) (result string,
sc := b.ctx.GetSessionVars().StmtCtx
arg1, err = types.ParseDuration(sc, arg1Str, getFsp4TimeAddSub(arg1Str))
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return "", true, nil
}
return "", true, err
}
if isDuration(arg0) {
result, err = strDurationAddDuration(sc, arg0, arg1)
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return "", true, nil
}
return "", true, err
}
return result, false, nil
Expand Down Expand Up @@ -5033,8 +5054,13 @@ func (b *builtinAddDateAndStringSig) evalString(row chunk.Row) (string, bool, er
if !isDuration(s) {
return "", true, nil
}
arg1, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, s, getFsp4TimeAddSub(s))
sc := b.ctx.GetSessionVars().StmtCtx
arg1, err := types.ParseDuration(sc, s, getFsp4TimeAddSub(s))
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return "", true, nil
}
return "", true, err
}
result, err := arg0.Add(arg1)
Expand Down Expand Up @@ -5705,6 +5731,10 @@ func (b *builtinSubDatetimeAndStringSig) evalTime(row chunk.Row) (types.Time, bo
sc := b.ctx.GetSessionVars().StmtCtx
arg1, err := types.ParseDuration(sc, s, types.GetFsp(s))
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return types.ZeroDatetime, true, nil
}
return types.ZeroDatetime, true, err
}
arg1time, err := arg1.ConvertToTime(sc, mysql.TypeDatetime)
Expand Down Expand Up @@ -5761,6 +5791,10 @@ func (b *builtinSubStringAndDurationSig) evalString(row chunk.Row) (result strin
if isDuration(arg0) {
result, err = strDurationSubDuration(sc, arg0, arg1)
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return "", true, nil
}
return "", true, err
}
return result, false, nil
Expand Down Expand Up @@ -5798,14 +5832,22 @@ func (b *builtinSubStringAndStringSig) evalString(row chunk.Row) (result string,
if isNull || err != nil {
return "", isNull, err
}
arg1, err = types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, s, getFsp4TimeAddSub(s))
sc := b.ctx.GetSessionVars().StmtCtx
arg1, err = types.ParseDuration(sc, s, getFsp4TimeAddSub(s))
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return "", true, nil
}
return "", true, err
}
sc := b.ctx.GetSessionVars().StmtCtx
if isDuration(arg0) {
result, err = strDurationSubDuration(sc, arg0, arg1)
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return "", true, nil
}
return "", true, err
}
return result, false, nil
Expand Down Expand Up @@ -5882,8 +5924,13 @@ func (b *builtinSubDurationAndStringSig) evalDuration(row chunk.Row) (types.Dura
if !isDuration(s) {
return types.ZeroDuration, true, nil
}
arg1, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, s, types.GetFsp(s))
sc := b.ctx.GetSessionVars().StmtCtx
arg1, err := types.ParseDuration(sc, s, types.GetFsp(s))
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return types.ZeroDuration, true, nil
}
return types.ZeroDuration, true, err
}
result, err := arg0.Sub(arg1)
Expand Down Expand Up @@ -5955,8 +6002,13 @@ func (b *builtinSubDateAndStringSig) evalString(row chunk.Row) (string, bool, er
if !isDuration(s) {
return "", true, nil
}
arg1, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, s, getFsp4TimeAddSub(s))
sc := b.ctx.GetSessionVars().StmtCtx
arg1, err := types.ParseDuration(sc, s, getFsp4TimeAddSub(s))
if err != nil {
if terror.ErrorEqual(err, types.ErrTruncatedWrongVal) {
sc.AppendWarning(err)
return "", true, nil
}
return "", true, err
}
result, err := arg0.Sub(arg1)
Expand Down
56 changes: 56 additions & 0 deletions expression/builtin_time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/pingcap/parser/ast"
"github.com/pingcap/parser/charset"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/parser/terror"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/sessionctx/stmtctx"
"github.com/pingcap/tidb/sessionctx/variable"
Expand Down Expand Up @@ -937,6 +938,33 @@ func (s *testEvaluatorSuite) TestAddTimeSig(c *C) {
c.Assert(result, Equals, t.expect)
}

tblWarning := []struct {
Input interface{}
InputDuration interface{}
warning *terror.Error
}{
{"0", "-32073", types.ErrTruncatedWrongVal},
{"-32073", "0", types.ErrTruncatedWrongVal},
{types.ZeroDuration, "-32073", types.ErrTruncatedWrongVal},
{"-32073", types.ZeroDuration, types.ErrTruncatedWrongVal},
{types.CurrentTime(mysql.TypeTimestamp), "-32073", types.ErrTruncatedWrongVal},
{types.CurrentTime(mysql.TypeDate), "-32073", types.ErrTruncatedWrongVal},
{types.CurrentTime(mysql.TypeDatetime), "-32073", types.ErrTruncatedWrongVal},
}
for i, t := range tblWarning {
tmpInput := types.NewDatum(t.Input)
tmpInputDuration := types.NewDatum(t.InputDuration)
f, err := fc.getFunction(s.ctx, s.datumsToConstants([]types.Datum{tmpInput, tmpInputDuration}))
c.Assert(err, IsNil)
d, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
result, _ := d.ToString()
c.Assert(result, Equals, "")
c.Assert(d.IsNull(), Equals, true)
warnings := s.ctx.GetSessionVars().StmtCtx.GetWarnings()
c.Assert(len(warnings), Equals, i+1)
c.Assert(terror.ErrorEqual(t.warning, warnings[i].Err), IsTrue, Commentf("err %v", warnings[i].Err))
}
}

func (s *testEvaluatorSuite) TestSubTimeSig(c *C) {
Expand Down Expand Up @@ -1002,6 +1030,34 @@ func (s *testEvaluatorSuite) TestSubTimeSig(c *C) {
result, _ := d.ToString()
c.Assert(result, Equals, t.expect)
}

tblWarning := []struct {
Input interface{}
InputDuration interface{}
warning *terror.Error
}{
{"0", "-32073", types.ErrTruncatedWrongVal},
{"-32073", "0", types.ErrTruncatedWrongVal},
{types.ZeroDuration, "-32073", types.ErrTruncatedWrongVal},
{"-32073", types.ZeroDuration, types.ErrTruncatedWrongVal},
{types.CurrentTime(mysql.TypeTimestamp), "-32073", types.ErrTruncatedWrongVal},
{types.CurrentTime(mysql.TypeDate), "-32073", types.ErrTruncatedWrongVal},
{types.CurrentTime(mysql.TypeDatetime), "-32073", types.ErrTruncatedWrongVal},
}
for i, t := range tblWarning {
tmpInput := types.NewDatum(t.Input)
tmpInputDuration := types.NewDatum(t.InputDuration)
f, err := fc.getFunction(s.ctx, s.datumsToConstants([]types.Datum{tmpInput, tmpInputDuration}))
c.Assert(err, IsNil)
d, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
result, _ := d.ToString()
c.Assert(result, Equals, "")
c.Assert(d.IsNull(), Equals, true)
warnings := s.ctx.GetSessionVars().StmtCtx.GetWarnings()
c.Assert(len(warnings), Equals, i+1)
c.Assert(terror.ErrorEqual(t.warning, warnings[i].Err), IsTrue, Commentf("err %v", warnings[i].Err))
}
}

func (s *testEvaluatorSuite) TestSysDate(c *C) {
Expand Down
35 changes: 34 additions & 1 deletion expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1430,14 +1430,47 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) {
result.Check(testkit.Rows("<nil> <nil> <nil>"))
result = tk.MustQuery("select addtime('2017-01-01', 1), addtime('2017-01-01 01:01:01', 1), addtime(cast('2017-01-01' as date), 1)")
result.Check(testkit.Rows("2017-01-01 00:00:01 2017-01-01 01:01:02 00:00:01"))

result = tk.MustQuery("select subtime(a, e), subtime(b, e), subtime(c, e), subtime(d, e) from t")
result.Check(testkit.Rows("<nil> <nil> <nil> <nil>"))
result = tk.MustQuery("select subtime('2017-01-01 01:01:01', 0b1), subtime('2017-01-01', b'1'), subtime('01:01:01', 0b1011)")
result.Check(testkit.Rows("<nil> <nil> <nil>"))
result = tk.MustQuery("select subtime('2017-01-01', 1), subtime('2017-01-01 01:01:01', 1), subtime(cast('2017-01-01' as date), 1)")
result.Check(testkit.Rows("2016-12-31 23:59:59 2017-01-01 01:01:00 -00:00:01"))

result = tk.MustQuery("select addtime(-32073, 0), addtime(0, -32073);")
result.Check(testkit.Rows("<nil> <nil>"))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|",
"Warning|1292|Truncated incorrect time value: '-32073'",
"Warning|1292|Truncated incorrect time value: '-32073'"))
result = tk.MustQuery("select addtime(-32073, c), addtime(c, -32073) from t;")
result.Check(testkit.Rows("<nil> <nil>"))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|",
"Warning|1292|Truncated incorrect time value: '-32073'",
"Warning|1292|Truncated incorrect time value: '-32073'"))
result = tk.MustQuery("select addtime(a, -32073), addtime(b, -32073), addtime(d, -32073) from t;")
result.Check(testkit.Rows("<nil> <nil> <nil>"))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|",
"Warning|1292|Truncated incorrect time value: '-32073'",
"Warning|1292|Truncated incorrect time value: '-32073'",
"Warning|1292|Truncated incorrect time value: '-32073'"))

result = tk.MustQuery("select subtime(-32073, 0), subtime(0, -32073);")
result.Check(testkit.Rows("<nil> <nil>"))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|",
"Warning|1292|Truncated incorrect time value: '-32073'",
"Warning|1292|Truncated incorrect time value: '-32073'"))
result = tk.MustQuery("select subtime(-32073, c), subtime(c, -32073) from t;")
result.Check(testkit.Rows("<nil> <nil>"))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|",
"Warning|1292|Truncated incorrect time value: '-32073'",
"Warning|1292|Truncated incorrect time value: '-32073'"))
result = tk.MustQuery("select subtime(a, -32073), subtime(b, -32073), subtime(d, -32073) from t;")
result.Check(testkit.Rows("<nil> <nil> <nil>"))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|",
"Warning|1292|Truncated incorrect time value: '-32073'",
"Warning|1292|Truncated incorrect time value: '-32073'",
"Warning|1292|Truncated incorrect time value: '-32073'"))

// fixed issue #3986
tk.MustExec("SET SQL_MODE='NO_ENGINE_SUBSTITUTION';")
tk.MustExec("SET TIME_ZONE='+03:00';")
Expand Down

0 comments on commit 214f77c

Please sign in to comment.