From c3515c6b6d798224acbb6509e9859c58317e9788 Mon Sep 17 00:00:00 2001 From: jackyan Date: Tue, 20 Aug 2019 20:54:26 +0800 Subject: [PATCH 1/4] expression: fix DIV with decimal type --- expression/builtin_arithmetic.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/expression/builtin_arithmetic.go b/expression/builtin_arithmetic.go index 85b1d757767d8..7ec30b039b59e 100644 --- a/expression/builtin_arithmetic.go +++ b/expression/builtin_arithmetic.go @@ -762,11 +762,24 @@ func (s *builtinArithmeticIntDivideDecimalSig) evalInt(row chunk.Row) (ret int64 return 0, true, err } + isLHSUnsigned := mysql.HasUnsignedFlag(s.args[0].GetType().Flag) + isRHSUnsigned := mysql.HasUnsignedFlag(s.args[1].GetType().Flag) + ret, err = c.ToInt() - // err returned by ToInt may be ErrTruncated or ErrOverflow, only handle ErrOverflow, ignore ErrTruncated. - if err == types.ErrOverflow { - return 0, true, types.ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%s DIV %s)", s.args[0].String(), s.args[1].String())) + if isLHSUnsigned || isRHSUnsigned { + val, err := c.ToUint() + if err == types.ErrOverflow && ret != 0 { + // err returned by ToInt may be ErrTruncated or ErrOverflow, only handle ErrOverflow, ignore ErrTruncated. + return 0, true, types.ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%s DIV %s)", s.args[0].String(), s.args[1].String())) + } + ret = int64(val) + } else { + // err returned by ToInt may be ErrTruncated or ErrOverflow, only handle ErrOverflow, ignore ErrTruncated. + if err == types.ErrOverflow { + return 0, true, types.ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%s DIV %s)", s.args[0].String(), s.args[1].String())) + } } + return ret, false, nil } From 1613aa2816cb36a5d13dd4a83daaec621a4b8281 Mon Sep 17 00:00:00 2001 From: jackyan Date: Wed, 21 Aug 2019 10:32:11 +0800 Subject: [PATCH 2/4] add test for 'DIV with decimal type' --- expression/builtin_arithmetic_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/expression/builtin_arithmetic_test.go b/expression/builtin_arithmetic_test.go index 61a47bbc5d334..c53c5dcb85c1f 100644 --- a/expression/builtin_arithmetic_test.go +++ b/expression/builtin_arithmetic_test.go @@ -441,6 +441,14 @@ func (s *testEvaluatorSuite) TestArithmeticIntDivide(c *C) { args: []interface{}{int64(-9223372036854775808), float64(-1)}, expect: []interface{}{nil, "*BIGINT value is out of range in '\\(-9223372036854775808 DIV -1\\)'"}, }, + { + args: []interface{}{uint64(1), float64(-2)}, + expect: []interface{}{0, nil}, + }, + { + args: []interface{}{uint64(1), float64(-1)}, + expect: []interface{}{nil, "*BIGINT UNSIGNED value is out of range in '\\(1 DIV -1\\)'"}, + }, } for _, tc := range testCases { From ecb2d90b59e5b683f4adb7bee5b4423cab1546a2 Mon Sep 17 00:00:00 2001 From: jackyan Date: Wed, 21 Aug 2019 10:51:20 +0800 Subject: [PATCH 3/4] fix typo --- expression/builtin_arithmetic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expression/builtin_arithmetic.go b/expression/builtin_arithmetic.go index 7ec30b039b59e..65dc71201e5c3 100644 --- a/expression/builtin_arithmetic.go +++ b/expression/builtin_arithmetic.go @@ -768,8 +768,8 @@ func (s *builtinArithmeticIntDivideDecimalSig) evalInt(row chunk.Row) (ret int64 ret, err = c.ToInt() if isLHSUnsigned || isRHSUnsigned { val, err := c.ToUint() + // err returned by ToUInt may be ErrTruncated or ErrOverflow, only handle ErrOverflow, ignore ErrTruncated. if err == types.ErrOverflow && ret != 0 { - // err returned by ToInt may be ErrTruncated or ErrOverflow, only handle ErrOverflow, ignore ErrTruncated. return 0, true, types.ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%s DIV %s)", s.args[0].String(), s.args[1].String())) } ret = int64(val) From e9181f821acf038748d95eedbf4bbf82cbfc7cab Mon Sep 17 00:00:00 2001 From: jackyan Date: Wed, 21 Aug 2019 14:35:32 +0800 Subject: [PATCH 4/4] improve the ability to handle more errors --- expression/builtin_arithmetic.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/expression/builtin_arithmetic.go b/expression/builtin_arithmetic.go index 65dc71201e5c3..9fbe66ca142f4 100644 --- a/expression/builtin_arithmetic.go +++ b/expression/builtin_arithmetic.go @@ -765,15 +765,21 @@ func (s *builtinArithmeticIntDivideDecimalSig) evalInt(row chunk.Row) (ret int64 isLHSUnsigned := mysql.HasUnsignedFlag(s.args[0].GetType().Flag) isRHSUnsigned := mysql.HasUnsignedFlag(s.args[1].GetType().Flag) - ret, err = c.ToInt() if isLHSUnsigned || isRHSUnsigned { val, err := c.ToUint() - // err returned by ToUInt may be ErrTruncated or ErrOverflow, only handle ErrOverflow, ignore ErrTruncated. - if err == types.ErrOverflow && ret != 0 { + // err returned by ToUint may be ErrTruncated or ErrOverflow, only handle ErrOverflow, ignore ErrTruncated. + if err == types.ErrOverflow { + v, err := c.ToInt() + // when the final result is at (-1, 0], it should be return 0 instead of the error + if v == 0 && err == types.ErrTruncated { + ret = int64(0) + return ret, false, nil + } return 0, true, types.ErrOverflow.GenWithStackByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%s DIV %s)", s.args[0].String(), s.args[1].String())) } ret = int64(val) } else { + ret, err = c.ToInt() // err returned by ToInt may be ErrTruncated or ErrOverflow, only handle ErrOverflow, ignore ErrTruncated. if err == types.ErrOverflow { return 0, true, types.ErrOverflow.GenWithStackByArgs("BIGINT", fmt.Sprintf("(%s DIV %s)", s.args[0].String(), s.args[1].String()))