Commit 2acfdc50 authored by Alexey Kopytov's avatar Alexey Kopytov

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.
parent d1ad316a
......@@ -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
......@@ -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
......
......@@ -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
......
......@@ -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));
......
......@@ -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
......
......@@ -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
......
......@@ -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);
......
......@@ -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'
......
......@@ -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-------------------------#'
###################################################################
......
......@@ -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;
......@@ -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
......
......@@ -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);
......
......@@ -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
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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);
}
......
......@@ -185,13 +185,56 @@ class Item_func :public Item_result_field
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 @@ class Item_func_tan :public Item_dec_func
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:
......
......@@ -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'"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment