summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Kopytov <Alexey.Kopytov@Sun.com>2010-03-18 13:38:29 +0300
committerAlexey Kopytov <Alexey.Kopytov@Sun.com>2010-03-18 13:38:29 +0300
commit2acfdc50929dda084cdad96e4208c1dd6f26e183 (patch)
treeb9789210c6251e842ccc7cee877d0f3ffa2b0887
parentd1ad316a59b6bd48dec94433ffe982ddfc376e35 (diff)
downloadmariadb-git-2acfdc50929dda084cdad96e4208c1dd6f26e183.tar.gz
Bug #8433: Overflow must be an error
All numeric operators and functions on integer, floating point and DECIMAL values now throw an 'out of range' error rather than returning an incorrect value or NULL, when the result is out of supported range for the corresponding data type. Some test cases in the test suite had to be updated accordingly either because the test case itself relied on a value returned in case of a numeric overflow, or because a numeric overflow was the root cause of the corresponding bugs. The latter tests are no longer relevant, since the expressions used to trigger the corresponding bugs are not valid anymore. However, such test cases have been adjusted and kept "for the record". mysql-test/r/func_math.result: Added test cases for bug #8433. Updated results of the test case for bug #31236. mysql-test/r/func_misc.result: Streamlined test cases. mysql-test/r/func_test.result: Streamlined test cases. mysql-test/r/select.result: Streamlined test cases. mysql-test/r/sp.result: Streamlined test cases. mysql-test/r/strict.result: Streamlined test cases. mysql-test/r/type_newdecimal.result: Streamlined test cases. mysql-test/suite/sys_vars/r/sql_slave_skip_counter_basic.result: Streamlined test cases. mysql-test/suite/sys_vars/t/sql_slave_skip_counter_basic.test: Streamlined test cases. mysql-test/t/func_math.test: Added test cases for bug #8433. Updated results of the test case for bug #31236. mysql-test/t/func_misc.test: Streamlined test cases. mysql-test/t/func_test.test: Streamlined test cases. mysql-test/t/select.test: Streamlined test cases. mysql-test/t/sp.test: Streamlined test cases. mysql-test/t/strict.test: Streamlined test cases. mysql-test/t/type_newdecimal.test: Streamlined test cases. sql/item_create.cc: Changed Item_func_cot() to be defined as a standalone Item rather than a combination of "1 / TAN(x)". sql/item_func.cc: Throw an 'out of range' error rather than returning an incorrect value or NULL, when the result of a numeric operator or a function is out of supported range for the corresponding data type. sql/item_func.h: Added validation helpers as inline methods of Item_func. sql/share/errmsg-utf8.txt: New ER_DATA_OUT_OF_RANGE error.
-rw-r--r--mysql-test/r/func_math.result136
-rw-r--r--mysql-test/r/func_misc.result6
-rw-r--r--mysql-test/r/func_test.result4
-rw-r--r--mysql-test/r/select.result15
-rw-r--r--mysql-test/r/sp.result32
-rw-r--r--mysql-test/r/strict.result5
-rw-r--r--mysql-test/r/type_newdecimal.result7
-rw-r--r--mysql-test/suite/sys_vars/r/sql_slave_skip_counter_basic.result4
-rw-r--r--mysql-test/suite/sys_vars/t/sql_slave_skip_counter_basic.test2
-rw-r--r--mysql-test/t/func_math.test141
-rw-r--r--mysql-test/t/func_misc.test2
-rw-r--r--mysql-test/t/func_test.test2
-rw-r--r--mysql-test/t/select.test4
-rw-r--r--mysql-test/t/sp.test9
-rw-r--r--mysql-test/t/strict.test1
-rw-r--r--mysql-test/t/type_newdecimal.test1
-rw-r--r--sql/item_create.cc4
-rw-r--r--sql/item_func.cc328
-rw-r--r--sql/item_func.h59
-rw-r--r--sql/share/errmsg-utf8.txt3
20 files changed, 640 insertions, 125 deletions
diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result
index 537b1db9781..449c05c65a9 100644
--- a/mysql-test/r/func_math.result
+++ b/mysql-test/r/func_math.result
@@ -98,7 +98,7 @@ explain extended select pi(),format(sin(pi()/2),6),format(cos(pi()/2),6),format(
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select pi() AS `pi()`,format(sin((pi() / 2)),6) AS `format(sin(pi()/2),6)`,format(cos((pi() / 2)),6) AS `format(cos(pi()/2),6)`,format(abs(tan(pi())),6) AS `format(abs(tan(pi())),6)`,format((1 / tan(1)),6) AS `format(cot(1),6)`,format(asin(1),6) AS `format(asin(1),6)`,format(acos(0),6) AS `format(acos(0),6)`,format(atan(1),6) AS `format(atan(1),6)`
+Note 1003 select pi() AS `pi()`,format(sin((pi() / 2)),6) AS `format(sin(pi()/2),6)`,format(cos((pi() / 2)),6) AS `format(cos(pi()/2),6)`,format(abs(tan(pi())),6) AS `format(abs(tan(pi())),6)`,format(cot(1),6) AS `format(cot(1),6)`,format(asin(1),6) AS `format(asin(1),6)`,format(acos(0),6) AS `format(acos(0),6)`,format(atan(1),6) AS `format(atan(1),6)`
select degrees(pi()),radians(360);
degrees(pi()) radians(360)
180 6.283185307179586
@@ -451,23 +451,17 @@ SELECT 1 FROM (SELECT ROUND(f1, f1) AS a FROM t1) AS s WHERE a LIKE 'a';
DROP TABLE t1;
End of 5.0 tests
SELECT 1e308 + 1e308;
-1e308 + 1e308
-NULL
+ERROR 22003: DOUBLE value is out of range in '(1e308 + 1e308)'
SELECT -1e308 - 1e308;
--1e308 - 1e308
-NULL
+ERROR 22003: DOUBLE value is out of range in '(-(1e308) - 1e308)'
SELECT 1e300 * 1e300;
-1e300 * 1e300
-NULL
+ERROR 22003: DOUBLE value is out of range in '(1e300 * 1e300)'
SELECT 1e300 / 1e-300;
-1e300 / 1e-300
-NULL
+ERROR 22003: DOUBLE value is out of range in '(1e300 / 1e-300)'
SELECT EXP(750);
-EXP(750)
-NULL
+ERROR 22003: DOUBLE value is out of range in 'exp(750)'
SELECT POW(10, 309);
-POW(10, 309)
-NULL
+ERROR 22003: DOUBLE value is out of range in 'pow(10,309)'
#
# Bug #44768: SIGFPE crash when selecting rand from a view
# containing null
@@ -488,11 +482,121 @@ RAND(i)
DROP TABLE t1;
#
select 123456789012345678901234567890.123456789012345678901234567890 div 1 as x;
-ERROR 22003: Out of range value for column 'x' at row 1
+ERROR 22003: BIGINT value is out of range in '(123456789012345678901234567890.123456789012345678901234567890 DIV 1)'
select "123456789012345678901234567890.123456789012345678901234567890" div 1 as x;
-ERROR 22003: Out of range value for column 'x' at row 1
+ERROR 22003: BIGINT value is out of range in '('123456789012345678901234567890.123456789012345678901234567890' DIV 1)'
SHOW WARNINGS;
Level Code Message
Warning 1292 Truncated incorrect DECIMAL value: ''
-Error 1264 Out of range value for column 'x' at row 1
+Error 1689 BIGINT value is out of range in '('123456789012345678901234567890.123456789012345678901234567890' DIV 1)'
End of 5.1 tests
+#
+# Bug #8433: Overflow must be an error
+#
+SELECT 1e308 + 1e308;
+ERROR 22003: DOUBLE value is out of range in '(1e308 + 1e308)'
+SELECT -1e308 - 1e308;
+ERROR 22003: DOUBLE value is out of range in '(-(1e308) - 1e308)'
+SELECT 1e300 * 1e300;
+ERROR 22003: DOUBLE value is out of range in '(1e300 * 1e300)'
+SELECT 1e300 / 1e-300;
+ERROR 22003: DOUBLE value is out of range in '(1e300 / 1e-300)'
+SELECT EXP(750);
+ERROR 22003: DOUBLE value is out of range in 'exp(750)'
+SELECT POW(10, 309);
+ERROR 22003: DOUBLE value is out of range in 'pow(10,309)'
+SELECT COT(0);
+ERROR 22003: DOUBLE value is out of range in 'cot(0)'
+SELECT DEGREES(1e307);
+ERROR 22003: DOUBLE value is out of range in 'degrees(1e307)'
+SELECT 9223372036854775808 + 9223372036854775808;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(9223372036854775808 + 9223372036854775808)'
+SELECT 18446744073709551615 + 1;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(18446744073709551615 + 1)'
+SELECT 1 + 18446744073709551615;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(1 + 18446744073709551615)'
+SELECT -2 + CAST(1 AS UNSIGNED);
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(-(2) + cast(1 as unsigned))'
+SELECT CAST(1 AS UNSIGNED) + -2;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(cast(1 as unsigned) + -(2))'
+SELECT -9223372036854775808 + -9223372036854775808;
+ERROR 22003: BIGINT value is out of range in '(-(9223372036854775808) + -(9223372036854775808))'
+SELECT 9223372036854775807 + 9223372036854775807;
+ERROR 22003: BIGINT value is out of range in '(9223372036854775807 + 9223372036854775807)'
+SELECT CAST(0 AS UNSIGNED) - 9223372036854775809;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(cast(0 as unsigned) - 9223372036854775809)'
+SELECT 9223372036854775808 - 9223372036854775809;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(9223372036854775808 - 9223372036854775809)'
+SELECT CAST(1 AS UNSIGNED) - 2;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(cast(1 as unsigned) - 2)'
+SELECT 18446744073709551615 - (-1);
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(18446744073709551615 - -(1))'
+SELECT -1 - 9223372036854775808;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(-(1) - 9223372036854775808)'
+SELECT -1 - CAST(1 AS UNSIGNED);
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(-(1) - cast(1 as unsigned))'
+SELECT -9223372036854775808 - 1;
+ERROR 22003: BIGINT value is out of range in '(-(9223372036854775808) - 1)'
+SELECT 9223372036854775807 - -9223372036854775808;
+ERROR 22003: BIGINT value is out of range in '(9223372036854775807 - -(9223372036854775808))'
+set SQL_MODE='NO_UNSIGNED_SUBTRACTION';
+SELECT 18446744073709551615 - 1;
+ERROR 22003: BIGINT value is out of range in '(18446744073709551615 - 1)'
+SELECT 18446744073709551615 - CAST(1 AS UNSIGNED);
+ERROR 22003: BIGINT value is out of range in '(18446744073709551615 - cast(1 as unsigned))'
+SELECT 18446744073709551614 - (-1);
+ERROR 22003: BIGINT value is out of range in '(18446744073709551614 - -(1))'
+SELECT 9223372036854775807 - -1;
+ERROR 22003: BIGINT value is out of range in '(9223372036854775807 - -(1))'
+set SQL_MODE=default;
+SELECT 4294967296 * 4294967296;
+ERROR 22003: BIGINT value is out of range in '(4294967296 * 4294967296)'
+SELECT 9223372036854775808 * 2;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(9223372036854775808 * 2)'
+SELECT 9223372036854775808 * 2;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(9223372036854775808 * 2)'
+SELECT 7158278827 * 3221225472;
+ERROR 22003: BIGINT value is out of range in '(7158278827 * 3221225472)'
+SELECT 9223372036854775807 * (-2);
+ERROR 22003: BIGINT value is out of range in '(9223372036854775807 * -(2))'
+SELECT CAST(1 as UNSIGNED) * (-1);
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(cast(1 as unsigned) * -(1))'
+SELECT 9223372036854775807 * 2;
+ERROR 22003: BIGINT value is out of range in '(9223372036854775807 * 2)'
+SELECT ABS(-9223372036854775808);
+ERROR 22003: BIGINT value is out of range in 'abs(-(9223372036854775808))'
+SELECT -9223372036854775808 DIV -1;
+ERROR 22003: BIGINT value is out of range in '(-(9223372036854775808) DIV -(1))'
+SELECT 18446744073709551615 DIV -1;
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(18446744073709551615 DIV -(1))'
+CREATE TABLE t1(a BIGINT, b BIGINT UNSIGNED);
+INSERT INTO t1 VALUES(-9223372036854775808, 9223372036854775809);
+SELECT -a FROM t1;
+ERROR 22003: BIGINT value is out of range in '-('-9223372036854775808')'
+SELECT -b FROM t1;
+ERROR 22003: BIGINT value is out of range in '-('9223372036854775809')'
+DROP TABLE t1;
+SET @a:=999999999999999999999999999999999999999999999999999999999999999999999999999999999;
+SELECT @a + @a;
+ERROR 22003: DECIMAL value is out of range in '((@a) + (@a))'
+SELECT @a * @a;
+ERROR 22003: DECIMAL value is out of range in '((@a) * (@a))'
+SELECT -@a - @a;
+ERROR 22003: DECIMAL value is out of range in '(-((@a)) - (@a))'
+SELECT @a / 0.5;
+ERROR 22003: DECIMAL value is out of range in '((@a) / 0.5)'
+SELECT COT(1/0);
+COT(1/0)
+NULL
+SELECT -1 + 9223372036854775808;
+-1 + 9223372036854775808
+9223372036854775807
+SELECT 2 DIV -2;
+2 DIV -2
+-1
+SELECT -(1 DIV 0);
+-(1 DIV 0)
+NULL
+SELECT -9223372036854775808 MOD -1;
+-9223372036854775808 MOD -1
+0
diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result
index 81dddd0f648..d4c1aef4054 100644
--- a/mysql-test/r/func_misc.result
+++ b/mysql-test/r/func_misc.result
@@ -25,9 +25,9 @@ length(uuid()) charset(uuid()) length(unhex(replace(uuid(),_utf8'-',_utf8'')))
36 utf8 16
set @a= uuid_short();
set @b= uuid_short();
-select cast(@a - @b as signed);
-cast(@a - @b as signed)
--1
+select @b - @a;
+@b - @a
+1
select length(format('nan', 2)) > 0;
length(format('nan', 2)) > 0
1
diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result
index 96a7bafccfc..bd111a3c310 100644
--- a/mysql-test/r/func_test.result
+++ b/mysql-test/r/func_test.result
@@ -63,8 +63,8 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select (10 % 7) AS `10 % 7`,(10 % 7) AS `10 mod 7`,(10 DIV 3) AS `10 div 3`
-select (1 << 64)-1, ((1 << 64)-1) DIV 1, ((1 << 64)-1) DIV 2;
-(1 << 64)-1 ((1 << 64)-1) DIV 1 ((1 << 64)-1) DIV 2
+select 18446744073709551615, 18446744073709551615 DIV 1, 18446744073709551615 DIV 2;
+18446744073709551615 18446744073709551615 DIV 1 18446744073709551615 DIV 2
18446744073709551615 18446744073709551615 9223372036854775807
explain extended select (1 << 64)-1, ((1 << 64)-1) DIV 1, ((1 << 64)-1) DIV 2;
id select_type table type possible_keys key key_len ref rows filtered Extra
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index cc752c03a36..305a74ee086 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -2426,27 +2426,28 @@ city
London
DROP TABLE t1;
create table t1 (a int(11) unsigned, b int(11) unsigned);
-insert into t1 values (1,0), (1,1), (1,2);
+insert into t1 values (1,0), (1,1), (18446744073709551615,0);
+Warnings:
+Warning 1264 Out of range value for column 'a' at row 3
select a-b from t1 order by 1;
a-b
0
1
-18446744073709551615
+4294967295
select a-b , (a-b < 0) from t1 order by 1;
a-b (a-b < 0)
0 0
1 0
-18446744073709551615 0
+4294967295 0
select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0;
d (a-b >= 0) b
1 1 0
0 1 1
-18446744073709551615 1 2
select cast((a - b) as unsigned) from t1 order by 1;
cast((a - b) as unsigned)
0
1
-18446744073709551615
+4294967295
drop table t1;
create table t1 (a int(11));
select all all * from t1;
@@ -3419,6 +3420,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 2 Using where
DROP TABLE t1,t2;
+SET SQL_MODE='NO_UNSIGNED_SUBTRACTION';
CREATE TABLE t1 (i TINYINT UNSIGNED NOT NULL);
INSERT t1 SET i = 0;
UPDATE t1 SET i = -1;
@@ -3438,8 +3440,9 @@ Warnings:
Warning 1264 Out of range value for column 'i' at row 1
SELECT * FROM t1;
i
-255
+0
DROP TABLE t1;
+SET SQL_MODE=default;
create table t1 (a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, b int, c int, e int, primary key(a,b,c));
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index b656680326b..62981a2a8d5 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -6022,16 +6022,12 @@ select bug20777(9223372036854775810) as '9223372036854775810 2**63+2';
9223372036854775810 2**63+2
9223372036854775810
select bug20777(-9223372036854775808) as 'lower bounds signed bigint';
-lower bounds signed bigint
-0
-Warnings:
-Warning 1264 Out of range value for column 'f1' at row 1
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(f1@0 - 10)'
select bug20777(9223372036854775807) as 'upper bounds signed bigint';
upper bounds signed bigint
9223372036854775807
select bug20777(0) as 'lower bounds unsigned bigint';
-lower bounds unsigned bigint
-0
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(f1@0 - 10)'
select bug20777(18446744073709551615) as 'upper bounds unsigned bigint';
upper bounds unsigned bigint
18446744073709551615
@@ -6041,10 +6037,7 @@ upper bounds unsigned bigint + 1
Warnings:
Warning 1264 Out of range value for column 'f1' at row 1
select bug20777(-1) as 'lower bounds unsigned bigint - 1';
-lower bounds unsigned bigint - 1
-0
-Warnings:
-Warning 1264 Out of range value for column 'f1' at row 1
+ERROR 22003: BIGINT UNSIGNED value is out of range in '(f1@0 - 10)'
create table examplebug20777 as select
0 as 'i',
bug20777(9223372036854775806) as '2**63-2',
@@ -6053,15 +6046,10 @@ bug20777(9223372036854775808) as '2**63',
bug20777(9223372036854775809) as '2**63+1',
bug20777(18446744073709551614) as '2**64-2',
bug20777(18446744073709551615) as '2**64-1',
-bug20777(18446744073709551616) as '2**64',
-bug20777(0) as '0',
-bug20777(-1) as '-1';
+bug20777(18446744073709551616) as '2**64';
Warnings:
Warning 1264 Out of range value for column 'f1' at row 1
-Warning 1264 Out of range value for column 'f1' at row 1
-insert into examplebug20777 values (1, 9223372036854775806, 9223372036854775807, 223372036854775808, 9223372036854775809, 18446744073709551614, 18446744073709551615, 8446744073709551616, 0, -1);
-Warnings:
-Warning 1264 Out of range value for column '-1' at row 1
+insert into examplebug20777 values (1, 9223372036854775806, 9223372036854775807, 223372036854775808, 9223372036854775809, 18446744073709551614, 18446744073709551615, 8446744073709551616);
show create table examplebug20777;
Table Create Table
examplebug20777 CREATE TABLE `examplebug20777` (
@@ -6072,14 +6060,12 @@ examplebug20777 CREATE TABLE `examplebug20777` (
`2**63+1` bigint(20) unsigned DEFAULT NULL,
`2**64-2` bigint(20) unsigned DEFAULT NULL,
`2**64-1` bigint(20) unsigned DEFAULT NULL,
- `2**64` bigint(20) unsigned DEFAULT NULL,
- `0` bigint(20) unsigned DEFAULT NULL,
- `-1` bigint(20) unsigned DEFAULT NULL
+ `2**64` bigint(20) unsigned DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from examplebug20777 order by i;
-i 2**63-2 2**63-1 2**63 2**63+1 2**64-2 2**64-1 2**64 0 -1
-0 9223372036854775806 9223372036854775807 9223372036854775808 9223372036854775809 18446744073709551614 18446744073709551615 18446744073709551615 0 0
-1 9223372036854775806 9223372036854775807 223372036854775808 9223372036854775809 18446744073709551614 18446744073709551615 8446744073709551616 0 0
+i 2**63-2 2**63-1 2**63 2**63+1 2**64-2 2**64-1 2**64
+0 9223372036854775806 9223372036854775807 9223372036854775808 9223372036854775809 18446744073709551614 18446744073709551615 18446744073709551615
+1 9223372036854775806 9223372036854775807 223372036854775808 9223372036854775809 18446744073709551614 18446744073709551615 8446744073709551616
drop table examplebug20777;
select bug20777(18446744073709551613)+1;
bug20777(18446744073709551613)+1
diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result
index fa4096cb424..769e797d2f6 100644
--- a/mysql-test/r/strict.result
+++ b/mysql-test/r/strict.result
@@ -895,6 +895,7 @@ ERROR 22003: Out of range value for column 'col1' at row 1
INSERT INTO t1 (col2) VALUES ('-1.2E-3');
ERROR 22003: Out of range value for column 'col2' at row 1
UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
+ERROR 22003: DOUBLE value is out of range in '("test"."t1"."col1" * 5000)'
UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
ERROR 22012: Division by 0
UPDATE t1 SET col2= MOD(col2,0) WHERE col2 > 0;
@@ -922,10 +923,10 @@ SELECT * FROM t1;
col1 col2
-2.2e-307 0
1e-303 0
-NULL 1.7e308
+1.7e308 1.7e308
-2.2e-307 0
-2e-307 0
-NULL 1.7e308
+1.7e308 1.7e308
0 NULL
2 NULL
NULL NULL
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
index 00526597a32..e5fbf158a8b 100644
--- a/mysql-test/r/type_newdecimal.result
+++ b/mysql-test/r/type_newdecimal.result
@@ -1385,11 +1385,7 @@ Warning 1264 Out of range value for column 'c1' at row 1
insert into t1 values(
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 *
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999);
-Warnings:
-Warning 1292 Truncated incorrect DECIMAL value: ''
-Warning 1292 Truncated incorrect DECIMAL value: ''
-Warning 1292 Truncated incorrect DECIMAL value: ''
-Warning 1264 Out of range value for column 'c1' at row 1
+ERROR 22003: DECIMAL value is out of range in '(99999999999999999999999999999999999999999999999999999999999999999 * 99999999999999999999999999999999999999999999999999999999999999999)'
insert into t1 values(1e100);
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
@@ -1397,7 +1393,6 @@ select * from t1;
c1
9999999999999999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999999999999999
-9999999999999999999999999999999999999999999999999999999999999999
drop table t1;
create table t1(a decimal(7,2));
insert into t1 values(123.12);
diff --git a/mysql-test/suite/sys_vars/r/sql_slave_skip_counter_basic.result b/mysql-test/suite/sys_vars/r/sql_slave_skip_counter_basic.result
index 2d709c486dd..e6d9aff7141 100644
--- a/mysql-test/suite/sys_vars/r/sql_slave_skip_counter_basic.result
+++ b/mysql-test/suite/sys_vars/r/sql_slave_skip_counter_basic.result
@@ -14,9 +14,9 @@ SET @@global.sql_slave_skip_counter = 2147483648*2;
Warnings:
Warning 1292 Truncated incorrect sql_slave_skip_counter value: '4294967296'
SET @@global.sql_slave_skip_counter = 2147483648*2-1;
-SET @@global.sql_slave_skip_counter = 4294967295*4294967295;
+SET @@global.sql_slave_skip_counter = 18446744065119617025;
Warnings:
-Warning 1292 Truncated incorrect sql_slave_skip_counter value: '-8589934591'
+Warning 1292 Truncated incorrect sql_slave_skip_counter value: '18446744065119617025'
'#--------------------FN_DYNVARS_165_03-------------------------#'
SET @@global.sql_slave_skip_counter = '5';
ERROR 42000: Incorrect argument type to variable 'sql_slave_skip_counter'
diff --git a/mysql-test/suite/sys_vars/t/sql_slave_skip_counter_basic.test b/mysql-test/suite/sys_vars/t/sql_slave_skip_counter_basic.test
index 86cb3824d07..10ca47133b7 100644
--- a/mysql-test/suite/sys_vars/t/sql_slave_skip_counter_basic.test
+++ b/mysql-test/suite/sys_vars/t/sql_slave_skip_counter_basic.test
@@ -56,7 +56,7 @@ SET @@global.sql_slave_skip_counter = 1024;
SET @@global.sql_slave_skip_counter = 2147483648;
SET @@global.sql_slave_skip_counter = 2147483648*2;
SET @@global.sql_slave_skip_counter = 2147483648*2-1;
-SET @@global.sql_slave_skip_counter = 4294967295*4294967295;
+SET @@global.sql_slave_skip_counter = 18446744065119617025;
--echo '#--------------------FN_DYNVARS_165_03-------------------------#'
###################################################################
diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test
index b999b1e8c1b..44af2f5ad3f 100644
--- a/mysql-test/t/func_math.test
+++ b/mysql-test/t/func_math.test
@@ -283,12 +283,20 @@ DROP TABLE t1;
#
# Bug #31236: Inconsistent division by zero behavior for floating point numbers
#
+# After the fix for bug #8433 we throw an error in the below test cases
+# rather than just return a NULL value.
+--error ER_DATA_OUT_OF_RANGE
SELECT 1e308 + 1e308;
+--error ER_DATA_OUT_OF_RANGE
SELECT -1e308 - 1e308;
+--error ER_DATA_OUT_OF_RANGE
SELECT 1e300 * 1e300;
+--error ER_DATA_OUT_OF_RANGE
SELECT 1e300 / 1e-300;
+--error ER_DATA_OUT_OF_RANGE
SELECT EXP(750);
+--error ER_DATA_OUT_OF_RANGE
SELECT POW(10, 309);
--echo #
@@ -314,10 +322,139 @@ DROP TABLE t1;
# 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
+--error ER_DATA_OUT_OF_RANGE
select 123456789012345678901234567890.123456789012345678901234567890 div 1 as x;
---error ER_WARN_DATA_OUT_OF_RANGE
+--error ER_DATA_OUT_OF_RANGE
select "123456789012345678901234567890.123456789012345678901234567890" div 1 as x;
SHOW WARNINGS;
--echo End of 5.1 tests
+
+--echo #
+--echo # Bug #8433: Overflow must be an error
+--echo #
+
+# Floating point overflows
+# ========================
+--error ER_DATA_OUT_OF_RANGE
+SELECT 1e308 + 1e308;
+--error ER_DATA_OUT_OF_RANGE
+SELECT -1e308 - 1e308;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 1e300 * 1e300;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 1e300 / 1e-300;
+--error ER_DATA_OUT_OF_RANGE
+SELECT EXP(750);
+--error ER_DATA_OUT_OF_RANGE
+SELECT POW(10, 309);
+--error ER_DATA_OUT_OF_RANGE
+SELECT COT(0);
+--error ER_DATA_OUT_OF_RANGE
+SELECT DEGREES(1e307);
+
+# Integer overflows
+# =================
+
+--error ER_DATA_OUT_OF_RANGE
+SELECT 9223372036854775808 + 9223372036854775808;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 18446744073709551615 + 1;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 1 + 18446744073709551615;
+--error ER_DATA_OUT_OF_RANGE
+SELECT -2 + CAST(1 AS UNSIGNED);
+--error ER_DATA_OUT_OF_RANGE
+SELECT CAST(1 AS UNSIGNED) + -2;
+--error ER_DATA_OUT_OF_RANGE
+SELECT -9223372036854775808 + -9223372036854775808;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 9223372036854775807 + 9223372036854775807;
+
+--error ER_DATA_OUT_OF_RANGE
+SELECT CAST(0 AS UNSIGNED) - 9223372036854775809;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 9223372036854775808 - 9223372036854775809;
+--error ER_DATA_OUT_OF_RANGE
+SELECT CAST(1 AS UNSIGNED) - 2;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 18446744073709551615 - (-1);
+--error ER_DATA_OUT_OF_RANGE
+SELECT -1 - 9223372036854775808;
+--error ER_DATA_OUT_OF_RANGE
+SELECT -1 - CAST(1 AS UNSIGNED);
+--error ER_DATA_OUT_OF_RANGE
+SELECT -9223372036854775808 - 1;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 9223372036854775807 - -9223372036854775808;
+
+# To test SIGNED overflow when subtraction arguments are both UNSIGNED
+set SQL_MODE='NO_UNSIGNED_SUBTRACTION';
+--error ER_DATA_OUT_OF_RANGE
+SELECT 18446744073709551615 - 1;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 18446744073709551615 - CAST(1 AS UNSIGNED);
+--error ER_DATA_OUT_OF_RANGE
+SELECT 18446744073709551614 - (-1);
+--error ER_DATA_OUT_OF_RANGE
+SELECT 9223372036854775807 - -1;
+set SQL_MODE=default;
+
+--error ER_DATA_OUT_OF_RANGE
+SELECT 4294967296 * 4294967296;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 9223372036854775808 * 2;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 9223372036854775808 * 2;
+# The following one triggers condition #3 from the comments in
+# Item_func_mul::int_op()
+--error ER_DATA_OUT_OF_RANGE
+SELECT 7158278827 * 3221225472;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 9223372036854775807 * (-2);
+--error ER_DATA_OUT_OF_RANGE
+SELECT CAST(1 as UNSIGNED) * (-1);
+--error ER_DATA_OUT_OF_RANGE
+SELECT 9223372036854775807 * 2;
+
+--error ER_DATA_OUT_OF_RANGE
+SELECT ABS(-9223372036854775808);
+
+--error ER_DATA_OUT_OF_RANGE
+SELECT -9223372036854775808 DIV -1;
+--error ER_DATA_OUT_OF_RANGE
+SELECT 18446744073709551615 DIV -1;
+
+
+# Have to create a table because the negation op may convert literals to DECIMAL
+CREATE TABLE t1(a BIGINT, b BIGINT UNSIGNED);
+INSERT INTO t1 VALUES(-9223372036854775808, 9223372036854775809);
+
+--error ER_DATA_OUT_OF_RANGE
+SELECT -a FROM t1;
+--error ER_DATA_OUT_OF_RANGE
+SELECT -b FROM t1;
+
+DROP TABLE t1;
+
+# Decimal overflows
+# =================
+
+SET @a:=999999999999999999999999999999999999999999999999999999999999999999999999999999999;
+--error ER_DATA_OUT_OF_RANGE
+SELECT @a + @a;
+--error ER_DATA_OUT_OF_RANGE
+SELECT @a * @a;
+--error ER_DATA_OUT_OF_RANGE
+SELECT -@a - @a;
+--error ER_DATA_OUT_OF_RANGE
+SELECT @a / 0.5;
+
+# Non-overflow tests to improve code coverage
+# ===========================================
+SELECT COT(1/0);
+SELECT -1 + 9223372036854775808;
+SELECT 2 DIV -2;
+SELECT -(1 DIV 0);
+# Crashed the server with SIGFPE before the bugfix
+SELECT -9223372036854775808 MOD -1;
diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test
index 6590b43f2dc..43cc6de6649 100644
--- a/mysql-test/t/func_misc.test
+++ b/mysql-test/t/func_misc.test
@@ -22,7 +22,7 @@ select length(uuid()), charset(uuid()), length(unhex(replace(uuid(),_utf8'-',_ut
# between two calls should be -1
set @a= uuid_short();
set @b= uuid_short();
-select cast(@a - @b as signed);
+select @b - @a;
#
# Test for core dump with nan
diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test
index 77bf3be5e72..f697e0b477a 100644
--- a/mysql-test/t/func_test.test
+++ b/mysql-test/t/func_test.test
@@ -24,7 +24,7 @@ select 1 XOR 1, 1 XOR 0, 0 XOR 1, 0 XOR 0, NULL XOR 1, 1 XOR NULL, 0 XOR NULL;
select 1 like 2 xor 2 like 1;
select 10 % 7, 10 mod 7, 10 div 3;
explain extended select 10 % 7, 10 mod 7, 10 div 3;
-select (1 << 64)-1, ((1 << 64)-1) DIV 1, ((1 << 64)-1) DIV 2;
+select 18446744073709551615, 18446744073709551615 DIV 1, 18446744073709551615 DIV 2;
explain extended select (1 << 64)-1, ((1 << 64)-1) DIV 1, ((1 << 64)-1) DIV 2;
create table t1 (a int);
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index 80a714882be..1e53461f665 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -1989,7 +1989,7 @@ DROP TABLE t1;
#
create table t1 (a int(11) unsigned, b int(11) unsigned);
-insert into t1 values (1,0), (1,1), (1,2);
+insert into t1 values (1,0), (1,1), (18446744073709551615,0);
select a-b from t1 order by 1;
select a-b , (a-b < 0) from t1 order by 1;
select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0;
@@ -2910,6 +2910,7 @@ DROP TABLE t1,t2;
# cases to prevent fixing this accidently. It is intended behaviour)
#
+SET SQL_MODE='NO_UNSIGNED_SUBTRACTION';
CREATE TABLE t1 (i TINYINT UNSIGNED NOT NULL);
INSERT t1 SET i = 0;
UPDATE t1 SET i = -1;
@@ -2919,6 +2920,7 @@ SELECT * FROM t1;
UPDATE t1 SET i = i - 1;
SELECT * FROM t1;
DROP TABLE t1;
+SET SQL_MODE=default;
# BUG#17379
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index b4727ad3df7..310803531d9 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -7076,11 +7076,14 @@ select bug20777(9223372036854775807) as '9223372036854775807 2**63-1';
select bug20777(9223372036854775808) as '9223372036854775808 2**63+0';
select bug20777(9223372036854775809) as '9223372036854775809 2**63+1';
select bug20777(9223372036854775810) as '9223372036854775810 2**63+2';
+--error ER_DATA_OUT_OF_RANGE
select bug20777(-9223372036854775808) as 'lower bounds signed bigint';
select bug20777(9223372036854775807) as 'upper bounds signed bigint';
+--error ER_DATA_OUT_OF_RANGE
select bug20777(0) as 'lower bounds unsigned bigint';
select bug20777(18446744073709551615) as 'upper bounds unsigned bigint';
select bug20777(18446744073709551616) as 'upper bounds unsigned bigint + 1';
+--error ER_DATA_OUT_OF_RANGE
select bug20777(-1) as 'lower bounds unsigned bigint - 1';
create table examplebug20777 as select
@@ -7091,10 +7094,8 @@ create table examplebug20777 as select
bug20777(9223372036854775809) as '2**63+1',
bug20777(18446744073709551614) as '2**64-2',
bug20777(18446744073709551615) as '2**64-1',
- bug20777(18446744073709551616) as '2**64',
- bug20777(0) as '0',
- bug20777(-1) as '-1';
-insert into examplebug20777 values (1, 9223372036854775806, 9223372036854775807, 223372036854775808, 9223372036854775809, 18446744073709551614, 18446744073709551615, 8446744073709551616, 0, -1);
+ bug20777(18446744073709551616) as '2**64';
+insert into examplebug20777 values (1, 9223372036854775806, 9223372036854775807, 223372036854775808, 9223372036854775809, 18446744073709551614, 18446744073709551615, 8446744073709551616);
show create table examplebug20777;
select * from examplebug20777 order by i;
diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test
index d1e136bf5fa..0dd324d5df2 100644
--- a/mysql-test/t/strict.test
+++ b/mysql-test/t/strict.test
@@ -822,6 +822,7 @@ INSERT INTO t1 (col2) VALUES (-1.1E-3);
INSERT INTO t1 (col1) VALUES ('+1.8E+309');
--error 1264
INSERT INTO t1 (col2) VALUES ('-1.2E-3');
+--error ER_DATA_OUT_OF_RANGE
UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
--error 1365
UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
index 8af9d4c263e..3f418a339cc 100644
--- a/mysql-test/t/type_newdecimal.test
+++ b/mysql-test/t/type_newdecimal.test
@@ -1090,6 +1090,7 @@ create table t1 (c1 decimal(64));
--disable_ps_protocol
insert into t1 values(
89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000);
+--error ER_DATA_OUT_OF_RANGE
insert into t1 values(
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 *
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999);
diff --git a/sql/item_create.cc b/sql/item_create.cc
index a393c886483..5277e2c7b1d 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -2946,9 +2946,7 @@ Create_func_cot Create_func_cot::s_singleton;
Item*
Create_func_cot::create(THD *thd, Item *arg1)
{
- Item *i1= new (thd->mem_root) Item_int((char*) "1", 1, 1);
- Item *i2= new (thd->mem_root) Item_func_tan(arg1);
- return new (thd->mem_root) Item_func_div(i1, i2);
+ return new (thd->mem_root) Item_func_cot(arg1);
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 75f8b2045b5..ef4c37be808 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -65,6 +65,14 @@ eval_const_cond(COND *cond)
}
+/**
+ Test if the sum of arguments overflows the ulonglong range.
+*/
+static inline bool test_if_sum_overflows_ull(ulonglong arg1, ulonglong arg2)
+{
+ return ULONGLONG_MAX - arg1 < arg2;
+}
+
void Item_func::set_arguments(List<Item> &list)
{
allowed_arg_cols= 1;
@@ -1091,16 +1099,68 @@ double Item_func_plus::real_op()
double value= args[0]->val_real() + args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
- return fix_result(value);
+ return check_float_overflow(value);
}
longlong Item_func_plus::int_op()
{
- longlong value=args[0]->val_int()+args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
+ longlong val0= args[0]->val_int();
+ longlong val1= args[1]->val_int();
+ longlong res= val0 + val1;
+ bool res_unsigned= FALSE;
+
+ if ((null_value= args[0]->null_value || args[1]->null_value))
return 0;
- return value;
+
+ /*
+ First check whether the result can be represented as a
+ (bool unsigned_flag, longlong value) pair, then check if it is compatible
+ with this Item's unsigned_flag by calling check_integer_overflow().
+ */
+ if (args[0]->unsigned_flag)
+ {
+ if (args[1]->unsigned_flag || val1 >= 0)
+ {
+ if (test_if_sum_overflows_ull((ulonglong) val0, (ulonglong) val1))
+ goto err;
+ res_unsigned= TRUE;
+ }
+ else
+ {
+ /* val1 is negative */
+ if ((ulonglong) val0 > (ulonglong) LONGLONG_MAX)
+ res_unsigned= TRUE;
+ }
+ }
+ else
+ {
+ if (args[1]->unsigned_flag)
+ {
+ if (val0 >= 0)
+ {
+ if (test_if_sum_overflows_ull((ulonglong) val0, (ulonglong) val1))
+ goto err;
+ res_unsigned= TRUE;
+ }
+ else
+ {
+ if ((ulonglong) val1 > (ulonglong) LONGLONG_MAX)
+ res_unsigned= TRUE;
+ }
+ }
+ else
+ {
+ if (val0 >=0 && val1 >= 0)
+ res_unsigned= TRUE;
+ else if (val0 < 0 && val1 < 0 && res >= 0)
+ goto err;
+ }
+ }
+ return check_integer_overflow(res, res_unsigned);
+
+err:
+ return raise_integer_overflow();
}
@@ -1124,8 +1184,10 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
- (my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 3))))
+ check_decimal_overflow(my_decimal_add(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW,
+ decimal_value,
+ val1, val2)) > 3)))
return decimal_value;
return 0;
}
@@ -1169,16 +1231,71 @@ double Item_func_minus::real_op()
double value= args[0]->val_real() - args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
- return fix_result(value);
+ return check_float_overflow(value);
}
longlong Item_func_minus::int_op()
{
- longlong value=args[0]->val_int() - args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
+ longlong val0= args[0]->val_int();
+ longlong val1= args[1]->val_int();
+ longlong res= val0 - val1;
+ bool res_unsigned= FALSE;
+
+ if ((null_value= args[0]->null_value || args[1]->null_value))
return 0;
- return value;
+
+ /*
+ First check whether the result can be represented as a
+ (bool unsigned_flag, longlong value) pair, then check if it is compatible
+ with this Item's unsigned_flag by calling check_integer_overflow().
+ */
+ if (args[0]->unsigned_flag)
+ {
+ if (args[1]->unsigned_flag)
+ {
+ if ((ulonglong) val0 < (ulonglong) val1)
+ {
+ if (res >= 0)
+ goto err;
+ }
+ else
+ res_unsigned= TRUE;
+ }
+ else
+ {
+ if (val1 >= 0)
+ {
+ if ((ulonglong) val0 > (ulonglong) val1)
+ res_unsigned= TRUE;
+ }
+ else
+ {
+ if (test_if_sum_overflows_ull((ulonglong) val0, (ulonglong) -val1))
+ goto err;
+ res_unsigned= TRUE;
+ }
+ }
+ }
+ else
+ {
+ if (args[1]->unsigned_flag)
+ {
+ if ((ulonglong) (val0 - LONGLONG_MIN) < (ulonglong) val1)
+ goto err;
+ }
+ else
+ {
+ if (val0 > 0 && val1 < 0)
+ res_unsigned= TRUE;
+ else if (val0 < 0 && val1 > 0 && res >= 0)
+ goto err;
+ }
+ }
+ return check_integer_overflow(res, res_unsigned);
+
+err:
+ return raise_integer_overflow();
}
@@ -1196,8 +1313,10 @@ my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value)
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
- (my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 3))))
+ (check_decimal_overflow(my_decimal_sub(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW,
+ decimal_value, val1,
+ val2)) > 3))))
return decimal_value;
return 0;
}
@@ -1209,17 +1328,86 @@ double Item_func_mul::real_op()
double value= args[0]->val_real() * args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
- return fix_result(value);
+ return check_float_overflow(value);
}
longlong Item_func_mul::int_op()
{
DBUG_ASSERT(fixed == 1);
- longlong value=args[0]->val_int()*args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
+ longlong a= args[0]->val_int();
+ longlong b= args[1]->val_int();
+ longlong res;
+ ulonglong res0, res1;
+ ulong a0, a1, b0, b1;
+ bool res_unsigned= FALSE;
+ bool a_negative= FALSE, b_negative= FALSE;
+
+ if ((null_value= args[0]->null_value || args[1]->null_value))
return 0;
- return value;
+
+ /*
+ First check whether the result can be represented as a
+ (bool unsigned_flag, longlong value) pair, then check if it is compatible
+ with this Item's unsigned_flag by calling check_integer_overflow().
+
+ Let a = a1 * 2^32 + a0 and b = b1 * 2^32 + b0. Then
+ a * b = (a1 * 2^32 + a0) * (b1 * 2^32 + b0) = a1 * b1 * 2^64 +
+ + (a1 * b0 + a0 * b1) * 2^32 + a0 * b0;
+ We can determine if the above sum overflows the ulonglong range by
+ sequentially checking the following conditions:
+ 1. If both a1 and b1 are non-zero.
+ 2. Otherwise, if (a1 * b0 + a0 * b1) is greater than ULONG_MAX.
+ 3. Otherwise, if (a1 * b0 + a0 * b1) * 2^32 + a0 * b0 is greater than
+ ULONGLONG_MAX.
+
+ Since we also have to take the unsigned_flag for a and b into account,
+ it is easier to first work with absolute values and set the
+ correct sign later.
+ */
+ if (!args[0]->unsigned_flag && a < 0)
+ {
+ a_negative= TRUE;
+ a= -a;
+ }
+ if (!args[1]->unsigned_flag && b < 0)
+ {
+ b_negative= TRUE;
+ b= -b;
+ }
+
+ a0= 0xFFFFFFFFUL & a;
+ a1= ((ulonglong) a) >> 32;
+ b0= 0xFFFFFFFFUL & b;
+ b1= ((ulonglong) b) >> 32;
+
+ if (a1 && b1)
+ goto err;
+
+ res1= (ulonglong) a1 * b0 + (ulonglong) a0 * b1;
+ if (res1 > 0xFFFFFFFFUL)
+ goto err;
+
+ res1= res1 << 32;
+ res0= (ulonglong) a0 * b0;
+
+ if (test_if_sum_overflows_ull(res1, res0))
+ goto err;
+ res= res1 + res0;
+
+ if (a_negative != b_negative)
+ {
+ if ((ulonglong) res > (ulonglong) LONGLONG_MIN + 1)
+ goto err;
+ res= -res;
+ }
+ else
+ res_unsigned= TRUE;
+
+ return check_integer_overflow(res, res_unsigned);
+
+err:
+ return raise_integer_overflow();
}
@@ -1234,8 +1422,10 @@ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
- (my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 3))))
+ (check_decimal_overflow(my_decimal_mul(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW,
+ decimal_value, val1,
+ val2)) > 3))))
return decimal_value;
return 0;
}
@@ -1268,7 +1458,7 @@ double Item_func_div::real_op()
signal_divide_by_null();
return 0.0;
}
- return fix_result(value/val2);
+ return check_float_overflow(value/val2);
}
@@ -1284,8 +1474,12 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value))
return 0;
- if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
- val1, val2, prec_increment)) > 3)
+ if ((err= check_decimal_overflow(my_decimal_div(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW &
+ ~E_DEC_DIV_ZERO,
+ decimal_value,
+ val1, val2,
+ prec_increment))) > 3)
{
if (err == E_DEC_DIV_ZERO)
signal_divide_by_null();
@@ -1376,22 +1570,35 @@ longlong Item_func_int_div::val_int()
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);
+ raise_integer_overflow();
return res;
}
- longlong value=args[0]->val_int();
- longlong val2=args[1]->val_int();
+ longlong val0=args[0]->val_int();
+ longlong val1=args[1]->val_int();
+ bool val0_negative, val1_negative, res_negative;
+ ulonglong uval0, uval1, res;
if ((null_value= (args[0]->null_value || args[1]->null_value)))
return 0;
- if (val2 == 0)
+ if (val1 == 0)
{
signal_divide_by_null();
return 0;
}
- return (unsigned_flag ?
- (ulonglong) value / (ulonglong) val2 :
- value / val2);
+
+ val0_negative= !args[0]->unsigned_flag && val0 < 0;
+ val1_negative= !args[1]->unsigned_flag && val1 < 0;
+ res_negative= val0_negative != val1_negative;
+ uval0= (ulonglong) (val0_negative ? -val0 : val0);
+ uval1= (ulonglong) (val1_negative ? -val1 : val1);
+ res= uval0 / uval1;
+ if (res_negative)
+ {
+ if (res > (ulonglong) LONGLONG_MAX)
+ return raise_integer_overflow();
+ res= (ulonglong) (-(longlong) res);
+ }
+ return check_integer_overflow(res, !res_negative);
}
@@ -1410,26 +1617,32 @@ void Item_func_int_div::fix_length_and_dec()
longlong Item_func_mod::int_op()
{
DBUG_ASSERT(fixed == 1);
- longlong value= args[0]->val_int();
- longlong val2= args[1]->val_int();
- longlong result;
+ longlong val0= args[0]->val_int();
+ longlong val1= args[1]->val_int();
+ bool val0_negative, val1_negative;
+ ulonglong uval0, uval1;
+ ulonglong res;
if ((null_value= args[0]->null_value || args[1]->null_value))
return 0; /* purecov: inspected */
- if (val2 == 0)
+ if (val1 == 0)
{
signal_divide_by_null();
return 0;
}
- if (args[0]->unsigned_flag)
- result= args[1]->unsigned_flag ?
- ((ulonglong) value) % ((ulonglong) val2) : ((ulonglong) value) % val2;
- else
- result= args[1]->unsigned_flag ?
- value % ((ulonglong) val2) : value % val2;
-
- return result;
+ /*
+ '%' is calculated by integer division internally. Since dividing
+ LONGLONG_MIN by -1 generates SIGFPE, we calculate using unsigned values and
+ then adjust the sign appropriately.
+ */
+ val0_negative= !args[0]->unsigned_flag && val0 < 0;
+ val1_negative= !args[1]->unsigned_flag && val1 < 0;
+ uval0= (ulonglong) (val0_negative ? -val0 : val0);
+ uval1= (ulonglong) (val1_negative ? -val1 : val1);
+ res= uval0 % uval1;
+ return check_integer_overflow(val0_negative ? -(longlong) res : res,
+ !val0_negative);
}
double Item_func_mod::real_op()
@@ -1499,8 +1712,12 @@ double Item_func_neg::real_op()
longlong Item_func_neg::int_op()
{
longlong value= args[0]->val_int();
- null_value= args[0]->null_value;
- return -value;
+ if ((null_value= args[0]->null_value))
+ return 0;
+ if (args[0]->unsigned_flag &&
+ (ulonglong) value > (ulonglong) LONGLONG_MAX + 1)
+ return raise_integer_overflow();
+ return check_integer_overflow(-value, !args[0]->unsigned_flag && value < 0);
}
@@ -1569,7 +1786,12 @@ longlong Item_func_abs::int_op()
longlong value= args[0]->val_int();
if ((null_value= args[0]->null_value))
return 0;
- return (value >= 0) || unsigned_flag ? value : -value;
+ if (unsigned_flag)
+ return value;
+ /* -LONGLONG_MIN = LONGLONG_MAX + 1 => outside of signed longlong range */
+ if (value == LONGLONG_MIN)
+ return raise_integer_overflow();
+ return (value >= 0) ? value : -value;
}
@@ -1676,7 +1898,7 @@ double Item_func_exp::val_real()
double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0.0; /* purecov: inspected */
- return fix_result(exp(value));
+ return check_float_overflow(exp(value));
}
double Item_func_sqrt::val_real()
@@ -1695,7 +1917,7 @@ double Item_func_pow::val_real()
double val2= args[1]->val_real();
if ((null_value=(args[0]->null_value || args[1]->null_value)))
return 0.0; /* purecov: inspected */
- return fix_result(pow(value,val2));
+ return check_float_overflow(pow(value,val2));
}
// Trigonometric functions
@@ -1731,7 +1953,7 @@ double Item_func_atan::val_real()
double val2= args[1]->val_real();
if ((null_value=args[1]->null_value))
return 0.0;
- return fix_result(atan2(value,val2));
+ return check_float_overflow(atan2(value,val2));
}
return atan(value);
}
@@ -1760,7 +1982,17 @@ double Item_func_tan::val_real()
double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0.0;
- return fix_result(tan(value));
+ return check_float_overflow(tan(value));
+}
+
+
+double Item_func_cot::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ double value= args[0]->val_real();
+ if ((null_value=args[0]->null_value))
+ return 0.0;
+ return check_float_overflow(1.0 / tan(value));
}
@@ -2235,7 +2467,7 @@ double Item_func_units::val_real()
double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0;
- return value*mul+add;
+ return check_float_overflow(value * mul + add);
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 6bfdae8d56d..2edb0ad41e3 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -185,13 +185,56 @@ public:
void * arg, traverse_order order);
bool is_expensive_processor(uchar *arg);
virtual bool is_expensive() { return 0; }
- inline double fix_result(double value)
+ inline void raise_numeric_overflow(const char *type_name)
{
- if (isfinite(value))
- return value;
- null_value=1;
+ char buf[256];
+ String str(buf, sizeof(buf), system_charset_info);
+ str.length(0);
+ print(&str, QT_ORDINARY);
+ my_error(ER_DATA_OUT_OF_RANGE, MYF(0), type_name, str.c_ptr_safe());
+ }
+ inline double raise_float_overflow()
+ {
+ raise_numeric_overflow("DOUBLE");
return 0.0;
}
+ inline longlong raise_integer_overflow()
+ {
+ raise_numeric_overflow(unsigned_flag ? "BIGINT UNSIGNED": "BIGINT");
+ return 0;
+ }
+ inline int raise_decimal_overflow()
+ {
+ raise_numeric_overflow("DECIMAL");
+ return E_DEC_OVERFLOW;
+ }
+ /**
+ Throw an error if the input double number is not finite, i.e. is either
+ +/-INF or NAN.
+ */
+ inline double check_float_overflow(double value)
+ {
+ return isfinite(value) ? value : raise_float_overflow();
+ }
+ /**
+ Throw an error if the input BIGINT value represented by the
+ (longlong value, bool unsigned flag) pair cannot be returned by the
+ function, i.e. is not compatible with this Item's unsigned_flag.
+ */
+ inline longlong check_integer_overflow(longlong value, bool val_unsigned)
+ {
+ if ((unsigned_flag && !val_unsigned && value < 0) ||
+ (!unsigned_flag && val_unsigned && (ulonglong) value > LONGLONG_MAX))
+ return raise_integer_overflow();
+ return value;
+ }
+ /**
+ Throw an error if the error code of a DECIMAL operation is E_DEC_OVERFLOW.
+ */
+ inline int check_decimal_overflow(int error)
+ {
+ return (error == E_DEC_OVERFLOW) ? raise_decimal_overflow() : error;
+ }
bool has_timestamp_args()
{
DBUG_ASSERT(fixed == TRUE);
@@ -658,6 +701,14 @@ public:
const char *func_name() const { return "tan"; }
};
+class Item_func_cot :public Item_dec_func
+{
+public:
+ Item_func_cot(Item *a) :Item_dec_func(a) {}
+ double val_real();
+ const char *func_name() const { return "cot"; }
+};
+
class Item_func_integer :public Item_int_func
{
public:
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 40b842c813e..677e2680dd0 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6323,3 +6323,6 @@ ER_SPATIAL_MUST_HAVE_GEOM_COL 42000
ER_TOO_LONG_INDEX_COMMENT
eng "Comment for index '%-.64s' is too long (max = %lu)"
+
+ER_DATA_OUT_OF_RANGE 22003
+ eng "%s value is out of range in '%s'"