summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Kopytov <Alexey.Kopytov@Sun.com>2009-10-13 12:31:42 +0400
committerAlexey Kopytov <Alexey.Kopytov@Sun.com>2009-10-13 12:31:42 +0400
commit7e3b4d21c0010bf6bc4fd8cdb8eee3caf8207f29 (patch)
treefea2364401dec8d958b129af9bc211c8ad3c9f96
parent4337c3808f32c0851b7b9e6efb2516302d691bf8 (diff)
downloadmariadb-git-7e3b4d21c0010bf6bc4fd8cdb8eee3caf8207f29.tar.gz
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.
-rw-r--r--mysql-test/r/func_math.result11
-rw-r--r--mysql-test/r/type_varchar.result5
-rw-r--r--mysql-test/t/func_math.test11
-rw-r--r--sql/item_func.cc32
4 files changed, 57 insertions, 2 deletions
diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result
index d8b8a14afc6..f469564c78b 100644
--- a/mysql-test/r/func_math.result
+++ b/mysql-test/r/func_math.result
@@ -382,6 +382,9 @@ y
SELECT b DIV 900 y FROM t1 GROUP BY y;
y
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;
y
0
@@ -482,4 +485,12 @@ RAND(i)
0.155220427694936
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
diff --git a/mysql-test/r/type_varchar.result b/mysql-test/r/type_varchar.result
index 96042a91bae..94628eb16ee 100644
--- a/mysql-test/r/type_varchar.result
+++ b/mysql-test/r/type_varchar.result
@@ -475,8 +475,9 @@ a (a DIV 2)
60 30
t 0
Warnings:
-Warning 1292 Truncated incorrect INTEGER value: '1a'
-Warning 1292 Truncated incorrect INTEGER value: 't '
+Warning 1292 Truncated incorrect DECIMAL value: '1a'
+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;
a CAST(a AS SIGNED)
10 10
diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test
index 91fdce8addb..b999b1e8c1b 100644
--- a/mysql-test/t/func_math.test
+++ b/mysql-test/t/func_math.test
@@ -309,4 +309,15 @@ DROP TABLE t1;
--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
diff --git a/sql/item_func.cc b/sql/item_func.cc
index cf499aaf93c..c0a84e3be28 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1348,6 +1348,38 @@ void Item_func_div::fix_length_and_dec()
longlong Item_func_int_div::val_int()
{
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 val2=args[1]->val_int();
if ((null_value= (args[0]->null_value || args[1]->null_value)))