Skip to content

Commit

Permalink
rowcodec: fix lose decimal precision during decode new row format to …
Browse files Browse the repository at this point in the history
…datum (pingcap#14631)
  • Loading branch information
lysu authored and hsqlu committed Feb 7, 2020
1 parent 2fa041c commit 27c6b0f
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 4 deletions.
7 changes: 7 additions & 0 deletions executor/insert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
14 changes: 12 additions & 2 deletions util/rowcodec/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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
Expand Down
16 changes: 14 additions & 2 deletions util/rowcodec/rowcodec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down Expand Up @@ -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
}
}
)

0 comments on commit 27c6b0f

Please sign in to comment.