Skip to content

Commit

Permalink
expression: fix cast json to decimal bug. (#8030) (#8109)
Browse files Browse the repository at this point in the history
  • Loading branch information
crazycs520 authored and zz-jason committed Oct 31, 2018
1 parent 6999f64 commit 01c9d82
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 4 deletions.
15 changes: 15 additions & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,21 @@ func (s *testSuite) TestJSON(c *C) {
// check CAST AS JSON.
result = tk.MustQuery(`select CAST('3' AS JSON), CAST('{}' AS JSON), CAST(null AS JSON)`)
result.Check(testkit.Rows(`3 {} <nil>`))

// Check cast json to decimal.
tk.MustExec("drop table if exists test_json")
tk.MustExec("create table test_json ( a decimal(60,2) as (JSON_EXTRACT(b,'$.c')), b json );")
tk.MustExec(`insert into test_json (b) values
('{"c": "1267.1"}'),
('{"c": "1267.01"}'),
('{"c": "1267.1234"}'),
('{"c": "1267.3456"}'),
('{"c": "1234567890123456789012345678901234567890123456789012345"}'),
('{"c": "1234567890123456789012345678901234567890123456789012345.12345"}');`)

tk.MustQuery("select a from test_json;").Check(testkit.Rows("1267.10", "1267.01", "1267.12",
"1267.35", "1234567890123456789012345678901234567890123456789012345.00",
"1234567890123456789012345678901234567890123456789012345.12"))
}

func (s *testSuite) TestMultiUpdate(c *C) {
Expand Down
8 changes: 4 additions & 4 deletions expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1541,11 +1541,11 @@ func (b *builtinCastJSONAsDecimalSig) evalDecimal(row chunk.Row) (res *types.MyD
return res, isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
f64, err := types.ConvertJSONToFloat(sc, val)
if err == nil {
res = new(types.MyDecimal)
err = res.FromFloat64(f64)
res, err = types.ConvertJSONToDecimal(sc, val)
if err != nil {
return res, false, errors.Trace(err)
}
res, err = types.ProduceDecWithSpecifiedTp(res, b.tp, sc)
return res, false, errors.Trace(err)
}

Expand Down
42 changes: 42 additions & 0 deletions expression/builtin_cast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,48 @@ func (s *testEvaluatorSuite) TestCastFuncSig(c *C) {
c.Assert(iRes, Equals, int64(0))
}

func (s *testEvaluatorSuite) TestCastJSONAsDecimalSig(c *C) {
ctx, sc := s.ctx, s.ctx.GetSessionVars().StmtCtx
originIgnoreTruncate := sc.IgnoreTruncate
sc.IgnoreTruncate = true
defer func() {
sc.IgnoreTruncate = originIgnoreTruncate
}()

col := &Column{RetType: types.NewFieldType(mysql.TypeJSON), Index: 0}
decFunc := newBaseBuiltinCastFunc(newBaseBuiltinFunc(ctx, []Expression{col}), false)
decFunc.tp = types.NewFieldType(mysql.TypeNewDecimal)
decFunc.tp.Flen = 60
decFunc.tp.Decimal = 2
sig := &builtinCastJSONAsDecimalSig{decFunc}

var tests = []struct {
In string
Out *types.MyDecimal
}{
{`{}`, types.NewDecFromStringForTest("0")},
{`[]`, types.NewDecFromStringForTest("0")},
{`3`, types.NewDecFromStringForTest("3")},
{`-3`, types.NewDecFromStringForTest("-3")},
{`4.5`, types.NewDecFromStringForTest("4.5")},
{`"1234"`, types.NewDecFromStringForTest("1234")},
// test truncate
{`"1234.1234"`, types.NewDecFromStringForTest("1234.12")},
{`"1234.4567"`, types.NewDecFromStringForTest("1234.46")},
// test big decimal
{`"1234567890123456789012345678901234567890123456789012345"`, types.NewDecFromStringForTest("1234567890123456789012345678901234567890123456789012345")},
}
for _, tt := range tests {
j, err := json.ParseBinaryFromString(tt.In)
c.Assert(err, IsNil)
row := chunk.MutRowFromDatums([]types.Datum{types.NewDatum(j)})
res, isNull, err := sig.evalDecimal(row.ToRow())
c.Assert(isNull, Equals, false)
c.Assert(err, IsNil)
c.Assert(res.Compare(tt.Out), Equals, 0)
}
}

// TestWrapWithCastAsTypesClasses tests WrapWithCastAsInt/Real/String/Decimal.
func (s *testEvaluatorSuite) TestWrapWithCastAsTypesClasses(c *C) {
ctx := s.ctx
Expand Down
15 changes: 15 additions & 0 deletions types/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,21 @@ func ConvertJSONToFloat(sc *stmtctx.StatementContext, j json.BinaryJSON) (float6
return 0, errors.New("Unknown type code in JSON")
}

// ConvertJSONToDecimal casts JSON into decimal.
func ConvertJSONToDecimal(sc *stmtctx.StatementContext, j json.BinaryJSON) (*MyDecimal, error) {
res := new(MyDecimal)
if j.TypeCode != json.TypeCodeString {
f64, err := ConvertJSONToFloat(sc, j)
if err != nil {
return res, errors.Trace(err)
}
err = res.FromFloat64(f64)
return res, errors.Trace(err)
}
err := sc.HandleTruncate(res.FromString([]byte(j.GetString())))
return res, errors.Trace(err)
}

// getValidFloatPrefix gets prefix of string which can be successfully parsed as float.
func getValidFloatPrefix(sc *stmtctx.StatementContext, s string) (valid string, err error) {
var (
Expand Down
21 changes: 21 additions & 0 deletions types/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,27 @@ func (s *testTypeConvertSuite) TestConvertJSONToFloat(c *C) {
}
}

func (s *testTypeConvertSuite) TestConvertJSONToDecimal(c *C) {
var tests = []struct {
In string
Out *MyDecimal
}{
{`{}`, NewDecFromStringForTest("0")},
{`[]`, NewDecFromStringForTest("0")},
{`3`, NewDecFromStringForTest("3")},
{`-3`, NewDecFromStringForTest("-3")},
{`4.5`, NewDecFromStringForTest("4.5")},
{`"1234"`, NewDecFromStringForTest("1234")},
{`"1234567890123456789012345678901234567890123456789012345"`, NewDecFromStringForTest("1234567890123456789012345678901234567890123456789012345")},
}
for _, tt := range tests {
j, err := json.ParseBinaryFromString(tt.In)
c.Assert(err, IsNil)
casted, _ := ConvertJSONToDecimal(new(stmtctx.StatementContext), j)
c.Assert(casted.Compare(tt.Out), Equals, 0)
}
}

func (s *testTypeConvertSuite) TestNumberToDuration(c *C) {
var testCases = []struct {
number int64
Expand Down

0 comments on commit 01c9d82

Please sign in to comment.