From df005918c5657c15d66f2ed42e0ef84645976a15 Mon Sep 17 00:00:00 2001 From: wjHuang Date: Thu, 10 Dec 2020 14:34:52 +0800 Subject: [PATCH] cherry pick #21600 to release-4.0 Signed-off-by: ti-srebot --- expression/builtin_time.go | 38 +++++++++++++----------- expression/builtin_time_test.go | 14 +++++++-- expression/builtin_time_vec_generated.go | 32 +++++++++++++++++--- expression/generator/time_vec.go | 22 ++++++++++---- 4 files changed, 78 insertions(+), 28 deletions(-) diff --git a/expression/builtin_time.go b/expression/builtin_time.go index dae4b1b37e8f8..5feedb293d59e 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -5075,21 +5075,23 @@ func isDuration(str string) bool { } // strDatetimeAddDuration adds duration to datetime string, returns a string value. -func strDatetimeAddDuration(sc *stmtctx.StatementContext, d string, arg1 types.Duration) (string, error) { +func strDatetimeAddDuration(sc *stmtctx.StatementContext, d string, arg1 types.Duration) (result string, isNull bool, err error) { arg0, err := types.ParseTime(sc, d, mysql.TypeDatetime, types.MaxFsp) if err != nil { - return "", err + // Return a warning regardless of the sql_mode, this is compatible with MySQL. + sc.AppendWarning(err) + return "", true, nil } ret, err := arg0.Add(sc, arg1) if err != nil { - return "", err + return "", false, err } fsp := types.MaxFsp if ret.Microsecond() == 0 { fsp = types.MinFsp } ret.SetFsp(fsp) - return ret.String(), nil + return ret.String(), false, nil } // strDurationAddDuration adds duration to duration string, returns a string value. @@ -5110,14 +5112,16 @@ func strDurationAddDuration(sc *stmtctx.StatementContext, d string, arg1 types.D } // strDatetimeSubDuration subtracts duration from datetime string, returns a string value. -func strDatetimeSubDuration(sc *stmtctx.StatementContext, d string, arg1 types.Duration) (string, error) { +func strDatetimeSubDuration(sc *stmtctx.StatementContext, d string, arg1 types.Duration) (result string, isNull bool, err error) { arg0, err := types.ParseTime(sc, d, mysql.TypeDatetime, types.MaxFsp) if err != nil { - return "", err + // Return a warning regardless of the sql_mode, this is compatible with MySQL. + sc.AppendWarning(err) + return "", true, nil } arg1time, err := arg1.ConvertToTime(sc, uint8(types.GetFsp(arg1.String()))) if err != nil { - return "", err + return "", false, err } tmpDuration := arg0.Sub(sc, &arg1time) fsp := types.MaxFsp @@ -5126,10 +5130,10 @@ func strDatetimeSubDuration(sc *stmtctx.StatementContext, d string, arg1 types.D } resultDuration, err := tmpDuration.ConvertToTime(sc, mysql.TypeDatetime) if err != nil { - return "", err + return "", false, err } resultDuration.SetFsp(fsp) - return resultDuration.String(), nil + return resultDuration.String(), false, nil } // strDurationSubDuration subtracts duration from duration string, returns a string value. @@ -5430,8 +5434,8 @@ func (b *builtinAddStringAndDurationSig) evalString(row chunk.Row) (result strin } return result, false, nil } - result, err = strDatetimeAddDuration(sc, arg0, arg1) - return result, err != nil, err + result, isNull, err = strDatetimeAddDuration(sc, arg0, arg1) + return result, isNull, err } type builtinAddStringAndStringSig struct { @@ -5483,8 +5487,8 @@ func (b *builtinAddStringAndStringSig) evalString(row chunk.Row) (result string, } return result, false, nil } - result, err = strDatetimeAddDuration(sc, arg0, arg1) - return result, err != nil, err + result, isNull, err = strDatetimeAddDuration(sc, arg0, arg1) + return result, isNull, err } type builtinAddDateAndDurationSig struct { @@ -6308,8 +6312,8 @@ func (b *builtinSubStringAndDurationSig) evalString(row chunk.Row) (result strin } return result, false, nil } - result, err = strDatetimeSubDuration(sc, arg0, arg1) - return result, err != nil, err + result, isNull, err = strDatetimeSubDuration(sc, arg0, arg1) + return result, isNull, err } type builtinSubStringAndStringSig struct { @@ -6361,8 +6365,8 @@ func (b *builtinSubStringAndStringSig) evalString(row chunk.Row) (result string, } return result, false, nil } - result, err = strDatetimeSubDuration(sc, arg0, arg1) - return result, err != nil, err + result, isNull, err = strDatetimeSubDuration(sc, arg0, arg1) + return result, isNull, err } type builtinSubTimeStringNullSig struct { diff --git a/expression/builtin_time_test.go b/expression/builtin_time_test.go index abc6406d4867a..e09d342dc357c 100644 --- a/expression/builtin_time_test.go +++ b/expression/builtin_time_test.go @@ -915,6 +915,8 @@ func (s *testEvaluatorSuite) TestAddTimeSig(c *C) { {"2017-12-31 23:59:59", "1", "2018-01-01 00:00:00"}, {"2007-12-31 23:59:59.999999", "2 1:1:1.000002", "2008-01-03 01:01:01.000001"}, {"2018-08-16 20:21:01", "00:00:00.000001", "2018-08-16 20:21:01.000001"}, + {"1", "xxcvadfgasd", ""}, + {"xxcvadfgasd", "1", ""}, } fc := funcs[ast.AddTime] for _, t := range tbl { @@ -992,7 +994,10 @@ func (s *testEvaluatorSuite) TestAddTimeSig(c *C) { {types.CurrentTime(mysql.TypeTimestamp), "-32073", types.ErrTruncatedWrongVal}, {types.CurrentTime(mysql.TypeDate), "-32073", types.ErrTruncatedWrongVal}, {types.CurrentTime(mysql.TypeDatetime), "-32073", types.ErrTruncatedWrongVal}, + {"1", "xxcvadfgasd", types.ErrTruncatedWrongVal}, + {"xxcvadfgasd", "1", types.ErrTruncatedWrongVal}, } + beforeWarnCnt := int(s.ctx.GetSessionVars().StmtCtx.WarningCount()) for i, t := range tblWarning { tmpInput := types.NewDatum(t.Input) tmpInputDuration := types.NewDatum(t.InputDuration) @@ -1004,7 +1009,7 @@ func (s *testEvaluatorSuite) TestAddTimeSig(c *C) { 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(len(warnings), Equals, i+1+beforeWarnCnt) c.Assert(terror.ErrorEqual(t.warning, warnings[i].Err), IsTrue, Commentf("err %v", warnings[i].Err)) } } @@ -1019,6 +1024,8 @@ func (s *testEvaluatorSuite) TestSubTimeSig(c *C) { {"110:00:00", "1 02:00:00", "84:00:00"}, {"2017-01-01 01:01:01.11", "01:01:01.11111", "2016-12-31 23:59:59.998890"}, {"2007-12-31 23:59:59.999999", "1 1:1:1.000002", "2007-12-30 22:58:58.999997"}, + {"1", "xxcvadfgasd", ""}, + {"xxcvadfgasd", "1", ""}, } fc := funcs[ast.SubTime] for _, t := range tbl { @@ -1084,7 +1091,10 @@ func (s *testEvaluatorSuite) TestSubTimeSig(c *C) { {types.CurrentTime(mysql.TypeTimestamp), "-32073", types.ErrTruncatedWrongVal}, {types.CurrentTime(mysql.TypeDate), "-32073", types.ErrTruncatedWrongVal}, {types.CurrentTime(mysql.TypeDatetime), "-32073", types.ErrTruncatedWrongVal}, + {"1", "xxcvadfgasd", types.ErrTruncatedWrongVal}, + {"xxcvadfgasd", "1", types.ErrTruncatedWrongVal}, } + beforeWarnCnt := int(s.ctx.GetSessionVars().StmtCtx.WarningCount()) for i, t := range tblWarning { tmpInput := types.NewDatum(t.Input) tmpInputDuration := types.NewDatum(t.InputDuration) @@ -1096,7 +1106,7 @@ func (s *testEvaluatorSuite) TestSubTimeSig(c *C) { 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(len(warnings), Equals, i+1+beforeWarnCnt) c.Assert(terror.ErrorEqual(t.warning, warnings[i].Err), IsTrue, Commentf("err %v", warnings[i].Err)) } } diff --git a/expression/builtin_time_vec_generated.go b/expression/builtin_time_vec_generated.go index f9f5292597818..d440aaa1a01ad 100644 --- a/expression/builtin_time_vec_generated.go +++ b/expression/builtin_time_vec_generated.go @@ -318,6 +318,7 @@ func (b *builtinAddStringAndDurationSig) vecEvalString(input *chunk.Chunk, resul fsp1 := int8(b.args[1].GetType().Decimal) arg1Duration := types.Duration{Duration: arg1, Fsp: fsp1} var output string + var isNull bool if isDuration(arg0) { output, err = strDurationAddDuration(sc, arg0, arg1Duration) @@ -332,11 +333,16 @@ func (b *builtinAddStringAndDurationSig) vecEvalString(input *chunk.Chunk, resul } } else { - output, err = strDatetimeAddDuration(sc, arg0, arg1Duration) + output, isNull, err = strDatetimeAddDuration(sc, arg0, arg1Duration) if err != nil { return err } + if isNull { + sc.AppendWarning(err) + result.AppendNull() // fixed: false + continue + } } // commit result @@ -410,6 +416,7 @@ func (b *builtinAddStringAndStringSig) vecEvalString(input *chunk.Chunk, result } var output string + var isNull bool if isDuration(arg0) { output, err = strDurationAddDuration(sc, arg0, arg1Duration) @@ -424,11 +431,16 @@ func (b *builtinAddStringAndStringSig) vecEvalString(input *chunk.Chunk, result } } else { - output, err = strDatetimeAddDuration(sc, arg0, arg1Duration) + output, isNull, err = strDatetimeAddDuration(sc, arg0, arg1Duration) if err != nil { return err } + if isNull { + sc.AppendWarning(err) + result.AppendNull() // fixed: false + continue + } } // commit result @@ -930,6 +942,7 @@ func (b *builtinSubStringAndDurationSig) vecEvalString(input *chunk.Chunk, resul fsp1 := int8(b.args[1].GetType().Decimal) arg1Duration := types.Duration{Duration: arg1, Fsp: fsp1} var output string + var isNull bool if isDuration(arg0) { output, err = strDurationSubDuration(sc, arg0, arg1Duration) @@ -944,11 +957,16 @@ func (b *builtinSubStringAndDurationSig) vecEvalString(input *chunk.Chunk, resul } } else { - output, err = strDatetimeSubDuration(sc, arg0, arg1Duration) + output, isNull, err = strDatetimeSubDuration(sc, arg0, arg1Duration) if err != nil { return err } + if isNull { + sc.AppendWarning(err) + result.AppendNull() // fixed: false + continue + } } // commit result @@ -1022,6 +1040,7 @@ func (b *builtinSubStringAndStringSig) vecEvalString(input *chunk.Chunk, result } var output string + var isNull bool if isDuration(arg0) { output, err = strDurationSubDuration(sc, arg0, arg1Duration) @@ -1036,11 +1055,16 @@ func (b *builtinSubStringAndStringSig) vecEvalString(input *chunk.Chunk, result } } else { - output, err = strDatetimeSubDuration(sc, arg0, arg1Duration) + output, isNull, err = strDatetimeSubDuration(sc, arg0, arg1Duration) if err != nil { return err } + if isNull { + sc.AppendWarning(err) + result.AppendNull() // fixed: false + continue + } } // commit result diff --git a/expression/generator/time_vec.go b/expression/generator/time_vec.go index 7587a3a21f25f..b6c13dc1af760 100644 --- a/expression/generator/time_vec.go +++ b/expression/generator/time_vec.go @@ -182,7 +182,7 @@ func (b *{{.SigName}}) vecEval{{ .Output.TypeName }}(input *chunk.Chunk, result if err != nil { return err } - + {{ else if or (eq .SigName "builtinAddDatetimeAndStringSig") (eq .SigName "builtinSubDatetimeAndStringSig") }} {{ if eq $.FuncName "AddTime" }} {{ template "ConvertStringToDuration" . }} @@ -242,6 +242,7 @@ func (b *{{.SigName}}) vecEval{{ .Output.TypeName }}(input *chunk.Chunk, result fsp1 := int8(b.args[1].GetType().Decimal) arg1Duration := types.Duration{Duration: arg1, Fsp: fsp1} var output string + var isNull bool if isDuration(arg0) { {{ if eq $.FuncName "AddTime" }} output, err = strDurationAddDuration(sc, arg0, arg1Duration) @@ -258,17 +259,23 @@ func (b *{{.SigName}}) vecEval{{ .Output.TypeName }}(input *chunk.Chunk, result } } else { {{ if eq $.FuncName "AddTime" }} - output, err = strDatetimeAddDuration(sc, arg0, arg1Duration) + output, isNull, err = strDatetimeAddDuration(sc, arg0, arg1Duration) {{ else }} - output, err = strDatetimeSubDuration(sc, arg0, arg1Duration) + output, isNull, err = strDatetimeSubDuration(sc, arg0, arg1Duration) {{ end }} if err != nil { return err } + if isNull { + sc.AppendWarning(err) + {{ template "SetNull" . }} + continue + } } {{ else if or (eq .SigName "builtinAddStringAndStringSig") (eq .SigName "builtinSubStringAndStringSig") }} {{ template "ConvertStringToDuration" . }} var output string + var isNull bool if isDuration(arg0) { {{ if eq $.FuncName "AddTime" }} output, err = strDurationAddDuration(sc, arg0, arg1Duration) @@ -285,13 +292,18 @@ func (b *{{.SigName}}) vecEval{{ .Output.TypeName }}(input *chunk.Chunk, result } } else { {{ if eq $.FuncName "AddTime" }} - output, err = strDatetimeAddDuration(sc, arg0, arg1Duration) + output, isNull, err = strDatetimeAddDuration(sc, arg0, arg1Duration) {{ else }} - output, err = strDatetimeSubDuration(sc, arg0, arg1Duration) + output, isNull, err = strDatetimeSubDuration(sc, arg0, arg1Duration) {{ end }} if err != nil { return err } + if isNull { + sc.AppendWarning(err) + {{ template "SetNull" . }} + continue + } } {{ else if or (eq .SigName "builtinAddDateAndDurationSig") (eq .SigName "builtinSubDateAndDurationSig") }} fsp0 := int8(b.args[0].GetType().Decimal)