diff --git a/executor/insert_test.go b/executor/insert_test.go index b2c29c195b298..1af7a0d89fee4 100644 --- a/executor/insert_test.go +++ b/executor/insert_test.go @@ -189,6 +189,13 @@ func (s *testSuite8) TestInsertOnDuplicateKey(c *C) { tk.MustExec(`insert into t1 values(4,14),(5,15),(6,16),(7,17),(8,18) on duplicate key update b=b+10`) c.Assert(tk.Se.AffectedRows(), Equals, uint64(7)) tk.CheckLastMessage("Records: 5 Duplicates: 2 Warnings: 0") + + // reproduce insert on duplicate key update bug under new row format. + tk.MustExec(`drop table if exists t1`) + tk.MustExec(`create table t1(c1 decimal(6,4), primary key(c1))`) + tk.MustExec(`insert into t1 set c1 = 0.1`) + tk.MustExec(`insert into t1 set c1 = 0.1 on duplicate key update c1 = 1`) + tk.MustQuery(`select * from t1 use index(primary)`).Check(testkit.Rows(`1.0000`)) } func (s *testSuite3) TestUpdateDuplicateKey(c *C) { diff --git a/util/rowcodec/decoder.go b/util/rowcodec/decoder.go index 08f8baab48277..5ef5ca3256a73 100644 --- a/util/rowcodec/decoder.go +++ b/util/rowcodec/decoder.go @@ -133,11 +133,13 @@ func (decoder *DatumMapDecoder) decodeColDatum(col *ColInfo, colData []byte) (ty mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob: d.SetBytes(colData) case mysql.TypeNewDecimal: - _, dec, _, _, err := codec.DecodeDecimal(colData) + _, dec, precision, frac, err := codec.DecodeDecimal(colData) if err != nil { return d, err } d.SetMysqlDecimal(dec) + d.SetLength(precision) + d.SetFrac(frac) case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp: var t types.Time t.SetType(uint8(col.Tp)) @@ -268,10 +270,18 @@ func (decoder *ChunkDecoder) decodeColToChunk(colIdx int, col *ColInfo, colData mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob: chk.AppendBytes(colIdx, colData) case mysql.TypeNewDecimal: - _, dec, _, _, err := codec.DecodeDecimal(colData) + _, dec, _, frac, err := codec.DecodeDecimal(colData) if err != nil { return err } + if col.Decimal != types.UnspecifiedLength && frac > col.Decimal { + to := new(types.MyDecimal) + err := dec.Round(to, col.Decimal, types.ModeHalfEven) + if err != nil { + return errors.Trace(err) + } + dec = to + } chk.AppendMyDecimal(colIdx, dec) case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp: var t types.Time diff --git a/util/rowcodec/rowcodec_test.go b/util/rowcodec/rowcodec_test.go index 86f253769239b..336ff36264a27 100644 --- a/util/rowcodec/rowcodec_test.go +++ b/util/rowcodec/rowcodec_test.go @@ -363,8 +363,8 @@ func (s *testSuite) TestTypesNewRowCodec(c *C) { { 8, types.NewFieldType(mysql.TypeNewDecimal), - types.NewDecimalDatum(types.NewDecFromStringForTest("1.99")), - types.NewDecimalDatum(types.NewDecFromStringForTest("1.99")), + withFrac(4)(withLen(6)(types.NewDecimalDatum(types.NewDecFromStringForTest("11.9900")))), + withFrac(4)(withLen(6)(types.NewDecimalDatum(types.NewDecFromStringForTest("11.9900")))), nil, false, }, @@ -775,4 +775,16 @@ var ( getDatumPoint = func(d types.Datum) *types.Datum { return &d } + withFrac = func(f int) func(d types.Datum) types.Datum { + return func(d types.Datum) types.Datum { + d.SetFrac(f) + return d + } + } + withLen = func(len int) func(d types.Datum) types.Datum { + return func(d types.Datum) types.Datum { + d.SetLength(len) + return d + } + } )