From 4cd33a21e5f124ba1156c57a1b5c236e51241cfa Mon Sep 17 00:00:00 2001 From: exialin Date: Mon, 3 Dec 2018 00:03:13 +0800 Subject: [PATCH 01/12] types: fix the lower bound when converting numbers less than 0 to unsigned integers --- executor/write_test.go | 10 ++++++++++ types/convert.go | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/executor/write_test.go b/executor/write_test.go index 70875e530b820..7b8d589c5fd6e 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -227,6 +227,16 @@ func (s *testSuite) TestInsert(c *C) { 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 6360 + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(a bigint unsigned);") + _, err = tk.Exec("insert into t value (-1);") + c.Assert(types.ErrWarnDataOutOfRange.Equal(err), IsTrue) + tk.MustExec("set sql_mode = '';") + tk.MustExec("insert into t value (-1);") + r = tk.MustQuery("select * from t;") + r.Check(testkit.Rows("0")) + // issue 6424 tk.MustExec("drop table if exists t") tk.MustExec("create table t(a time(6))") diff --git a/types/convert.go b/types/convert.go index 27df51b771997..705980139a6d2 100644 --- a/types/convert.go +++ b/types/convert.go @@ -107,6 +107,10 @@ func ConvertUintToInt(val uint64, upperBound int64, tp byte) (int64, error) { // ConvertIntToUint converts an int value to an uint value. func ConvertIntToUint(val int64, upperBound uint64, tp byte) (uint64, error) { + if val < 0 { + return 0, overflow(val, tp) + } + if uint64(val) > upperBound { return upperBound, overflow(val, tp) } From d234d3403f2d049a3ce683ce8dd00b6d39ba71bb Mon Sep 17 00:00:00 2001 From: exialin Date: Sat, 8 Dec 2018 14:55:47 +0800 Subject: [PATCH 02/12] fix test and consider other cases --- executor/executor.go | 4 ++++ executor/write_test.go | 9 ++++++++- expression/builtin_cast.go | 8 ++++---- sessionctx/stmtctx/stmtctx.go | 5 +++++ types/convert.go | 13 ++++++++----- types/datum.go | 24 ++++++++++++------------ types/helper.go | 14 ++++++++++++++ 7 files changed, 55 insertions(+), 22 deletions(-) diff --git a/executor/executor.go b/executor/executor.go index f561b7b4f8112..691e25aa29c9e 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -1259,6 +1259,7 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr sc.Priority = stmt.Priority + sc.ClipToZero = true case *ast.DeleteStmt: sc.InUpdateOrDeleteStmt = true sc.DupKeyAsWarning = stmt.IgnoreErr @@ -1275,12 +1276,15 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr sc.Priority = stmt.Priority + sc.ClipToZero = true case *ast.CreateTableStmt, *ast.AlterTableStmt: // Make sure the sql_mode is strict when checking column default value. case *ast.LoadDataStmt: sc.DupKeyAsWarning = true sc.BadNullAsWarning = true sc.TruncateAsWarning = !vars.StrictSQLMode + sc.ClipToZero = true + sc.InLoadDataStmt = true case *ast.SelectStmt: sc.InSelectStmt = true diff --git a/executor/write_test.go b/executor/write_test.go index 7b8d589c5fd6e..7ee37ef45c858 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -230,12 +230,19 @@ func (s *testSuite) TestInsert(c *C) { // issue 6360 tk.MustExec("drop table if exists t;") tk.MustExec("create table t(a bigint unsigned);") + tk.MustExec("set sql_mode = 'strict_all_tables';") _, err = tk.Exec("insert into t value (-1);") c.Assert(types.ErrWarnDataOutOfRange.Equal(err), IsTrue) tk.MustExec("set sql_mode = '';") tk.MustExec("insert into t value (-1);") + tk.MustExec("insert into t select -1;") + tk.MustExec("insert into t select cast(-1 as unsigned);;") + tk.MustExec("insert into t value (-1.111);") + tk.MustExec("insert into t value ('-1.111');") r = tk.MustQuery("select * from t;") - r.Check(testkit.Rows("0")) + r.Check(testkit.Rows("0", "0", "18446744073709551615", "0", "0")) + // remember to restore sql_mode so as not to influence other tests + tk.MustExec("set sql_mode = 'strict_all_tables';") // issue 6424 tk.MustExec("drop table if exists t") diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index 7b2b993952459..f7e4886c1d8be 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -464,7 +464,7 @@ func (b *builtinCastIntAsRealSig) evalReal(row chunk.Row) (res float64, isNull b res = 0 } else { var uVal uint64 - uVal, err = types.ConvertIntToUint(val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) + uVal, err = types.ConvertIntToUint(nil, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) res = float64(uVal) } return res, false, errors.Trace(err) @@ -491,7 +491,7 @@ func (b *builtinCastIntAsDecimalSig) evalDecimal(row chunk.Row) (res *types.MyDe res = &types.MyDecimal{} } else { var uVal uint64 - uVal, err = types.ConvertIntToUint(val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) + uVal, err = types.ConvertIntToUint(nil, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) if err != nil { return res, false, errors.Trace(err) } @@ -520,7 +520,7 @@ func (b *builtinCastIntAsStringSig) evalString(row chunk.Row) (res string, isNul res = strconv.FormatInt(val, 10) } else { var uVal uint64 - uVal, err = types.ConvertIntToUint(val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) + uVal, err = types.ConvertIntToUint(nil, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) if err != nil { return res, false, errors.Trace(err) } @@ -747,7 +747,7 @@ func (b *builtinCastRealAsIntSig) evalInt(row chunk.Row) (res int64, isNull bool res = 0 } else { var uintVal uint64 - uintVal, err = types.ConvertFloatToUint(val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeDouble) + uintVal, err = types.ConvertFloatToUint(nil, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeDouble) res = int64(uintVal) } return res, isNull, errors.Trace(err) diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index ef416642c2c62..1b4a1ae364306 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -49,6 +49,7 @@ type StatementContext struct { InInsertStmt bool InUpdateOrDeleteStmt bool InSelectStmt bool + InLoadDataStmt bool IgnoreTruncate bool IgnoreZeroInDate bool DupKeyAsWarning bool @@ -61,6 +62,10 @@ type StatementContext struct { PadCharToFullLength bool BatchCheck bool InNullRejectCheck bool + // As for insert, update, alter table and load data infile statements, when not in strict SQL mode, + // the value should be clipped to 0 for unsigned integer types. + // see https://dev.mysql.com/doc/refman/5.7/en/out-of-range-and-overflow.html + ClipToZero bool // mu struct holds variables that change during execution. mu struct { diff --git a/types/convert.go b/types/convert.go index 705980139a6d2..9bd2c4b48ec13 100644 --- a/types/convert.go +++ b/types/convert.go @@ -106,8 +106,8 @@ func ConvertUintToInt(val uint64, upperBound int64, tp byte) (int64, error) { } // ConvertIntToUint converts an int value to an uint value. -func ConvertIntToUint(val int64, upperBound uint64, tp byte) (uint64, error) { - if val < 0 { +func ConvertIntToUint(sc *stmtctx.StatementContext, val int64, upperBound uint64, tp byte) (uint64, error) { + if sc != nil && sc.ClipToZero && val < 0 { return 0, overflow(val, tp) } @@ -128,9 +128,12 @@ func ConvertUintToUint(val uint64, upperBound uint64, tp byte) (uint64, error) { } // ConvertFloatToUint converts a float value to an uint value. -func ConvertFloatToUint(fval float64, upperBound uint64, tp byte) (uint64, error) { +func ConvertFloatToUint(sc *stmtctx.StatementContext, fval float64, upperBound uint64, tp byte) (uint64, error) { val := RoundFloat(fval) if val < 0 { + if sc != nil && sc.ClipToZero && val < 0 { + return 0, overflow(val, tp) + } return uint64(int64(val)), overflow(val, tp) } @@ -404,7 +407,7 @@ func ConvertJSONToInt(sc *stmtctx.StatementContext, j json.BinaryJSON, unsigned return ConvertFloatToInt(f, lBound, uBound, mysql.TypeDouble) } bound := UnsignedUpperBound[mysql.TypeLonglong] - u, err := ConvertFloatToUint(f, bound, mysql.TypeDouble) + u, err := ConvertFloatToUint(sc, f, bound, mysql.TypeDouble) return int64(u), errors.Trace(err) case json.TypeCodeString: return StrToInt(sc, hack.String(j.GetString())) @@ -427,7 +430,7 @@ func ConvertJSONToFloat(sc *stmtctx.StatementContext, j json.BinaryJSON) (float6 case json.TypeCodeInt64: return float64(j.GetInt64()), nil case json.TypeCodeUint64: - u, err := ConvertIntToUint(j.GetInt64(), UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) + u, err := ConvertIntToUint(sc, j.GetInt64(), UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) return float64(u), errors.Trace(err) case json.TypeCodeFloat64: return j.GetFloat64(), nil diff --git a/types/datum.go b/types/datum.go index 86d94792f2762..cec492473e645 100644 --- a/types/datum.go +++ b/types/datum.go @@ -865,21 +865,21 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( ) switch d.k { case KindInt64: - val, err = ConvertIntToUint(d.GetInt64(), upperBound, tp) + val, err = ConvertIntToUint(sc, d.GetInt64(), upperBound, tp) case KindUint64: val, err = ConvertUintToUint(d.GetUint64(), upperBound, tp) case KindFloat32, KindFloat64: - val, err = ConvertFloatToUint(d.GetFloat64(), upperBound, tp) + val, err = ConvertFloatToUint(sc, d.GetFloat64(), upperBound, tp) case KindString, KindBytes: - val, err = StrToUint(sc, d.GetString()) - if err != nil { - return ret, errors.Trace(err) + ival, err1 := StrToUint(sc, d.GetString()) + if err1 != nil && !strToUintIgnoreError(sc) { + return ret, errors.Trace(err1) } - val, err = ConvertUintToUint(val, upperBound, tp) + val, err = ConvertUintToUint(ival, upperBound, tp) if err != nil { return ret, errors.Trace(err) } - ret.SetUint64(val) + err = err1 case KindMysqlTime: dec := d.GetMysqlTime().ToNumber() err = dec.Round(dec, 0, ModeHalfEven) @@ -887,7 +887,7 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( if err == nil { err = err1 } - val, err1 = ConvertIntToUint(ival, upperBound, tp) + val, err1 = ConvertIntToUint(sc, ival, upperBound, tp) if err == nil { err = err1 } @@ -896,18 +896,18 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( err = dec.Round(dec, 0, ModeHalfEven) ival, err1 := dec.ToInt() if err1 == nil { - val, err = ConvertIntToUint(ival, upperBound, tp) + val, err = ConvertIntToUint(sc, ival, upperBound, tp) } case KindMysqlDecimal: fval, err1 := d.GetMysqlDecimal().ToFloat64() - val, err = ConvertFloatToUint(fval, upperBound, tp) + val, err = ConvertFloatToUint(sc, fval, upperBound, tp) if err == nil { err = err1 } case KindMysqlEnum: - val, err = ConvertFloatToUint(d.GetMysqlEnum().ToNumber(), upperBound, tp) + val, err = ConvertFloatToUint(sc, d.GetMysqlEnum().ToNumber(), upperBound, tp) case KindMysqlSet: - val, err = ConvertFloatToUint(d.GetMysqlSet().ToNumber(), upperBound, tp) + val, err = ConvertFloatToUint(sc, d.GetMysqlSet().ToNumber(), upperBound, tp) case KindBinaryLiteral, KindMysqlBit: val, err = d.GetBinaryLiteral().ToInt(sc) case KindMysqlJSON: diff --git a/types/helper.go b/types/helper.go index f03dc1390c6de..b11b71f2a60e2 100644 --- a/types/helper.go +++ b/types/helper.go @@ -19,6 +19,7 @@ import ( "unicode" "github.com/pingcap/errors" + "github.com/pingcap/tidb/sessionctx/stmtctx" ) // RoundFloat rounds float val to the nearest integer value with float64 format, like MySQL Round function. @@ -193,3 +194,16 @@ func strToInt(str string) (int64, error) { } return int64(r), err } + +// strToUintIgnoreError indicates whether we should ignore the error when +// converting string to uint +func strToUintIgnoreError(sc *stmtctx.StatementContext) bool { + if sc.InInsertStmt && sc.TruncateAsWarning { + return true + } + if sc.InLoadDataStmt { + return true + } + + return false +} From 88054743214bd0b4f826827c0971a38c21b430fc Mon Sep 17 00:00:00 2001 From: exialin Date: Mon, 10 Dec 2018 22:58:10 +0800 Subject: [PATCH 03/12] address review --- executor/executor.go | 6 +++--- executor/write_test.go | 7 ++++++- sessionctx/stmtctx/stmtctx.go | 4 ---- types/convert.go | 4 ++-- types/helper.go | 9 +++++++++ 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/executor/executor.go b/executor/executor.go index 75c2df6ba3454..74c31e269cdeb 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -1259,7 +1259,7 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr sc.Priority = stmt.Priority - sc.ClipToZero = true + // sc.ClipToZero = true case *ast.DeleteStmt: sc.InUpdateOrDeleteStmt = true sc.DupKeyAsWarning = stmt.IgnoreErr @@ -1276,14 +1276,14 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr sc.Priority = stmt.Priority - sc.ClipToZero = true + // sc.ClipToZero = true case *ast.CreateTableStmt, *ast.AlterTableStmt: // Make sure the sql_mode is strict when checking column default value. case *ast.LoadDataStmt: sc.DupKeyAsWarning = true sc.BadNullAsWarning = true sc.TruncateAsWarning = !vars.StrictSQLMode - sc.ClipToZero = true + // sc.ClipToZero = true sc.InLoadDataStmt = true case *ast.SelectStmt: sc.InSelectStmt = true diff --git a/executor/write_test.go b/executor/write_test.go index 3c76153386663..ec321dd718b1d 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -236,10 +236,15 @@ func (s *testSuite) TestInsert(c *C) { c.Assert(types.ErrWarnDataOutOfRange.Equal(err), IsTrue) tk.MustExec("set sql_mode = '';") tk.MustExec("insert into t value (-1);") + // TODO: the following warning messages is not consistent with MySQL, fix them in the future PR + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1690 constant -1 overflows bigint")) tk.MustExec("insert into t select -1;") - tk.MustExec("insert into t select cast(-1 as unsigned);;") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1690 constant -1 overflows bigint")) + tk.MustExec("insert into t select cast(-1 as unsigned);") tk.MustExec("insert into t value (-1.111);") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1690 constant -1 overflows bigint")) tk.MustExec("insert into t value ('-1.111');") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1690 BIGINT UNSIGNED value is out of range in '-1'")) r = tk.MustQuery("select * from t;") r.Check(testkit.Rows("0", "0", "18446744073709551615", "0", "0")) // remember to restore sql_mode so as not to influence other tests diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 00df1e08ce1b6..39e82d7fb780b 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -62,10 +62,6 @@ type StatementContext struct { PadCharToFullLength bool BatchCheck bool InNullRejectCheck bool - // As for insert, update, alter table and load data infile statements, when not in strict SQL mode, - // the value should be clipped to 0 for unsigned integer types. - // see https://dev.mysql.com/doc/refman/5.7/en/out-of-range-and-overflow.html - ClipToZero bool // mu struct holds variables that change during execution. mu struct { diff --git a/types/convert.go b/types/convert.go index 9bd2c4b48ec13..5281c27f0bc29 100644 --- a/types/convert.go +++ b/types/convert.go @@ -107,7 +107,7 @@ func ConvertUintToInt(val uint64, upperBound int64, tp byte) (int64, error) { // ConvertIntToUint converts an int value to an uint value. func ConvertIntToUint(sc *stmtctx.StatementContext, val int64, upperBound uint64, tp byte) (uint64, error) { - if sc != nil && sc.ClipToZero && val < 0 { + if sc != nil && shouldClipToZero(sc) && val < 0 { return 0, overflow(val, tp) } @@ -131,7 +131,7 @@ func ConvertUintToUint(val uint64, upperBound uint64, tp byte) (uint64, error) { func ConvertFloatToUint(sc *stmtctx.StatementContext, fval float64, upperBound uint64, tp byte) (uint64, error) { val := RoundFloat(fval) if val < 0 { - if sc != nil && sc.ClipToZero && val < 0 { + if sc != nil && shouldClipToZero(sc) && val < 0 { return 0, overflow(val, tp) } return uint64(int64(val)), overflow(val, tp) diff --git a/types/helper.go b/types/helper.go index b11b71f2a60e2..bf774c50e64cb 100644 --- a/types/helper.go +++ b/types/helper.go @@ -195,6 +195,15 @@ func strToInt(str string) (int64, error) { return int64(r), err } +// shouldClipToZero indicates whether values less than 0 should be clipped to 0 for unsigned integer types. +// This is the case for insert, update, alter table and load data infile statements, when not in strict SQL mode. +// see https://dev.mysql.com/doc/refman/5.7/en/out-of-range-and-overflow.html +func shouldClipToZero(sc *stmtctx.StatementContext) bool { + // Currently altering column of integer to unsigned integer is not supported. + // If it is supported one day, that case should be added here. + return sc.InInsertStmt || sc.InUpdateOrDeleteStmt || sc.InLoadDataStmt +} + // strToUintIgnoreError indicates whether we should ignore the error when // converting string to uint func strToUintIgnoreError(sc *stmtctx.StatementContext) bool { From f002c795bb3eb92a1d388ece33ff34e411fcd8f1 Mon Sep 17 00:00:00 2001 From: exialin Date: Mon, 10 Dec 2018 23:14:30 +0800 Subject: [PATCH 04/12] remove commented lines --- executor/executor.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/executor/executor.go b/executor/executor.go index 74c31e269cdeb..838535ce76849 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -1259,7 +1259,6 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr sc.Priority = stmt.Priority - // sc.ClipToZero = true case *ast.DeleteStmt: sc.InUpdateOrDeleteStmt = true sc.DupKeyAsWarning = stmt.IgnoreErr @@ -1276,14 +1275,12 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr sc.Priority = stmt.Priority - // sc.ClipToZero = true case *ast.CreateTableStmt, *ast.AlterTableStmt: // Make sure the sql_mode is strict when checking column default value. case *ast.LoadDataStmt: sc.DupKeyAsWarning = true sc.BadNullAsWarning = true sc.TruncateAsWarning = !vars.StrictSQLMode - // sc.ClipToZero = true sc.InLoadDataStmt = true case *ast.SelectStmt: sc.InSelectStmt = true From 37fb967958aa82f7906e147001fdf702a458ec95 Mon Sep 17 00:00:00 2001 From: exialin Date: Sat, 5 Jan 2019 01:02:51 +0800 Subject: [PATCH 05/12] add test for load data --- executor/write_test.go | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/executor/write_test.go b/executor/write_test.go index 75622fdb809c1..7938bfdacfbed 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -240,12 +240,12 @@ func (s *testSuite2) TestInsert(c *C) { // issue 6360 tk.MustExec("drop table if exists t;") tk.MustExec("create table t(a bigint unsigned);") - tk.MustExec("set sql_mode = 'strict_all_tables';") + tk.MustExec(" set @orig_sql_mode = @@sql_mode; set @@sql_mode = 'strict_all_tables';") _, err = tk.Exec("insert into t value (-1);") c.Assert(types.ErrWarnDataOutOfRange.Equal(err), IsTrue) - tk.MustExec("set sql_mode = '';") + tk.MustExec("set @@sql_mode = '';") tk.MustExec("insert into t value (-1);") - // TODO: the following warning messages is not consistent with MySQL, fix them in the future PR + // TODO: the following warning messages are not consistent with MySQL, fix them in the future PRs tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1690 constant -1 overflows bigint")) tk.MustExec("insert into t select -1;") tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1690 constant -1 overflows bigint")) @@ -256,8 +256,7 @@ func (s *testSuite2) TestInsert(c *C) { tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1690 BIGINT UNSIGNED value is out of range in '-1'")) r = tk.MustQuery("select * from t;") r.Check(testkit.Rows("0", "0", "18446744073709551615", "0", "0")) - // remember to restore sql_mode so as not to influence other tests - tk.MustExec("set sql_mode = 'strict_all_tables';") + tk.MustExec("set @@sql_mode = @orig_sql_mode;") // issue 6424 tk.MustExec("drop table if exists t") @@ -1942,6 +1941,28 @@ func (s *testSuite2) TestLoadDataIgnoreLines(c *C) { checkCases(tests, ld, c, tk, ctx, selectSQL, deleteSQL) } +// related to issue 6360 +func (s *testSuite2) TestLoadDataOverflowBigintUnsigned(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test; drop table if exists load_data_test;") + tk.MustExec("CREATE TABLE load_data_test (a bigint unsigned);") + tk.MustExec("load data local infile '/tmp/nonexistence.csv' into table load_data_test") + ctx := tk.Se.(sessionctx.Context) + ld, ok := ctx.Value(executor.LoadDataVarKey).(*executor.LoadDataInfo) + c.Assert(ok, IsTrue) + defer ctx.SetValue(executor.LoadDataVarKey, nil) + c.Assert(ld, NotNil) + tests := []testCase{ + {nil, []byte("-1\n-18446744073709551615\n-18446744073709551616\n"), []string{"0", "0", "0"}, nil, "Records: 3 Deleted: 0 Skipped: 0 Warnings: 3"}, + // manual test can pass but here will fail + // {nil, []byte("-9223372036854775809\n"), []string{"0"}, nil, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 1"}, + // {nil, []byte("18446744073709551616\n"), []string{"18446744073709551615"}, nil, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 1"}, + } + deleteSQL := "delete from load_data_test" + selectSQL := "select * from load_data_test;" + checkCases(tests, ld, c, tk, ctx, selectSQL, deleteSQL) +} + func (s *testSuite2) TestBatchInsertDelete(c *C) { originLimit := atomic.LoadUint64(&kv.TxnEntryCountLimit) defer func() { From 4b5ebaa1dfe3bb1eef4e3b77c5fe65829b50b56d Mon Sep 17 00:00:00 2001 From: exialin Date: Sat, 5 Jan 2019 12:26:44 +0800 Subject: [PATCH 06/12] minor change --- sessionctx/stmtctx/stmtctx.go | 21 +++++++++++++++++++++ types/convert.go | 4 ++-- types/datum.go | 6 +++--- types/helper.go | 22 ---------------------- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 6a3080095d9d5..932294097a6e1 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -380,3 +380,24 @@ func (sc *StatementContext) GetExecDetails() execdetails.ExecDetails { sc.mu.Unlock() return details } + +// ShouldClipToZero indicates whether values less than 0 should be clipped to 0 for unsigned integer types. +// This is the case for `insert`, `update`, `alter table` and `load data infile` statements, when not in strict SQL mode. +// see https://dev.mysql.com/doc/refman/5.7/en/out-of-range-and-overflow.html +func (sc *StatementContext) ShouldClipToZero() bool { + // TODO: Currently altering column of integer to unsigned integer is not supported. + // If it is supported one day, that case should be added here. + return sc.InInsertStmt || sc.InUpdateOrDeleteStmt || sc.InLoadDataStmt +} + +// StrToUintIgnoreError indicates whether we should ignore the error when +// converting string to uint overflows +func (sc *StatementContext) StrToUintIgnoreError() bool { + if sc.InInsertStmt && sc.TruncateAsWarning { + return true + } + if sc.InLoadDataStmt { + return true + } + return false +} diff --git a/types/convert.go b/types/convert.go index 5281c27f0bc29..aa890d4453e45 100644 --- a/types/convert.go +++ b/types/convert.go @@ -107,7 +107,7 @@ func ConvertUintToInt(val uint64, upperBound int64, tp byte) (int64, error) { // ConvertIntToUint converts an int value to an uint value. func ConvertIntToUint(sc *stmtctx.StatementContext, val int64, upperBound uint64, tp byte) (uint64, error) { - if sc != nil && shouldClipToZero(sc) && val < 0 { + if sc != nil && sc.ShouldClipToZero() && val < 0 { return 0, overflow(val, tp) } @@ -131,7 +131,7 @@ func ConvertUintToUint(val uint64, upperBound uint64, tp byte) (uint64, error) { func ConvertFloatToUint(sc *stmtctx.StatementContext, fval float64, upperBound uint64, tp byte) (uint64, error) { val := RoundFloat(fval) if val < 0 { - if sc != nil && shouldClipToZero(sc) && val < 0 { + if sc != nil && sc.ShouldClipToZero() && val < 0 { return 0, overflow(val, tp) } return uint64(int64(val)), overflow(val, tp) diff --git a/types/datum.go b/types/datum.go index a5c61ba8f3763..33a7d4eaf645d 100644 --- a/types/datum.go +++ b/types/datum.go @@ -872,11 +872,11 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( case KindFloat32, KindFloat64: val, err = ConvertFloatToUint(sc, d.GetFloat64(), upperBound, tp) case KindString, KindBytes: - ival, err1 := StrToUint(sc, d.GetString()) - if err1 != nil && !strToUintIgnoreError(sc) { + uval, err1 := StrToUint(sc, d.GetString()) + if err1 != nil && !sc.StrToUintIgnoreError() { return ret, errors.Trace(err1) } - val, err = ConvertUintToUint(ival, upperBound, tp) + val, err = ConvertUintToUint(uval, upperBound, tp) if err != nil { return ret, errors.Trace(err) } diff --git a/types/helper.go b/types/helper.go index bf774c50e64cb..120ef45401df7 100644 --- a/types/helper.go +++ b/types/helper.go @@ -194,25 +194,3 @@ func strToInt(str string) (int64, error) { } return int64(r), err } - -// shouldClipToZero indicates whether values less than 0 should be clipped to 0 for unsigned integer types. -// This is the case for insert, update, alter table and load data infile statements, when not in strict SQL mode. -// see https://dev.mysql.com/doc/refman/5.7/en/out-of-range-and-overflow.html -func shouldClipToZero(sc *stmtctx.StatementContext) bool { - // Currently altering column of integer to unsigned integer is not supported. - // If it is supported one day, that case should be added here. - return sc.InInsertStmt || sc.InUpdateOrDeleteStmt || sc.InLoadDataStmt -} - -// strToUintIgnoreError indicates whether we should ignore the error when -// converting string to uint -func strToUintIgnoreError(sc *stmtctx.StatementContext) bool { - if sc.InInsertStmt && sc.TruncateAsWarning { - return true - } - if sc.InLoadDataStmt { - return true - } - - return false -} From 92d87dee5e33c77bbf2cae9d8272cd94ae84e647 Mon Sep 17 00:00:00 2001 From: exialin Date: Sat, 5 Jan 2019 12:34:50 +0800 Subject: [PATCH 07/12] fix --- types/helper.go | 1 - 1 file changed, 1 deletion(-) diff --git a/types/helper.go b/types/helper.go index 120ef45401df7..f03dc1390c6de 100644 --- a/types/helper.go +++ b/types/helper.go @@ -19,7 +19,6 @@ import ( "unicode" "github.com/pingcap/errors" - "github.com/pingcap/tidb/sessionctx/stmtctx" ) // RoundFloat rounds float val to the nearest integer value with float64 format, like MySQL Round function. From c94c9f394ad45f6b1e5463ef3bbe0bde9616217b Mon Sep 17 00:00:00 2001 From: exialin Date: Mon, 7 Jan 2019 21:11:16 +0800 Subject: [PATCH 08/12] fix --- executor/executor_test.go | 1 + executor/load_data.go | 2 +- executor/write_test.go | 4 +--- sessionctx/stmtctx/stmtctx.go | 6 +++--- types/convert.go | 2 +- types/datum.go | 2 +- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/executor/executor_test.go b/executor/executor_test.go index adc8b2b72db74..7bf748bc723fa 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -342,6 +342,7 @@ func checkCases(tests []testCase, ld *executor.LoadDataInfo, c.Assert(ctx.NewTxn(context.Background()), IsNil) ctx.GetSessionVars().StmtCtx.DupKeyAsWarning = true ctx.GetSessionVars().StmtCtx.BadNullAsWarning = true + ctx.GetSessionVars().StmtCtx.InLoadDataStmt = true data, reachLimit, err1 := ld.InsertData(tt.data1, tt.data2) c.Assert(err1, IsNil) c.Assert(reachLimit, IsFalse) diff --git a/executor/load_data.go b/executor/load_data.go index df81f8ccd2730..5d690470791e0 100644 --- a/executor/load_data.go +++ b/executor/load_data.go @@ -202,7 +202,7 @@ func (e *LoadDataInfo) getLine(prevData, curData []byte) ([]byte, []byte, bool) } // InsertData inserts data into specified table according to the specified format. -// If it has the rest of data isn't completed the processing, then is returns without completed data. +// If it has the rest of data isn't completed the processing, then it returns without completed data. // If the number of inserted rows reaches the batchRows, then the second return value is true. // If prevData isn't nil and curData is nil, there are no other data to deal with and the isEOF is true. func (e *LoadDataInfo) InsertData(prevData, curData []byte) ([]byte, bool, error) { diff --git a/executor/write_test.go b/executor/write_test.go index 7938bfdacfbed..2977eaf0bf61b 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -1954,9 +1954,7 @@ func (s *testSuite2) TestLoadDataOverflowBigintUnsigned(c *C) { c.Assert(ld, NotNil) tests := []testCase{ {nil, []byte("-1\n-18446744073709551615\n-18446744073709551616\n"), []string{"0", "0", "0"}, nil, "Records: 3 Deleted: 0 Skipped: 0 Warnings: 3"}, - // manual test can pass but here will fail - // {nil, []byte("-9223372036854775809\n"), []string{"0"}, nil, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 1"}, - // {nil, []byte("18446744073709551616\n"), []string{"18446744073709551615"}, nil, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 1"}, + {nil, []byte("-9223372036854775809\n18446744073709551616\n"), []string{"0", "18446744073709551615"}, nil, "Records: 2 Deleted: 0 Skipped: 0 Warnings: 2"}, } deleteSQL := "delete from load_data_test" selectSQL := "select * from load_data_test;" diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 932294097a6e1..5ccbc1366d456 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -390,9 +390,9 @@ func (sc *StatementContext) ShouldClipToZero() bool { return sc.InInsertStmt || sc.InUpdateOrDeleteStmt || sc.InLoadDataStmt } -// StrToUintIgnoreError indicates whether we should ignore the error when -// converting string to uint overflows -func (sc *StatementContext) StrToUintIgnoreError() bool { +// ShouldIgnoreError indicates whether we should ignore the error when type conversion overflows, +// so we can leave it for further processing like clipping values less than 0 to 0 for unsigned integer types. +func (sc *StatementContext) ShouldIgnoreError() bool { if sc.InInsertStmt && sc.TruncateAsWarning { return true } diff --git a/types/convert.go b/types/convert.go index aa890d4453e45..1660a3ff25de5 100644 --- a/types/convert.go +++ b/types/convert.go @@ -131,7 +131,7 @@ func ConvertUintToUint(val uint64, upperBound uint64, tp byte) (uint64, error) { func ConvertFloatToUint(sc *stmtctx.StatementContext, fval float64, upperBound uint64, tp byte) (uint64, error) { val := RoundFloat(fval) if val < 0 { - if sc != nil && sc.ShouldClipToZero() && val < 0 { + if sc != nil && sc.ShouldClipToZero() { return 0, overflow(val, tp) } return uint64(int64(val)), overflow(val, tp) diff --git a/types/datum.go b/types/datum.go index 33a7d4eaf645d..b836cd8edb069 100644 --- a/types/datum.go +++ b/types/datum.go @@ -873,7 +873,7 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( val, err = ConvertFloatToUint(sc, d.GetFloat64(), upperBound, tp) case KindString, KindBytes: uval, err1 := StrToUint(sc, d.GetString()) - if err1 != nil && !sc.StrToUintIgnoreError() { + if err1 != nil && !sc.ShouldIgnoreError() { return ret, errors.Trace(err1) } val, err = ConvertUintToUint(uval, upperBound, tp) From cb0695363ee7fda4c19467de20a07b1946328409 Mon Sep 17 00:00:00 2001 From: exialin Date: Mon, 7 Jan 2019 21:58:21 +0800 Subject: [PATCH 09/12] add sc --- expression/builtin_cast.go | 12 ++++++++---- types/convert.go | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index ff819df7a8521..65b4397fa6699 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -464,7 +464,8 @@ func (b *builtinCastIntAsRealSig) evalReal(row chunk.Row) (res float64, isNull b res = 0 } else { var uVal uint64 - uVal, err = types.ConvertIntToUint(nil, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) + sc := b.ctx.GetSessionVars().StmtCtx + uVal, err = types.ConvertIntToUint(sc, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) res = float64(uVal) } return res, false, err @@ -491,7 +492,8 @@ func (b *builtinCastIntAsDecimalSig) evalDecimal(row chunk.Row) (res *types.MyDe res = &types.MyDecimal{} } else { var uVal uint64 - uVal, err = types.ConvertIntToUint(nil, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) + sc := b.ctx.GetSessionVars().StmtCtx + uVal, err = types.ConvertIntToUint(sc, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) if err != nil { return res, false, err } @@ -520,7 +522,8 @@ func (b *builtinCastIntAsStringSig) evalString(row chunk.Row) (res string, isNul res = strconv.FormatInt(val, 10) } else { var uVal uint64 - uVal, err = types.ConvertIntToUint(nil, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) + sc := b.ctx.GetSessionVars().StmtCtx + uVal, err = types.ConvertIntToUint(sc, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeLonglong) if err != nil { return res, false, err } @@ -750,7 +753,8 @@ func (b *builtinCastRealAsIntSig) evalInt(row chunk.Row) (res int64, isNull bool res = 0 } else { var uintVal uint64 - uintVal, err = types.ConvertFloatToUint(nil, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeDouble) + sc := b.ctx.GetSessionVars().StmtCtx + uintVal, err = types.ConvertFloatToUint(sc, val, types.UnsignedUpperBound[mysql.TypeLonglong], mysql.TypeDouble) res = int64(uintVal) } return res, isNull, err diff --git a/types/convert.go b/types/convert.go index 1660a3ff25de5..87e3cd82e24a8 100644 --- a/types/convert.go +++ b/types/convert.go @@ -107,7 +107,7 @@ func ConvertUintToInt(val uint64, upperBound int64, tp byte) (int64, error) { // ConvertIntToUint converts an int value to an uint value. func ConvertIntToUint(sc *stmtctx.StatementContext, val int64, upperBound uint64, tp byte) (uint64, error) { - if sc != nil && sc.ShouldClipToZero() && val < 0 { + if sc.ShouldClipToZero() && val < 0 { return 0, overflow(val, tp) } @@ -131,7 +131,7 @@ func ConvertUintToUint(val uint64, upperBound uint64, tp byte) (uint64, error) { func ConvertFloatToUint(sc *stmtctx.StatementContext, fval float64, upperBound uint64, tp byte) (uint64, error) { val := RoundFloat(fval) if val < 0 { - if sc != nil && sc.ShouldClipToZero() { + if sc.ShouldClipToZero() { return 0, overflow(val, tp) } return uint64(int64(val)), overflow(val, tp) From 62c79e82a9942bee244e39ae4a6075a47ba2d347 Mon Sep 17 00:00:00 2001 From: exialin Date: Wed, 9 Jan 2019 16:04:50 +0800 Subject: [PATCH 10/12] fix ci --- executor/distsql.go | 2 +- executor/executor.go | 6 +++--- expression/errors.go | 4 ++-- sessionctx/stmtctx/stmtctx.go | 5 +++-- types/datum.go | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/executor/distsql.go b/executor/distsql.go index 8b2b6a21820e6..beed71598d4fc 100644 --- a/executor/distsql.go +++ b/executor/distsql.go @@ -123,7 +123,7 @@ func statementContextToFlags(sc *stmtctx.StatementContext) uint64 { var flags uint64 if sc.InInsertStmt { flags |= model.FlagInInsertStmt - } else if sc.InUpdateOrDeleteStmt { + } else if sc.InUpdateStmt || sc.InDeleteStmt { flags |= model.FlagInUpdateOrDeleteStmt } else if sc.InSelectStmt { flags |= model.FlagInSelectStmt diff --git a/executor/executor.go b/executor/executor.go index df04402fb463a..25a27a36b0ca4 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -1272,7 +1272,7 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { // pushing them down to TiKV as flags. switch stmt := s.(type) { case *ast.UpdateStmt: - sc.InUpdateOrDeleteStmt = true + sc.InUpdateStmt = true sc.DupKeyAsWarning = stmt.IgnoreErr sc.BadNullAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.TruncateAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr @@ -1280,7 +1280,7 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr sc.Priority = stmt.Priority case *ast.DeleteStmt: - sc.InUpdateOrDeleteStmt = true + sc.InDeleteStmt = true sc.DupKeyAsWarning = stmt.IgnoreErr sc.BadNullAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.TruncateAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr @@ -1342,7 +1342,7 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { sc.PrevLastInsertID = vars.StmtCtx.PrevLastInsertID } sc.PrevAffectedRows = 0 - if vars.StmtCtx.InUpdateOrDeleteStmt || vars.StmtCtx.InInsertStmt { + if vars.StmtCtx.InUpdateStmt || vars.StmtCtx.InDeleteStmt || vars.StmtCtx.InInsertStmt { sc.PrevAffectedRows = int64(vars.StmtCtx.AffectedRows()) } else if vars.StmtCtx.InSelectStmt { sc.PrevAffectedRows = -1 diff --git a/expression/errors.go b/expression/errors.go index 8a18acfa2ad5a..1ebc4ffdaba7b 100644 --- a/expression/errors.go +++ b/expression/errors.go @@ -72,7 +72,7 @@ func handleInvalidTimeError(ctx sessionctx.Context, err error) error { return err } sc := ctx.GetSessionVars().StmtCtx - if ctx.GetSessionVars().StrictSQLMode && (sc.InInsertStmt || sc.InUpdateOrDeleteStmt) { + if ctx.GetSessionVars().StrictSQLMode && (sc.InInsertStmt || sc.InUpdateStmt || sc.InDeleteStmt) { return err } sc.AppendWarning(err) @@ -82,7 +82,7 @@ func handleInvalidTimeError(ctx sessionctx.Context, err error) error { // handleDivisionByZeroError reports error or warning depend on the context. func handleDivisionByZeroError(ctx sessionctx.Context) error { sc := ctx.GetSessionVars().StmtCtx - if sc.InInsertStmt || sc.InUpdateOrDeleteStmt { + if sc.InInsertStmt || sc.InUpdateStmt || sc.InDeleteStmt { if !ctx.GetSessionVars().SQLMode.HasErrorForDivisionByZeroMode() { return nil } diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 5ccbc1366d456..4abb4c59dc3e9 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -47,7 +47,8 @@ type StatementContext struct { // If IsDDLJobInQueue is true, it means the DDL job is in the queue of storage, and it can be handled by the DDL worker. IsDDLJobInQueue bool InInsertStmt bool - InUpdateOrDeleteStmt bool + InUpdateStmt bool + InDeleteStmt bool InSelectStmt bool InLoadDataStmt bool IgnoreTruncate bool @@ -387,7 +388,7 @@ func (sc *StatementContext) GetExecDetails() execdetails.ExecDetails { func (sc *StatementContext) ShouldClipToZero() bool { // TODO: Currently altering column of integer to unsigned integer is not supported. // If it is supported one day, that case should be added here. - return sc.InInsertStmt || sc.InUpdateOrDeleteStmt || sc.InLoadDataStmt + return sc.InInsertStmt || sc.InUpdateStmt || sc.InLoadDataStmt } // ShouldIgnoreError indicates whether we should ignore the error when type conversion overflows, diff --git a/types/datum.go b/types/datum.go index b836cd8edb069..285083891b9e9 100644 --- a/types/datum.go +++ b/types/datum.go @@ -1138,7 +1138,7 @@ func ProduceDecWithSpecifiedTp(dec *MyDecimal, tp *FieldType, sc *stmtctx.Statem return nil, errors.Trace(err) } if !dec.IsZero() && frac > decimal && dec.Compare(&old) != 0 { - if sc.InInsertStmt || sc.InUpdateOrDeleteStmt { + if sc.InInsertStmt || sc.InUpdateStmt || sc.InDeleteStmt { // fix https://github.com/pingcap/tidb/issues/3895 // fix https://github.com/pingcap/tidb/issues/5532 sc.AppendWarning(ErrTruncated) From 60f2e3bcf9614b4a482c1c110f3389f4ace4e5f8 Mon Sep 17 00:00:00 2001 From: exialin Date: Wed, 9 Jan 2019 18:19:30 +0800 Subject: [PATCH 11/12] remove update --- sessionctx/stmtctx/stmtctx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 4abb4c59dc3e9..352f9f3af2923 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -388,7 +388,7 @@ func (sc *StatementContext) GetExecDetails() execdetails.ExecDetails { func (sc *StatementContext) ShouldClipToZero() bool { // TODO: Currently altering column of integer to unsigned integer is not supported. // If it is supported one day, that case should be added here. - return sc.InInsertStmt || sc.InUpdateStmt || sc.InLoadDataStmt + return sc.InInsertStmt || sc.InLoadDataStmt } // ShouldIgnoreError indicates whether we should ignore the error when type conversion overflows, From e62b14a1c820f1dbbdb5c442407386148399a157 Mon Sep 17 00:00:00 2001 From: exialin Date: Thu, 10 Jan 2019 15:05:10 +0800 Subject: [PATCH 12/12] rename function --- sessionctx/stmtctx/stmtctx.go | 9 +++------ types/datum.go | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 352f9f3af2923..87d856d089c41 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -391,13 +391,10 @@ func (sc *StatementContext) ShouldClipToZero() bool { return sc.InInsertStmt || sc.InLoadDataStmt } -// ShouldIgnoreError indicates whether we should ignore the error when type conversion overflows, +// ShouldIgnoreOverflowError indicates whether we should ignore the error when type conversion overflows, // so we can leave it for further processing like clipping values less than 0 to 0 for unsigned integer types. -func (sc *StatementContext) ShouldIgnoreError() bool { - if sc.InInsertStmt && sc.TruncateAsWarning { - return true - } - if sc.InLoadDataStmt { +func (sc *StatementContext) ShouldIgnoreOverflowError() bool { + if (sc.InInsertStmt && sc.TruncateAsWarning) || sc.InLoadDataStmt { return true } return false diff --git a/types/datum.go b/types/datum.go index 285083891b9e9..ed340e00aaf33 100644 --- a/types/datum.go +++ b/types/datum.go @@ -873,7 +873,7 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( val, err = ConvertFloatToUint(sc, d.GetFloat64(), upperBound, tp) case KindString, KindBytes: uval, err1 := StrToUint(sc, d.GetString()) - if err1 != nil && !sc.ShouldIgnoreError() { + if err1 != nil && ErrOverflow.Equal(err1) && !sc.ShouldIgnoreOverflowError() { return ret, errors.Trace(err1) } val, err = ConvertUintToUint(uval, upperBound, tp)