From 92d583cc634688ae0a8e6a2547c70a423e499a14 Mon Sep 17 00:00:00 2001 From: gaoxingliang Date: Fri, 30 Aug 2019 15:36:17 +0800 Subject: [PATCH 1/5] types/data: the bit operation didn't parse correctly --- executor/insert_test.go | 19 +++++++++++++++++++ types/convert.go | 4 ++-- types/datum.go | 9 +++++---- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/executor/insert_test.go b/executor/insert_test.go index 1ad3ab5dae696..ed818057477f6 100644 --- a/executor/insert_test.go +++ b/executor/insert_test.go @@ -15,6 +15,7 @@ package executor_test import ( "fmt" + "github.com/pingcap/tidb/types" . "github.com/pingcap/check" "github.com/pingcap/parser/terror" @@ -573,3 +574,21 @@ func (s *testSuite3) TestPartitionInsertOnDuplicate(c *C) { tk.MustExec("insert into t3 values (1,2,3,4,5),(6,2,3,4,6) on duplicate key update e = e + values(e)") tk.MustQuery("select * from t3").Check(testkit.Rows("1 2 3 4 16")) } + +func (s *testSuite3) TestBit(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec(`use test`) + tk.MustExec(`create table t1 (a bit(3))`) + _, err := tk.Exec("insert into t1 values(-1)") + c.Assert(types.ErrDataTooLong.Equal(err), IsTrue) + c.Assert(err.Error(), Matches, ".*Data too long for column 't1' at.*") + _, err = tk.Exec("insert into t1 values(9)") + c.Assert(err.Error(), Matches, ".*Data too long for column 't1' at.*") + + tk.MustExec(`create table t64 (a bit(64))`) + tk.MustExec("insert into t64 values(-1)") + tk.MustExec("insert into t64 values(18446744073709551615)") // 2^64 - 1 + _, err = tk.Exec("insert into t64 values(18446744073709551616)") // z^64 + c.Assert(err.Error(), Matches, ".* Out of range value for column 'a' at.*") + +} diff --git a/types/convert.go b/types/convert.go index 2dffeb6a44a2d..6f6b7f10024f5 100644 --- a/types/convert.go +++ b/types/convert.go @@ -137,8 +137,8 @@ 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.ShouldClipToZero() && val < 0 { +func ConvertIntToUint(sc *stmtctx.StatementContext, val int64, upperBound uint64, tp byte, unsignedFlag bool) (uint64, error) { + if sc.ShouldClipToZero() && val < 0 && !unsignedFlag { return 0, overflow(val, tp) } diff --git a/types/datum.go b/types/datum.go index 0d2053f06e954..9b8582007a349 100644 --- a/types/datum.go +++ b/types/datum.go @@ -877,7 +877,7 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( ) switch d.k { case KindInt64: - val, err = ConvertIntToUint(sc, d.GetInt64(), upperBound, tp) + val, err = ConvertIntToUint(sc, d.GetInt64(), upperBound, tp, mysql.HasUnsignedFlag(target.Flag)) case KindUint64: val, err = ConvertUintToUint(d.GetUint64(), upperBound, tp) case KindFloat32, KindFloat64: @@ -899,7 +899,7 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( if err == nil { err = err1 } - val, err1 = ConvertIntToUint(sc, ival, upperBound, tp) + val, err1 = ConvertIntToUint(sc, ival, upperBound, tp, mysql.HasUnsignedFlag(target.Flag)) if err == nil { err = err1 } @@ -908,7 +908,7 @@ 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(sc, ival, upperBound, tp) + val, err = ConvertIntToUint(sc, ival, upperBound, tp, mysql.HasUnsignedFlag(target.Flag)) } case KindMysqlDecimal: val, err = ConvertDecimalToUint(sc, d.GetMysqlDecimal(), upperBound, tp) @@ -1220,7 +1220,8 @@ func (d *Datum) convertToMysqlBit(sc *stmtctx.StatementContext, target *FieldTyp uintValue, err = uintDatum.GetUint64(), err1 } if target.Flen < 64 && uintValue >= 1<<(uint64(target.Flen)) { - return Datum{}, errors.Trace(ErrOverflow.GenWithStackByArgs("BIT", fmt.Sprintf("(%d)", target.Flen))) + err = ErrDataTooLong.GenWithStack("Data Too Long, field len %d", target.Flen) + return Datum{}, errors.Trace(err) } byteSize := (target.Flen + 7) >> 3 ret.SetMysqlBit(NewBinaryLiteralFromUint(uintValue, byteSize)) From 5bd621e27799708d6a02124889b3cf08886c0563 Mon Sep 17 00:00:00 2001 From: gaoxingliang Date: Fri, 30 Aug 2019 16:04:54 +0800 Subject: [PATCH 2/5] types/data: the bit operation didn't parse correctly (#11895) --- executor/insert_test.go | 6 +++--- types/convert.go | 4 ++-- types/datum.go | 11 ++++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/executor/insert_test.go b/executor/insert_test.go index ed818057477f6..57f4e28e3b288 100644 --- a/executor/insert_test.go +++ b/executor/insert_test.go @@ -581,14 +581,14 @@ func (s *testSuite3) TestBit(c *C) { tk.MustExec(`create table t1 (a bit(3))`) _, err := tk.Exec("insert into t1 values(-1)") c.Assert(types.ErrDataTooLong.Equal(err), IsTrue) - c.Assert(err.Error(), Matches, ".*Data too long for column 't1' at.*") + c.Assert(err.Error(), Matches, ".*Data too long for column 'a' at.*") _, err = tk.Exec("insert into t1 values(9)") - c.Assert(err.Error(), Matches, ".*Data too long for column 't1' at.*") + c.Assert(err.Error(), Matches, ".*Data too long for column 'a' at.*") tk.MustExec(`create table t64 (a bit(64))`) tk.MustExec("insert into t64 values(-1)") tk.MustExec("insert into t64 values(18446744073709551615)") // 2^64 - 1 _, err = tk.Exec("insert into t64 values(18446744073709551616)") // z^64 - c.Assert(err.Error(), Matches, ".* Out of range value for column 'a' at.*") + c.Assert(err.Error(), Matches, ".*Out of range value for column 'a' at.*") } diff --git a/types/convert.go b/types/convert.go index 6f6b7f10024f5..2dffeb6a44a2d 100644 --- a/types/convert.go +++ b/types/convert.go @@ -137,8 +137,8 @@ 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, unsignedFlag bool) (uint64, error) { - if sc.ShouldClipToZero() && val < 0 && !unsignedFlag { +func ConvertIntToUint(sc *stmtctx.StatementContext, val int64, upperBound uint64, tp byte) (uint64, error) { + if sc.ShouldClipToZero() && val < 0 { return 0, overflow(val, tp) } diff --git a/types/datum.go b/types/datum.go index 9b8582007a349..c614a8908b69d 100644 --- a/types/datum.go +++ b/types/datum.go @@ -877,7 +877,7 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( ) switch d.k { case KindInt64: - val, err = ConvertIntToUint(sc, d.GetInt64(), upperBound, tp, mysql.HasUnsignedFlag(target.Flag)) + val, err = ConvertIntToUint(sc, d.GetInt64(), upperBound, tp) case KindUint64: val, err = ConvertUintToUint(d.GetUint64(), upperBound, tp) case KindFloat32, KindFloat64: @@ -899,7 +899,7 @@ func (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) ( if err == nil { err = err1 } - val, err1 = ConvertIntToUint(sc, ival, upperBound, tp, mysql.HasUnsignedFlag(target.Flag)) + val, err1 = ConvertIntToUint(sc, ival, upperBound, tp) if err == nil { err = err1 } @@ -908,7 +908,7 @@ 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(sc, ival, upperBound, tp, mysql.HasUnsignedFlag(target.Flag)) + val, err = ConvertIntToUint(sc, ival, upperBound, tp) } case KindMysqlDecimal: val, err = ConvertDecimalToUint(sc, d.GetMysqlDecimal(), upperBound, tp) @@ -1215,6 +1215,11 @@ func (d *Datum) convertToMysqlBit(sc *stmtctx.StatementContext, target *FieldTyp switch d.k { case KindString, KindBytes: uintValue, err = BinaryLiteral(d.b).ToInt(sc) + case KindInt64: + // if input kind is int64 (signed), when trans to bit, we need to treat it as unsigned + d.k = KindUint64 + uintDatum, err1 := d.convertToUint(sc, target) + uintValue, err = uintDatum.GetUint64(), err1 default: uintDatum, err1 := d.convertToUint(sc, target) uintValue, err = uintDatum.GetUint64(), err1 From a68a052f166f84a7b54018fbd602a252b8923cfc Mon Sep 17 00:00:00 2001 From: gaoxingliang Date: Fri, 30 Aug 2019 16:10:59 +0800 Subject: [PATCH 3/5] types/data: the bit operation didn't parse correctly (#11895) --- types/datum.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/types/datum.go b/types/datum.go index c614a8908b69d..2cf482f565d9c 100644 --- a/types/datum.go +++ b/types/datum.go @@ -1225,8 +1225,7 @@ func (d *Datum) convertToMysqlBit(sc *stmtctx.StatementContext, target *FieldTyp uintValue, err = uintDatum.GetUint64(), err1 } if target.Flen < 64 && uintValue >= 1<<(uint64(target.Flen)) { - err = ErrDataTooLong.GenWithStack("Data Too Long, field len %d", target.Flen) - return Datum{}, errors.Trace(err) + return Datum{}, errors.Trace(ErrDataTooLong.GenWithStack("Data Too Long, field len %d", target.Flen)) } byteSize := (target.Flen + 7) >> 3 ret.SetMysqlBit(NewBinaryLiteralFromUint(uintValue, byteSize)) From cbf2e25e8c10d60292589e049d5462fd68aa8f64 Mon Sep 17 00:00:00 2001 From: gaoxingliang Date: Tue, 10 Sep 2019 14:51:51 +0800 Subject: [PATCH 4/5] types/data: the bit operation didn't parse correctly (#11895) --- types/datum.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/types/datum.go b/types/datum.go index 2cf482f565d9c..7118531652c40 100644 --- a/types/datum.go +++ b/types/datum.go @@ -1218,8 +1218,7 @@ func (d *Datum) convertToMysqlBit(sc *stmtctx.StatementContext, target *FieldTyp case KindInt64: // if input kind is int64 (signed), when trans to bit, we need to treat it as unsigned d.k = KindUint64 - uintDatum, err1 := d.convertToUint(sc, target) - uintValue, err = uintDatum.GetUint64(), err1 + fallthrough default: uintDatum, err1 := d.convertToUint(sc, target) uintValue, err = uintDatum.GetUint64(), err1 From e68dc53bb787970ef98eac12fc534531af057ebc Mon Sep 17 00:00:00 2001 From: gaoxingliang Date: Tue, 10 Sep 2019 15:58:18 +0800 Subject: [PATCH 5/5] types/data: format --- executor/insert_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executor/insert_test.go b/executor/insert_test.go index 57f4e28e3b288..0ec561cb04a40 100644 --- a/executor/insert_test.go +++ b/executor/insert_test.go @@ -15,11 +15,11 @@ package executor_test import ( "fmt" - "github.com/pingcap/tidb/types" . "github.com/pingcap/check" "github.com/pingcap/parser/terror" "github.com/pingcap/tidb/table" + "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/testkit" )