diff options
-rw-r--r-- | mysql-test/r/func_math.result | 136 | ||||
-rw-r--r-- | mysql-test/r/func_misc.result | 6 | ||||
-rw-r--r-- | mysql-test/r/func_test.result | 4 | ||||
-rw-r--r-- | mysql-test/r/select.result | 15 | ||||
-rw-r--r-- | mysql-test/r/sp.result | 32 | ||||
-rw-r--r-- | mysql-test/r/strict.result | 5 | ||||
-rw-r--r-- | mysql-test/r/type_newdecimal.result | 7 | ||||
-rw-r--r-- | mysql-test/suite/sys_vars/r/sql_slave_skip_counter_basic.result | 4 | ||||
-rw-r--r-- | mysql-test/suite/sys_vars/t/sql_slave_skip_counter_basic.test | 2 | ||||
-rw-r--r-- | mysql-test/t/func_math.test | 141 | ||||
-rw-r--r-- | mysql-test/t/func_misc.test | 2 | ||||
-rw-r--r-- | mysql-test/t/func_test.test | 2 | ||||
-rw-r--r-- | mysql-test/t/select.test | 4 | ||||
-rw-r--r-- | mysql-test/t/sp.test | 9 | ||||
-rw-r--r-- | mysql-test/t/strict.test | 1 | ||||
-rw-r--r-- | mysql-test/t/type_newdecimal.test | 1 | ||||
-rw-r--r-- | sql/item_create.cc | 4 | ||||
-rw-r--r-- | sql/item_func.cc | 328 | ||||
-rw-r--r-- | sql/item_func.h | 59 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 3 |
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..307f1714132 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 1690 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 cd7874be414..5a746b330bc 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 a835f021d3a..4f259fc4d7d 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 391ddfa4a7c..1616acff942 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; @@ -1094,16 +1102,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(); } @@ -1127,8 +1187,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; } @@ -1172,16 +1234,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(); } @@ -1199,8 +1316,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; } @@ -1212,17 +1331,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(); } @@ -1237,8 +1425,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; } @@ -1271,7 +1461,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); } @@ -1287,8 +1477,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(); @@ -1379,22 +1573,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); } @@ -1413,26 +1620,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() @@ -1502,8 +1715,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); } @@ -1572,7 +1789,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; } @@ -1679,7 +1901,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() @@ -1698,7 +1920,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 @@ -1734,7 +1956,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); } @@ -1763,7 +1985,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)); } @@ -2238,7 +2470,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 fc7f8708a45..38253a73265 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -187,13 +187,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); @@ -667,6 +710,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 4b680c1788d..517782cb0b4 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6324,3 +6324,6 @@ ER_TOO_LONG_INDEX_COMMENT ER_LOCK_ABORTED eng "Wait on a lock was aborted due to a pending exclusive lock" + +ER_DATA_OUT_OF_RANGE 22003 + eng "%s value is out of range in '%s'" |