mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
Backport of the patch for bug #8457 "Precision math: DIV
returns incorrect result with large decimal value" For the DIV operator, neither operands nor result were checked for integer overflows. This patch changes the DIV behavior for non-integer operands as follows: if either of the operands has a non-integer type, convert both operands to the DECIMAL type, then calculate the division using DECIMAL arithmetics. Convert the resulting DECIMAL value into BIGINT [UNSIGNED] if it fits into the corresponding range, or throw an 'out of range' error otherwise. mysql-test/r/func_math.result: Added a test case for bug #8457. Fixed results for a test case depending on the wrong behavior. mysql-test/r/type_varchar.result: Fixed results for a test case depending on the wrong behavior. mysql-test/t/func_math.test: Added a test case for bug #8457. sql/item_func.cc: If either of the operands has a non-integer type, convert both operands to the DECIMAL type, then calculate the division using DECIMAL arithmetics. Convert the resulting DECIMAL value into BIGINT [UNSIGNED] if it fits into the corresponding range, or throw an 'out of range' error otherwise.
This commit is contained in:
@@ -382,6 +382,9 @@ y
|
|||||||
SELECT b DIV 900 y FROM t1 GROUP BY y;
|
SELECT b DIV 900 y FROM t1 GROUP BY y;
|
||||||
y
|
y
|
||||||
0
|
0
|
||||||
|
Warnings:
|
||||||
|
Warning 1366 Incorrect decimal value: '' for column '' at row -1
|
||||||
|
Warning 1366 Incorrect decimal value: '' for column '' at row -1
|
||||||
SELECT c DIV 900 y FROM t1 GROUP BY y;
|
SELECT c DIV 900 y FROM t1 GROUP BY y;
|
||||||
y
|
y
|
||||||
0
|
0
|
||||||
@@ -482,4 +485,12 @@ RAND(i)
|
|||||||
0.155220427694936
|
0.155220427694936
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
|
select 123456789012345678901234567890.123456789012345678901234567890 div 1 as x;
|
||||||
|
ERROR 22003: Out of range value for column 'x' at row 1
|
||||||
|
select "123456789012345678901234567890.123456789012345678901234567890" div 1 as x;
|
||||||
|
ERROR 22003: Out of range value for column 'x' at row 1
|
||||||
|
SHOW WARNINGS;
|
||||||
|
Level Code Message
|
||||||
|
Warning 1292 Truncated incorrect DECIMAL value: ''
|
||||||
|
Error 1264 Out of range value for column 'x' at row 1
|
||||||
End of 5.1 tests
|
End of 5.1 tests
|
||||||
|
@@ -475,8 +475,9 @@ a (a DIV 2)
|
|||||||
60 30
|
60 30
|
||||||
t 0
|
t 0
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1292 Truncated incorrect INTEGER value: '1a'
|
Warning 1292 Truncated incorrect DECIMAL value: '1a'
|
||||||
Warning 1292 Truncated incorrect INTEGER value: 't '
|
Warning 1366 Incorrect decimal value: '' for column '' at row -1
|
||||||
|
Warning 1292 Truncated incorrect DECIMAL value: 't '
|
||||||
SELECT a,CAST(a AS SIGNED) FROM t1 ORDER BY a;
|
SELECT a,CAST(a AS SIGNED) FROM t1 ORDER BY a;
|
||||||
a CAST(a AS SIGNED)
|
a CAST(a AS SIGNED)
|
||||||
10 10
|
10 10
|
||||||
|
@@ -309,4 +309,15 @@ DROP TABLE t1;
|
|||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #8457: Precision math:
|
||||||
|
# DIV returns incorrect result with large decimal value
|
||||||
|
# Bug #46606:Casting error for large numbers in 5.4 when 'div' is used
|
||||||
|
|
||||||
|
--error ER_WARN_DATA_OUT_OF_RANGE
|
||||||
|
select 123456789012345678901234567890.123456789012345678901234567890 div 1 as x;
|
||||||
|
--error ER_WARN_DATA_OUT_OF_RANGE
|
||||||
|
select "123456789012345678901234567890.123456789012345678901234567890" div 1 as x;
|
||||||
|
SHOW WARNINGS;
|
||||||
|
|
||||||
--echo End of 5.1 tests
|
--echo End of 5.1 tests
|
||||||
|
@@ -1348,6 +1348,38 @@ void Item_func_div::fix_length_and_dec()
|
|||||||
longlong Item_func_int_div::val_int()
|
longlong Item_func_int_div::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Perform division using DECIMAL math if either of the operands has a
|
||||||
|
non-integer type
|
||||||
|
*/
|
||||||
|
if (args[0]->result_type() != INT_RESULT ||
|
||||||
|
args[1]->result_type() != INT_RESULT)
|
||||||
|
{
|
||||||
|
my_decimal value0, value1, tmp;
|
||||||
|
my_decimal *val0, *val1;
|
||||||
|
longlong res;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
val0= args[0]->val_decimal(&value0);
|
||||||
|
val1= args[1]->val_decimal(&value1);
|
||||||
|
if ((null_value= (args[0]->null_value || args[1]->null_value)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, &tmp,
|
||||||
|
val0, val1, 0)) > 3)
|
||||||
|
{
|
||||||
|
if (err == E_DEC_DIV_ZERO)
|
||||||
|
signal_divide_by_null();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_decimal2int(E_DEC_FATAL_ERROR, &tmp, unsigned_flag, &res) &
|
||||||
|
E_DEC_OVERFLOW)
|
||||||
|
my_error(ER_WARN_DATA_OUT_OF_RANGE, MYF(0), name, 1);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
longlong value=args[0]->val_int();
|
longlong value=args[0]->val_int();
|
||||||
longlong val2=args[1]->val_int();
|
longlong val2=args[1]->val_int();
|
||||||
if ((null_value= (args[0]->null_value || args[1]->null_value)))
|
if ((null_value= (args[0]->null_value || args[1]->null_value)))
|
||||||
|
Reference in New Issue
Block a user