diff --git a/expression/integration_test.go b/expression/integration_test.go index 528b63d73bc58..1d27e687aaf9b 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -238,6 +238,15 @@ func (s *testIntegrationSuite) TestConvertToBit(c *C) { tk.MustExec(`insert t1 value ('09-01-01')`) tk.MustExec(`insert t select a from t1`) tk.MustQuery("select a+0 from t").Check(testkit.Rows("20090101000000")) + + // For issue 20118 + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(a tinyint, b bit(63));") + tk.MustExec("insert ignore into t values(599999999, -1);") + tk.MustQuery("show warnings;").Check(testkit.Rows( + "Warning 1690 constant 599999999 overflows tinyint", + "Warning 1406 Data Too Long, field len 63")) + tk.MustQuery("select * from t;").Check(testkit.Rows("127 \u007f\xff\xff\xff\xff\xff\xff\xff")) } func (s *testIntegrationSuite) TestMathBuiltin(c *C) { diff --git a/types/datum.go b/types/datum.go index 341f20eaeef0f..17ae9cfbe8cfe 100644 --- a/types/datum.go +++ b/types/datum.go @@ -1287,9 +1287,14 @@ func (d *Datum) convertToMysqlBit(sc *stmtctx.StatementContext, target *FieldTyp uintDatum, err1 := d.convertToUint(sc, target) uintValue, err = uintDatum.GetUint64(), err1 } - if target.Flen < 64 && uintValue >= 1<<(uint64(target.Flen)) { + // Avoid byte size panic, never goto this branch. + if target.Flen <= 0 || target.Flen >= 128 { return Datum{}, errors.Trace(ErrDataTooLong.GenWithStack("Data Too Long, field len %d", target.Flen)) } + if target.Flen < 64 && uintValue >= 1<<(uint64(target.Flen)) { + uintValue &= (1 << (uint64(target.Flen))) - 1 + err = ErrDataTooLong.GenWithStack("Data Too Long, field len %d", target.Flen) + } byteSize := (target.Flen + 7) >> 3 ret.SetMysqlBit(NewBinaryLiteralFromUint(uintValue, byteSize)) return ret, errors.Trace(err)