diff options
author | Alexander Barkov <bar@mariadb.com> | 2020-06-05 12:57:42 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2020-06-06 11:33:11 +0400 |
commit | 79cdd7e76bbebf62629066166f43279095a0fcc9 (patch) | |
tree | f18fc41438f97b84427815e6b82727706c86b4c0 | |
parent | a793ae5bc1270b18ab9359363dedab951f9a912f (diff) | |
download | mariadb-git-79cdd7e76bbebf62629066166f43279095a0fcc9.tar.gz |
MDEV-20305 Data loss on DOUBLE and DECIMAL conversion to INT
Bit operators (~ ^ | & << >>) and the function BIT_COUNT()
always called val_int() for their arguments.
It worked correctly only for INT type arguments.
In case of DECIMAL and DOUBLE arguments it did not work well:
the argument values were truncated to the maximum SIGNED BIGINT value
of 9223372036854775807.
Fixing the code as follows:
- If the argument if of an integer data type,
it works using val_int() as before.
- If the argument if of some other data type, it gets the argument value
using val_decimal(), to avoid truncation, and then converts the result
to ulonglong.
Using Item_handled_func to switch between the two approaches easier.
As an additional advantage, with Item_handled_func it will be easier
to implement overloading in the future, so data type plugings will be able
to define their own behavioir of bit operators and BIT_COUNT().
Moving the code from the former val_int() implementations
as methods to Longlong_null, to avoid code duplication in the
INT and DECIMAL branches.
-rw-r--r-- | mysql-test/main/func_bit.result | 367 | ||||
-rw-r--r-- | mysql-test/main/func_bit.test | 97 | ||||
-rw-r--r-- | mysql-test/main/func_group.result | 2 | ||||
-rw-r--r-- | mysql-test/main/func_str.result | 4 | ||||
-rw-r--r-- | mysql-test/main/func_time.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/engines/iuds/r/type_bit_iuds.result | 54 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 78 | ||||
-rw-r--r-- | sql/item_func.cc | 187 | ||||
-rw-r--r-- | sql/item_func.h | 153 | ||||
-rw-r--r-- | sql/my_decimal.h | 10 | ||||
-rw-r--r-- | sql/sql_type.h | 4 | ||||
-rw-r--r-- | sql/sql_type_int.h | 54 |
12 files changed, 890 insertions, 122 deletions
diff --git a/mysql-test/main/func_bit.result b/mysql-test/main/func_bit.result new file mode 100644 index 00000000000..4eb44f76ef3 --- /dev/null +++ b/mysql-test/main/func_bit.result @@ -0,0 +1,367 @@ +# +# Start of 10.5 tests +# +# +# MDEV-20305 Data loss on DOUBLE and DECIMAL conversion to INT +# +CREATE PROCEDURE p1(type VARCHAR(64), val VARCHAR(64)) +BEGIN +EXECUTE IMMEDIATE CONCAT('CREATE TABLE t1 (a ', type, ')'); +SHOW CREATE TABLE t1; +EXECUTE IMMEDIATE CONCAT('INSERT INTO t1 VALUES (', val, ')'); +SELECT +a, +~a, +a & 18446744073709551615, +18446744073709551615 & a, +0 | a, +a | 0, +a << 0, +a >> 0, +a ^ 1, +1 ^ a, +BIT_COUNT(a) +FROM t1; +SHOW WARNINGS; +DROP TABLE t1; +END; +$$ +CALL p1('BIGINT UNSIGNED', 18446744073709551615); +Table t1 +Create Table CREATE TABLE `t1` ( + `a` bigint(20) unsigned DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +a 18446744073709551615 +~a 0 +a & 18446744073709551615 18446744073709551615 +18446744073709551615 & a 18446744073709551615 +0 | a 18446744073709551615 +a | 0 18446744073709551615 +a << 0 18446744073709551615 +a >> 0 18446744073709551615 +a ^ 1 18446744073709551614 +1 ^ a 18446744073709551614 +BIT_COUNT(a) 64 +CALL p1('DOUBLE', 18446744073709551615); +Table t1 +Create Table CREATE TABLE `t1` ( + `a` double DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +a 1.8446744073709552e19 +~a 0 +a & 18446744073709551615 18446744073709551615 +18446744073709551615 & a 18446744073709551615 +0 | a 18446744073709551615 +a | 0 18446744073709551615 +a << 0 18446744073709551615 +a >> 0 18446744073709551615 +a ^ 1 18446744073709551614 +1 ^ a 18446744073709551614 +BIT_COUNT(a) 64 +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +CALL p1('DECIMAL(30,0)', 18446744073709551615); +Table t1 +Create Table CREATE TABLE `t1` ( + `a` decimal(30,0) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +a 18446744073709551615 +~a 0 +a & 18446744073709551615 18446744073709551615 +18446744073709551615 & a 18446744073709551615 +0 | a 18446744073709551615 +a | 0 18446744073709551615 +a << 0 18446744073709551615 +a >> 0 18446744073709551615 +a ^ 1 18446744073709551614 +1 ^ a 18446744073709551614 +BIT_COUNT(a) 64 +CALL p1('BIGINT', -1); +Table t1 +Create Table CREATE TABLE `t1` ( + `a` bigint(20) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +a -1 +~a 0 +a & 18446744073709551615 18446744073709551615 +18446744073709551615 & a 18446744073709551615 +0 | a 18446744073709551615 +a | 0 18446744073709551615 +a << 0 18446744073709551615 +a >> 0 18446744073709551615 +a ^ 1 18446744073709551614 +1 ^ a 18446744073709551614 +BIT_COUNT(a) 64 +CALL p1('DOUBLE', -1); +Table t1 +Create Table CREATE TABLE `t1` ( + `a` double DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +a -1 +~a 0 +a & 18446744073709551615 18446744073709551615 +18446744073709551615 & a 18446744073709551615 +0 | a 18446744073709551615 +a | 0 18446744073709551615 +a << 0 18446744073709551615 +a >> 0 18446744073709551615 +a ^ 1 18446744073709551614 +1 ^ a 18446744073709551614 +BIT_COUNT(a) 64 +CALL p1('DECIMAL(30,0)', -1); +Table t1 +Create Table CREATE TABLE `t1` ( + `a` decimal(30,0) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +a -1 +~a 0 +a & 18446744073709551615 18446744073709551615 +18446744073709551615 & a 18446744073709551615 +0 | a 18446744073709551615 +a | 0 18446744073709551615 +a << 0 18446744073709551615 +a >> 0 18446744073709551615 +a ^ 1 18446744073709551614 +1 ^ a 18446744073709551614 +BIT_COUNT(a) 64 +CALL p1('BIGINT', -9223372036854775808); +Table t1 +Create Table CREATE TABLE `t1` ( + `a` bigint(20) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +a -9223372036854775808 +~a 9223372036854775807 +a & 18446744073709551615 9223372036854775808 +18446744073709551615 & a 9223372036854775808 +0 | a 9223372036854775808 +a | 0 9223372036854775808 +a << 0 9223372036854775808 +a >> 0 9223372036854775808 +a ^ 1 9223372036854775809 +1 ^ a 9223372036854775809 +BIT_COUNT(a) 1 +CALL p1('DOUBLE', -9223372036854775808); +Table t1 +Create Table CREATE TABLE `t1` ( + `a` double DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +a -9.223372036854776e18 +~a 9223372036854775807 +a & 18446744073709551615 9223372036854775808 +18446744073709551615 & a 9223372036854775808 +0 | a 9223372036854775808 +a | 0 9223372036854775808 +a << 0 9223372036854775808 +a >> 0 9223372036854775808 +a ^ 1 9223372036854775809 +1 ^ a 9223372036854775809 +BIT_COUNT(a) 1 +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +Level Warning +Code 1916 +Message Got overflow when converting '-9223372036854776000' to INT. Value truncated +CALL p1('DECIMAL(30,0)', -9223372036854775808); +Table t1 +Create Table CREATE TABLE `t1` ( + `a` decimal(30,0) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +a -9223372036854775808 +~a 9223372036854775807 +a & 18446744073709551615 9223372036854775808 +18446744073709551615 & a 9223372036854775808 +0 | a 9223372036854775808 +a | 0 9223372036854775808 +a << 0 9223372036854775808 +a >> 0 9223372036854775808 +a ^ 1 9223372036854775809 +1 ^ a 9223372036854775809 +BIT_COUNT(a) 1 +DROP PROCEDURE p1; +SELECT CAST(CAST(18446744073709551615 AS UNSIGNED) AS DECIMAL(32))<<0 AS c1; +c1 +18446744073709551615 +SELECT CAST(CAST(18446744073709551615 AS UNSIGNED) AS DOUBLE)<<0 AS c1; +c1 +18446744073709551615 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT COALESCE(CAST(CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED) AS DECIMAL(32))) << 0 AS c1; +c1 +18446744073709551615 +SELECT COALESCE(CAST(CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED) AS DOUBLE)) << 0 AS c1; +c1 +18446744073709551615 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT 18446744073709551615 ^ 1 AS c1; +c1 +18446744073709551614 +SELECT 18446744073709551615.0 ^ 1 AS c1; +c1 +18446744073709551614 +SELECT 18446744073709551615e0 ^ 1 AS c1; +c1 +18446744073709551614 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT LAST_VALUE(18446744073709551615) ^ 1 AS c1; +c1 +18446744073709551614 +SELECT LAST_VALUE(18446744073709551615.0) ^ 1 AS c1; +c1 +18446744073709551614 +SELECT LAST_VALUE(18446744073709551615e0) ^ 1 AS c1; +c1 +18446744073709551614 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT 18446744073709551615 & 18446744073709551615 AS c1; +c1 +18446744073709551615 +SELECT 18446744073709551615 & 18446744073709551615.0 AS c1; +c1 +18446744073709551615 +SELECT 18446744073709551615 & 18446744073709551615e0 AS c1; +c1 +18446744073709551615 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT 18446744073709551615.0 & 18446744073709551615 AS c1; +c1 +18446744073709551615 +SELECT 18446744073709551615.0 & 18446744073709551615.0 AS c1; +c1 +18446744073709551615 +SELECT 18446744073709551615.0 & 18446744073709551615e0 AS c1; +c1 +18446744073709551615 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT 18446744073709551615e0 & 18446744073709551615 AS c1; +c1 +18446744073709551615 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT 18446744073709551615e0 & 18446744073709551615.0 AS c1; +c1 +18446744073709551615 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT 18446744073709551615e0 & 18446744073709551615e0 AS c1; +c1 +18446744073709551615 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT 0 | 18446744073709551615 AS c1; +c1 +18446744073709551615 +SELECT 0 | 18446744073709551615.0 AS c1; +c1 +18446744073709551615 +SELECT 0 | 18446744073709551615e0 AS c1; +c1 +18446744073709551615 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT 18446744073709551615 | 0 AS c1; +c1 +18446744073709551615 +SELECT 18446744073709551615.0 | 0 AS c1; +c1 +18446744073709551615 +SELECT 18446744073709551615e0 | 0 AS c1; +c1 +18446744073709551615 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT ~18446744073709551615 AS c1; +c1 +0 +SELECT ~18446744073709551615.0 AS c1; +c1 +0 +SELECT ~18446744073709551615e0 AS c1; +c1 +0 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT BIT_COUNT(18446744073709551615) AS c1; +c1 +64 +SELECT BIT_COUNT(18446744073709551615.0) AS c1; +c1 +64 +SELECT BIT_COUNT(18446744073709551615e0) AS c1; +c1 +64 +Warnings: +Warning 1916 Got overflow when converting '18446744073709552000' to UNSIGNED INT. Value truncated +SELECT BIT_COUNT(-9223372036854775808) AS c1; +c1 +1 +SELECT BIT_COUNT(-9223372036854775808.0) AS c1; +c1 +1 +SELECT BIT_COUNT(-9223372036854775808e0) AS c1; +c1 +1 +Warnings: +Warning 1916 Got overflow when converting '-9223372036854776000' to INT. Value truncated +# +# End of 10.5 tests +# diff --git a/mysql-test/main/func_bit.test b/mysql-test/main/func_bit.test new file mode 100644 index 00000000000..e4f3189eafc --- /dev/null +++ b/mysql-test/main/func_bit.test @@ -0,0 +1,97 @@ +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-20305 Data loss on DOUBLE and DECIMAL conversion to INT +--echo # + +DELIMITER $$; +CREATE PROCEDURE p1(type VARCHAR(64), val VARCHAR(64)) +BEGIN + EXECUTE IMMEDIATE CONCAT('CREATE TABLE t1 (a ', type, ')'); + SHOW CREATE TABLE t1; + EXECUTE IMMEDIATE CONCAT('INSERT INTO t1 VALUES (', val, ')'); + SELECT + a, + ~a, + a & 18446744073709551615, + 18446744073709551615 & a, + 0 | a, + a | 0, + a << 0, + a >> 0, + a ^ 1, + 1 ^ a, + BIT_COUNT(a) + FROM t1; + SHOW WARNINGS; + DROP TABLE t1; +END; +$$ +DELIMITER ;$$ + +--vertical_results +CALL p1('BIGINT UNSIGNED', 18446744073709551615); +CALL p1('DOUBLE', 18446744073709551615); +CALL p1('DECIMAL(30,0)', 18446744073709551615); + +CALL p1('BIGINT', -1); +CALL p1('DOUBLE', -1); +CALL p1('DECIMAL(30,0)', -1); + +CALL p1('BIGINT', -9223372036854775808); +CALL p1('DOUBLE', -9223372036854775808); +CALL p1('DECIMAL(30,0)', -9223372036854775808); +--horizontal_results + +DROP PROCEDURE p1; + + +SELECT CAST(CAST(18446744073709551615 AS UNSIGNED) AS DECIMAL(32))<<0 AS c1; +SELECT CAST(CAST(18446744073709551615 AS UNSIGNED) AS DOUBLE)<<0 AS c1; + +SELECT COALESCE(CAST(CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED) AS DECIMAL(32))) << 0 AS c1; +SELECT COALESCE(CAST(CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED) AS DOUBLE)) << 0 AS c1; + +SELECT 18446744073709551615 ^ 1 AS c1; +SELECT 18446744073709551615.0 ^ 1 AS c1; +SELECT 18446744073709551615e0 ^ 1 AS c1; + +SELECT LAST_VALUE(18446744073709551615) ^ 1 AS c1; +SELECT LAST_VALUE(18446744073709551615.0) ^ 1 AS c1; +SELECT LAST_VALUE(18446744073709551615e0) ^ 1 AS c1; + +SELECT 18446744073709551615 & 18446744073709551615 AS c1; +SELECT 18446744073709551615 & 18446744073709551615.0 AS c1; +SELECT 18446744073709551615 & 18446744073709551615e0 AS c1; +SELECT 18446744073709551615.0 & 18446744073709551615 AS c1; +SELECT 18446744073709551615.0 & 18446744073709551615.0 AS c1; +SELECT 18446744073709551615.0 & 18446744073709551615e0 AS c1; +SELECT 18446744073709551615e0 & 18446744073709551615 AS c1; +SELECT 18446744073709551615e0 & 18446744073709551615.0 AS c1; +SELECT 18446744073709551615e0 & 18446744073709551615e0 AS c1; + + +SELECT 0 | 18446744073709551615 AS c1; +SELECT 0 | 18446744073709551615.0 AS c1; +SELECT 0 | 18446744073709551615e0 AS c1; +SELECT 18446744073709551615 | 0 AS c1; +SELECT 18446744073709551615.0 | 0 AS c1; +SELECT 18446744073709551615e0 | 0 AS c1; + +SELECT ~18446744073709551615 AS c1; +SELECT ~18446744073709551615.0 AS c1; +SELECT ~18446744073709551615e0 AS c1; + +SELECT BIT_COUNT(18446744073709551615) AS c1; +SELECT BIT_COUNT(18446744073709551615.0) AS c1; +SELECT BIT_COUNT(18446744073709551615e0) AS c1; + +SELECT BIT_COUNT(-9223372036854775808) AS c1; +SELECT BIT_COUNT(-9223372036854775808.0) AS c1; +SELECT BIT_COUNT(-9223372036854775808e0) AS c1; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/mysql-test/main/func_group.result b/mysql-test/main/func_group.result index 088ddf22e59..1fc92ba90cc 100644 --- a/mysql-test/main/func_group.result +++ b/mysql-test/main/func_group.result @@ -2326,7 +2326,7 @@ SELECT MAX('x') << 1, CAST(MAX('x') AS DOUBLE), CAST(MAX('x') AS DECIMAL); MAX('x') << 1 CAST(MAX('x') AS DOUBLE) CAST(MAX('x') AS DECIMAL) 0 0 0 Warnings: -Warning 1292 Truncated incorrect INTEGER value: 'x' +Warning 1292 Truncated incorrect DECIMAL value: 'x' Warning 1292 Truncated incorrect DOUBLE value: 'x' Warning 1292 Truncated incorrect DECIMAL value: 'x' # diff --git a/mysql-test/main/func_str.result b/mysql-test/main/func_str.result index 6fc61dc0f5f..992363c6b91 100644 --- a/mysql-test/main/func_str.result +++ b/mysql-test/main/func_str.result @@ -3071,7 +3071,7 @@ SELECT ((rpad(1.0,2048,1)) = ('4(') ^ (0.1)); ((rpad(1.0,2048,1)) = ('4(') ^ (0.1)) 0 Warnings: -Warning 1292 Truncated incorrect INTEGER value: '4(' +Warning 1292 Truncated incorrect DECIMAL value: '4(' SELECT pow((rpad(10.0,2048,1)),(b'1111111111111111111111111111111111111111111')); ERROR 22003: DOUBLE value is out of range in 'pow(rpad(10.0,2048,1),0x07ffffffffff)' @@ -3079,7 +3079,7 @@ SELECT ((rpad(1.0,2048,1)) + (0) ^ ('../')); ((rpad(1.0,2048,1)) + (0) ^ ('../')) 1.011111111111111 Warnings: -Warning 1292 Truncated incorrect INTEGER value: '../' +Warning 1292 Truncated incorrect DECIMAL value: '../' SELECT stddev_samp(rpad(1.0,2048,1)); stddev_samp(rpad(1.0,2048,1)) NULL diff --git a/mysql-test/main/func_time.result b/mysql-test/main/func_time.result index a9b27a15fa7..d44f634db08 100644 --- a/mysql-test/main/func_time.result +++ b/mysql-test/main/func_time.result @@ -2795,7 +2795,7 @@ SET sql_mode=DEFAULT; DO TO_DAYS(SEC_TO_TIME(TIME(CEILING(UUID())))); DO TO_DAYS(SEC_TO_TIME(MAKEDATE('',RAND(~(''))))); Warnings: -Warning 1292 Truncated incorrect INTEGER value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1292 Truncated incorrect INTEGER value: '' Warning 1292 Truncated incorrect seconds value: '20000101' SELECT SEC_TO_TIME(MAKEDATE(0,RAND(~0))); diff --git a/mysql-test/suite/engines/iuds/r/type_bit_iuds.result b/mysql-test/suite/engines/iuds/r/type_bit_iuds.result index 2c84abfd49d..93ed7a9f162 100644 --- a/mysql-test/suite/engines/iuds/r/type_bit_iuds.result +++ b/mysql-test/suite/engines/iuds/r/type_bit_iuds.result @@ -56209,9 +56209,9 @@ SELECT 0 + b'101010101010101010101010101010'; 715827882 SELECT 0 + (101010101010101010101010101010<<0); 0 + (101010101010101010101010101010<<0) -9223372036854775807 +18446744073709551615 Warnings: -Warning 1916 Got overflow when converting '101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(0)); CREATE TABLE t2(c1 BIT(0), c2 BIT(0), c3 BIT(0)); INSERT IGNORE INTO t1 VALUES (b'101010101010101010101010101010'); @@ -57001,7 +57001,7 @@ SELECT 0 + (101010101010101010101010101010<<1); 0 + (101010101010101010101010101010<<1) 18446744073709551614 Warnings: -Warning 1916 Got overflow when converting '101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(1)); CREATE TABLE t2(c1 BIT(1), c2 BIT(1), c3 BIT(1)); set @v1=1; @@ -57840,7 +57840,7 @@ SELECT 0 + (101010101010101010101010101010<<2); 0 + (101010101010101010101010101010<<2) 18446744073709551612 Warnings: -Warning 1916 Got overflow when converting '101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(2)); CREATE TABLE t2(c1 BIT(2), c2 BIT(2), c3 BIT(2)); set @v1=2; @@ -58698,7 +58698,7 @@ SELECT 0 + (101010101010101010101010101010<<4); 0 + (101010101010101010101010101010<<4) 18446744073709551600 Warnings: -Warning 1916 Got overflow when converting '101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(4)); CREATE TABLE t2(c1 BIT(4), c2 BIT(4), c3 BIT(4)); set @v1=4; @@ -59620,7 +59620,7 @@ SELECT 0 + (101010101010101010101010101010<<8); 0 + (101010101010101010101010101010<<8) 18446744073709551360 Warnings: -Warning 1916 Got overflow when converting '101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(8)); CREATE TABLE t2(c1 BIT(8), c2 BIT(8), c3 BIT(8)); set @v1=8; @@ -60827,7 +60827,7 @@ SELECT 0 + (101010101010101010101010101010<<16); 0 + (101010101010101010101010101010<<16) 18446744073709486080 Warnings: -Warning 1916 Got overflow when converting '101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(16)); CREATE TABLE t2(c1 BIT(16), c2 BIT(16), c3 BIT(16)); set @v1=16; @@ -62239,7 +62239,7 @@ SELECT 0 + (101010101010101010101010101010<<32); 0 + (101010101010101010101010101010<<32) 18446744069414584320 Warnings: -Warning 1916 Got overflow when converting '101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(32)); CREATE TABLE t2(c1 BIT(32), c2 BIT(32), c3 BIT(32)); set @v1=32; @@ -64312,7 +64312,7 @@ SELECT 0 + (101010101010101010101010101010<<64); 0 + (101010101010101010101010101010<<64) 0 Warnings: -Warning 1916 Got overflow when converting '101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(64)); CREATE TABLE t2(c1 BIT(64), c2 BIT(64), c3 BIT(64)); set @v1=64; @@ -67487,9 +67487,9 @@ Warnings: Note 1051 Unknown table 'test.t3' SELECT 0 + (1010101010101010101010101010101010101010101010101010101010101010<<0); 0 + (1010101010101010101010101010101010101010101010101010101010101010<<0) -9223372036854775807 +18446744073709551615 Warnings: -Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(0)); CREATE TABLE t2(c1 BIT(0), c2 BIT(0), c3 BIT(0)); INSERT IGNORE INTO t1 VALUES (b'1010101010101010101010101010101010101010101010101010101010101010'); @@ -68276,7 +68276,7 @@ SELECT 0 + (1010101010101010101010101010101010101010101010101010101010101010<<1) 0 + (1010101010101010101010101010101010101010101010101010101010101010<<1) 18446744073709551614 Warnings: -Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(1)); CREATE TABLE t2(c1 BIT(1), c2 BIT(1), c3 BIT(1)); set @v1=1; @@ -69112,7 +69112,7 @@ SELECT 0 + (1010101010101010101010101010101010101010101010101010101010101010<<2) 0 + (1010101010101010101010101010101010101010101010101010101010101010<<2) 18446744073709551612 Warnings: -Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(2)); CREATE TABLE t2(c1 BIT(2), c2 BIT(2), c3 BIT(2)); set @v1=2; @@ -69967,7 +69967,7 @@ SELECT 0 + (1010101010101010101010101010101010101010101010101010101010101010<<4) 0 + (1010101010101010101010101010101010101010101010101010101010101010<<4) 18446744073709551600 Warnings: -Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(4)); CREATE TABLE t2(c1 BIT(4), c2 BIT(4), c3 BIT(4)); set @v1=4; @@ -70886,7 +70886,7 @@ SELECT 0 + (1010101010101010101010101010101010101010101010101010101010101010<<8) 0 + (1010101010101010101010101010101010101010101010101010101010101010<<8) 18446744073709551360 Warnings: -Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(8)); CREATE TABLE t2(c1 BIT(8), c2 BIT(8), c3 BIT(8)); set @v1=8; @@ -72090,7 +72090,7 @@ SELECT 0 + (1010101010101010101010101010101010101010101010101010101010101010<<16 0 + (1010101010101010101010101010101010101010101010101010101010101010<<16) 18446744073709486080 Warnings: -Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(16)); CREATE TABLE t2(c1 BIT(16), c2 BIT(16), c3 BIT(16)); set @v1=16; @@ -73499,7 +73499,7 @@ SELECT 0 + (1010101010101010101010101010101010101010101010101010101010101010<<32 0 + (1010101010101010101010101010101010101010101010101010101010101010<<32) 18446744069414584320 Warnings: -Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(32)); CREATE TABLE t2(c1 BIT(32), c2 BIT(32), c3 BIT(32)); set @v1=32; @@ -75575,7 +75575,7 @@ SELECT 0 + (1010101010101010101010101010101010101010101010101010101010101010<<64 0 + (1010101010101010101010101010101010101010101010101010101010101010<<64) 0 Warnings: -Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to INT. Value truncated +Warning 1916 Got overflow when converting '1010101010101010101010101010101010101010101010101010101010101010' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(64)); CREATE TABLE t2(c1 BIT(64), c2 BIT(64), c3 BIT(64)); set @v1=64; @@ -78750,9 +78750,9 @@ Warnings: Note 1051 Unknown table 'test.t3' SELECT 0 + (10101010101010101010101010101010101010101010101010101010101010101<<0); 0 + (10101010101010101010101010101010101010101010101010101010101010101<<0) -9223372036854775807 +18446744073709551615 Warnings: -Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to INT. Value truncated +Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(0)); CREATE TABLE t2(c1 BIT(0), c2 BIT(0), c3 BIT(0)); INSERT IGNORE INTO t1 VALUES (b'10101010101010101010101010101010101010101010101010101010101010101'); @@ -79539,7 +79539,7 @@ SELECT 0 + (10101010101010101010101010101010101010101010101010101010101010101<<1 0 + (10101010101010101010101010101010101010101010101010101010101010101<<1) 18446744073709551614 Warnings: -Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to INT. Value truncated +Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(1)); CREATE TABLE t2(c1 BIT(1), c2 BIT(1), c3 BIT(1)); set @v1=1; @@ -80375,7 +80375,7 @@ SELECT 0 + (10101010101010101010101010101010101010101010101010101010101010101<<2 0 + (10101010101010101010101010101010101010101010101010101010101010101<<2) 18446744073709551612 Warnings: -Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to INT. Value truncated +Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(2)); CREATE TABLE t2(c1 BIT(2), c2 BIT(2), c3 BIT(2)); set @v1=2; @@ -81230,7 +81230,7 @@ SELECT 0 + (10101010101010101010101010101010101010101010101010101010101010101<<4 0 + (10101010101010101010101010101010101010101010101010101010101010101<<4) 18446744073709551600 Warnings: -Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to INT. Value truncated +Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(4)); CREATE TABLE t2(c1 BIT(4), c2 BIT(4), c3 BIT(4)); set @v1=4; @@ -82149,7 +82149,7 @@ SELECT 0 + (10101010101010101010101010101010101010101010101010101010101010101<<8 0 + (10101010101010101010101010101010101010101010101010101010101010101<<8) 18446744073709551360 Warnings: -Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to INT. Value truncated +Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(8)); CREATE TABLE t2(c1 BIT(8), c2 BIT(8), c3 BIT(8)); set @v1=8; @@ -83353,7 +83353,7 @@ SELECT 0 + (10101010101010101010101010101010101010101010101010101010101010101<<1 0 + (10101010101010101010101010101010101010101010101010101010101010101<<16) 18446744073709486080 Warnings: -Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to INT. Value truncated +Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(16)); CREATE TABLE t2(c1 BIT(16), c2 BIT(16), c3 BIT(16)); set @v1=16; @@ -84762,7 +84762,7 @@ SELECT 0 + (10101010101010101010101010101010101010101010101010101010101010101<<3 0 + (10101010101010101010101010101010101010101010101010101010101010101<<32) 18446744069414584320 Warnings: -Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to INT. Value truncated +Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(32)); CREATE TABLE t2(c1 BIT(32), c2 BIT(32), c3 BIT(32)); set @v1=32; @@ -86838,7 +86838,7 @@ SELECT 0 + (10101010101010101010101010101010101010101010101010101010101010101<<6 0 + (10101010101010101010101010101010101010101010101010101010101010101<<64) 0 Warnings: -Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to INT. Value truncated +Warning 1916 Got overflow when converting '10101010101010101010101010101010101010101010101010101010101010101' to UNSIGNED INT. Value truncated CREATE TABLE t1(c1 BIT(64)); CREATE TABLE t2(c1 BIT(64), c2 BIT(64), c3 BIT(64)); set @v1=64; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 7fe16848082..24914accc6f 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4733,43 +4733,73 @@ void Item_func_in::mark_as_condition_AND_part(TABLE_LIST *embedding) } -longlong Item_func_bit_or::val_int() +class Func_handler_bit_or_int_to_ulonglong: + public Item_handled_func::Handler_ulonglong { - DBUG_ASSERT(fixed == 1); - ulonglong arg1= (ulonglong) args[0]->val_int(); - if (args[0]->null_value) +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; /* purecov: inspected */ - return 0; /* purecov: inspected */ + DBUG_ASSERT(item->is_fixed()); + Longlong_null a= item->arguments()[0]->to_longlong_null(); + return a.is_null() ? a : a | item->arguments()[1]->to_longlong_null(); } - ulonglong arg2= (ulonglong) args[1]->val_int(); - if (args[1]->null_value) +}; + + +class Func_handler_bit_or_dec_to_ulonglong: + public Item_handled_func::Handler_ulonglong +{ +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; - return 0; + DBUG_ASSERT(item->is_fixed()); + VDec a(item->arguments()[0]); + return a.is_null() ? Longlong_null() : + a.to_xlonglong_null() | VDec(item->arguments()[1]).to_xlonglong_null(); } - null_value=0; - return (longlong) (arg1 | arg2); +}; + + +bool Item_func_bit_or::fix_length_and_dec() +{ + static Func_handler_bit_or_int_to_ulonglong ha_int_to_ull; + static Func_handler_bit_or_dec_to_ulonglong ha_dec_to_ull; + return fix_length_and_dec_op2_std(&ha_int_to_ull, &ha_dec_to_ull); } -longlong Item_func_bit_and::val_int() +class Func_handler_bit_and_int_to_ulonglong: + public Item_handled_func::Handler_ulonglong { - DBUG_ASSERT(fixed == 1); - ulonglong arg1= (ulonglong) args[0]->val_int(); - if (args[0]->null_value) +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; /* purecov: inspected */ - return 0; /* purecov: inspected */ + DBUG_ASSERT(item->is_fixed()); + Longlong_null a= item->arguments()[0]->to_longlong_null(); + return a.is_null() ? a : a & item->arguments()[1]->to_longlong_null(); } - ulonglong arg2= (ulonglong) args[1]->val_int(); - if (args[1]->null_value) +}; + + +class Func_handler_bit_and_dec_to_ulonglong: + public Item_handled_func::Handler_ulonglong +{ +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; /* purecov: inspected */ - return 0; /* purecov: inspected */ + DBUG_ASSERT(item->is_fixed()); + VDec a(item->arguments()[0]); + return a.is_null() ? Longlong_null() : + a.to_xlonglong_null() & VDec(item->arguments()[1]).to_xlonglong_null(); } - null_value=0; - return (longlong) (arg1 & arg2); +}; + + +bool Item_func_bit_and::fix_length_and_dec() +{ + static Func_handler_bit_and_int_to_ulonglong ha_int_to_ull; + static Func_handler_bit_and_dec_to_ulonglong ha_dec_to_ull; + return fix_length_and_dec_op2_std(&ha_int_to_ull, &ha_dec_to_ull); } Item_cond::Item_cond(THD *thd, Item_cond *item) diff --git a/sql/item_func.cc b/sql/item_func.cc index da185f9878b..c3deae59960 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2139,44 +2139,103 @@ double Item_func_cot::val_real() // Shift-functions, same as << and >> in C/C++ -longlong Item_func_shift_left::val_int() +class Func_handler_shift_left_int_to_ulonglong: + public Item_handled_func::Handler_ulonglong { - DBUG_ASSERT(fixed == 1); - uint shift; - ulonglong res= ((ulonglong) args[0]->val_int() << - (shift=(uint) args[1]->val_int())); - if (args[0]->null_value || args[1]->null_value) +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; - return 0; + DBUG_ASSERT(item->is_fixed()); + return item->arguments()[0]->to_longlong_null() << + item->arguments()[1]->to_longlong_null(); } - null_value=0; - return (shift < sizeof(longlong)*8 ? (longlong) res : 0); +}; + + +class Func_handler_shift_left_decimal_to_ulonglong: + public Item_handled_func::Handler_ulonglong +{ +public: + Longlong_null to_longlong_null(Item_handled_func *item) const + { + DBUG_ASSERT(item->is_fixed()); + return VDec(item->arguments()[0]).to_xlonglong_null() << + item->arguments()[1]->to_longlong_null(); + } +}; + + +bool Item_func_shift_left::fix_length_and_dec() +{ + static Func_handler_shift_left_int_to_ulonglong ha_int_to_ull; + static Func_handler_shift_left_decimal_to_ulonglong ha_dec_to_ull; + return fix_length_and_dec_op1_std(&ha_int_to_ull, &ha_dec_to_ull); } -longlong Item_func_shift_right::val_int() + +class Func_handler_shift_right_int_to_ulonglong: + public Item_handled_func::Handler_ulonglong { - DBUG_ASSERT(fixed == 1); - uint shift; - ulonglong res= (ulonglong) args[0]->val_int() >> - (shift=(uint) args[1]->val_int()); - if (args[0]->null_value || args[1]->null_value) +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; - return 0; + DBUG_ASSERT(item->fixed == 1); + return item->arguments()[0]->to_longlong_null() >> + item->arguments()[1]->to_longlong_null(); } - null_value=0; - return (shift < sizeof(longlong)*8 ? (longlong) res : 0); +}; + + +class Func_handler_shift_right_decimal_to_ulonglong: + public Item_handled_func::Handler_ulonglong +{ +public: + Longlong_null to_longlong_null(Item_handled_func *item) const + { + DBUG_ASSERT(item->is_fixed()); + return VDec(item->arguments()[0]).to_xlonglong_null() >> + item->arguments()[1]->to_longlong_null(); + } +}; + + +bool Item_func_shift_right::fix_length_and_dec() +{ + static Func_handler_shift_right_int_to_ulonglong ha_int_to_ull; + static Func_handler_shift_right_decimal_to_ulonglong ha_dec_to_ull; + return fix_length_and_dec_op1_std(&ha_int_to_ull, &ha_dec_to_ull); } -longlong Item_func_bit_neg::val_int() +class Func_handler_bit_neg_int_to_ulonglong: + public Item_handled_func::Handler_ulonglong { - DBUG_ASSERT(fixed == 1); - ulonglong res= (ulonglong) args[0]->val_int(); - if ((null_value=args[0]->null_value)) - return 0; - return ~res; +public: + Longlong_null to_longlong_null(Item_handled_func *item) const + { + DBUG_ASSERT(item->is_fixed()); + return ~ item->arguments()[0]->to_longlong_null(); + } +}; + + +class Func_handler_bit_neg_decimal_to_ulonglong: + public Item_handled_func::Handler_ulonglong +{ +public: + Longlong_null to_longlong_null(Item_handled_func *item) const + { + DBUG_ASSERT(item->is_fixed()); + return ~ VDec(item->arguments()[0]).to_xlonglong_null(); + } +}; + + +bool Item_func_bit_neg::fix_length_and_dec() +{ + static Func_handler_bit_neg_int_to_ulonglong ha_int_to_ull; + static Func_handler_bit_neg_decimal_to_ulonglong ha_dec_to_ull; + return fix_length_and_dec_op1_std(&ha_int_to_ull, &ha_dec_to_ull); } @@ -3199,13 +3258,39 @@ longlong Item_func_find_in_set::val_int() return 0; } -longlong Item_func_bit_count::val_int() + +class Func_handler_bit_count_int_to_slong: + public Item_handled_func::Handler_slong2 { - DBUG_ASSERT(fixed == 1); - ulonglong value= (ulonglong) args[0]->val_int(); - if ((null_value= args[0]->null_value)) - return 0; /* purecov: inspected */ - return (longlong) my_count_bits(value); +public: + Longlong_null to_longlong_null(Item_handled_func *item) const + { + DBUG_ASSERT(item->is_fixed()); + return item->arguments()[0]->to_longlong_null().bit_count(); + } +}; + + +class Func_handler_bit_count_decimal_to_slong: + public Item_handled_func::Handler_slong2 +{ +public: + Longlong_null to_longlong_null(Item_handled_func *item) const + { + DBUG_ASSERT(item->is_fixed()); + return VDec(item->arguments()[0]).to_xlonglong_null().bit_count(); + } +}; + + +bool Item_func_bit_count::fix_length_and_dec() +{ + static Func_handler_bit_count_int_to_slong ha_int_to_slong; + static Func_handler_bit_count_decimal_to_slong ha_dec_to_slong; + set_func_handler(args[0]->cmp_type() == INT_RESULT ? + (const Handler *) &ha_int_to_slong : + (const Handler *) &ha_dec_to_slong); + return m_func_handler->fix_length_and_dec(this); } @@ -6221,14 +6306,38 @@ void Item_func_match::print(String *str, enum_query_type query_type) str->append(STRING_WITH_LEN("))")); } -longlong Item_func_bit_xor::val_int() + +class Func_handler_bit_xor_int_to_ulonglong: + public Item_handled_func::Handler_ulonglong { - DBUG_ASSERT(fixed == 1); - ulonglong arg1= (ulonglong) args[0]->val_int(); - ulonglong arg2= (ulonglong) args[1]->val_int(); - if ((null_value= (args[0]->null_value || args[1]->null_value))) - return 0; - return (longlong) (arg1 ^ arg2); +public: + Longlong_null to_longlong_null(Item_handled_func *item) const + { + DBUG_ASSERT(item->is_fixed()); + return item->arguments()[0]->to_longlong_null() ^ + item->arguments()[1]->to_longlong_null(); + } +}; + + +class Func_handler_bit_xor_dec_to_ulonglong: + public Item_handled_func::Handler_ulonglong +{ +public: + Longlong_null to_longlong_null(Item_handled_func *item) const + { + DBUG_ASSERT(item->is_fixed()); + return VDec(item->arguments()[0]).to_xlonglong_null() ^ + VDec(item->arguments()[1]).to_xlonglong_null(); + } +}; + + +bool Item_func_bit_xor::fix_length_and_dec() +{ + static const Func_handler_bit_xor_int_to_ulonglong ha_int_to_ull; + static const Func_handler_bit_xor_dec_to_ulonglong ha_dec_to_ull; + return fix_length_and_dec_op2_std(&ha_int_to_ull, &ha_dec_to_ull); } diff --git a/sql/item_func.h b/sql/item_func.h index 3771992d617..ca72563581b 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -641,6 +641,87 @@ public: }; + class Handler_int: public Handler + { + public: + String *val_str(Item_handled_func *item, String *to) const + { + longlong nr= val_int(item); + if (item->null_value) + return 0; + to->set_int(nr, item->unsigned_flag, item->collation.collation); + return to; + } + String *val_str_ascii(Item_handled_func *item, String *to) const + { + return item->Item::val_str_ascii(to); + } + double val_real(Item_handled_func *item) const + { + return item->unsigned_flag ? (double) ((ulonglong) val_int(item)) : + (double) val_int(item); + } + my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const + { + return item->val_decimal_from_int(to); + } + bool get_date(THD *thd, Item_handled_func *item, + MYSQL_TIME *to, date_mode_t fuzzydate) const + { + return item->get_date_from_int(thd, to, fuzzydate); + } + longlong val_int(Item_handled_func *item) const + { + Longlong_null tmp= to_longlong_null(item); + item->null_value= tmp.is_null(); + return tmp.value(); + } + virtual Longlong_null to_longlong_null(Item_handled_func *item) const= 0; + }; + + class Handler_slong: public Handler_int + { + public: + const Type_handler *return_type_handler(const Item_handled_func *item) const + { + return &type_handler_slong; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + item->unsigned_flag= false; + item->collation= DTCollation_numeric(); + item->fix_char_length(11); + return false; + } + }; + + class Handler_slong2: public Handler_slong + { + public: + bool fix_length_and_dec(Item_handled_func *func) const + { + bool rc= Handler_slong::fix_length_and_dec(func); + func->max_length= 2; + return rc; + } + }; + + class Handler_ulonglong: public Handler_int + { + public: + const Type_handler *return_type_handler(const Item_handled_func *item) const + { + return &type_handler_ulonglong; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + item->unsigned_flag= true; + item->collation= DTCollation_numeric(); + item->fix_char_length(21); + return false; + } + }; + protected: const Handler *m_func_handler; public: @@ -2188,84 +2269,99 @@ public: /* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */ -class Item_func_bit: public Item_longlong_func +class Item_func_bit_operator: public Item_handled_func { bool check_arguments() const { return check_argument_types_can_return_int(0, arg_count); } +protected: + bool fix_length_and_dec_op1_std(const Handler *ha_int, const Handler *ha_dec) + { + set_func_handler(args[0]->cmp_type() == INT_RESULT ? ha_int : ha_dec); + return m_func_handler->fix_length_and_dec(this); + } + bool fix_length_and_dec_op2_std(const Handler *ha_int, const Handler *ha_dec) + { + set_func_handler(args[0]->cmp_type() == INT_RESULT && + args[1]->cmp_type() == INT_RESULT ? ha_int : ha_dec); + return m_func_handler->fix_length_and_dec(this); + } public: - Item_func_bit(THD *thd, Item *a, Item *b): Item_longlong_func(thd, a, b) {} - Item_func_bit(THD *thd, Item *a): Item_longlong_func(thd, a) {} - bool fix_length_and_dec() { unsigned_flag= 1; return FALSE; } - - virtual inline void print(String *str, enum_query_type query_type) + Item_func_bit_operator(THD *thd, Item *a) + :Item_handled_func(thd, a) {} + Item_func_bit_operator(THD *thd, Item *a, Item *b) + :Item_handled_func(thd, a, b) {} + void print(String *str, enum_query_type query_type) { print_op(str, query_type); } bool need_parentheses_in_default() { return true; } }; -class Item_func_bit_or :public Item_func_bit +class Item_func_bit_or :public Item_func_bit_operator { public: - Item_func_bit_or(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {} - longlong val_int(); + Item_func_bit_or(THD *thd, Item *a, Item *b) + :Item_func_bit_operator(thd, a, b) {} + bool fix_length_and_dec(); const char *func_name() const { return "|"; } enum precedence precedence() const { return BITOR_PRECEDENCE; } Item *get_copy(THD *thd) { return get_item_copy<Item_func_bit_or>(thd, this); } }; -class Item_func_bit_and :public Item_func_bit +class Item_func_bit_and :public Item_func_bit_operator { public: - Item_func_bit_and(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {} - longlong val_int(); + Item_func_bit_and(THD *thd, Item *a, Item *b) + :Item_func_bit_operator(thd, a, b) {} + bool fix_length_and_dec(); const char *func_name() const { return "&"; } enum precedence precedence() const { return BITAND_PRECEDENCE; } Item *get_copy(THD *thd) { return get_item_copy<Item_func_bit_and>(thd, this); } }; -class Item_func_bit_count :public Item_long_func +class Item_func_bit_count :public Item_handled_func { bool check_arguments() const { return args[0]->check_type_can_return_int(func_name()); } public: - Item_func_bit_count(THD *thd, Item *a): Item_long_func(thd, a) {} - longlong val_int(); + Item_func_bit_count(THD *thd, Item *a): Item_handled_func(thd, a) {} const char *func_name() const { return "bit_count"; } - bool fix_length_and_dec() { max_length=2; return FALSE; } + bool fix_length_and_dec(); Item *get_copy(THD *thd) { return get_item_copy<Item_func_bit_count>(thd, this); } }; -class Item_func_shift_left :public Item_func_bit +class Item_func_shift_left :public Item_func_bit_operator { public: - Item_func_shift_left(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {} - longlong val_int(); + Item_func_shift_left(THD *thd, Item *a, Item *b) + :Item_func_bit_operator(thd, a, b) {} + bool fix_length_and_dec(); const char *func_name() const { return "<<"; } enum precedence precedence() const { return SHIFT_PRECEDENCE; } Item *get_copy(THD *thd) { return get_item_copy<Item_func_shift_left>(thd, this); } }; -class Item_func_shift_right :public Item_func_bit +class Item_func_shift_right :public Item_func_bit_operator { public: - Item_func_shift_right(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {} - longlong val_int(); + Item_func_shift_right(THD *thd, Item *a, Item *b) + :Item_func_bit_operator(thd, a, b) {} + bool fix_length_and_dec(); const char *func_name() const { return ">>"; } enum precedence precedence() const { return SHIFT_PRECEDENCE; } Item *get_copy(THD *thd) { return get_item_copy<Item_func_shift_right>(thd, this); } }; -class Item_func_bit_neg :public Item_func_bit +class Item_func_bit_neg :public Item_func_bit_operator { public: - Item_func_bit_neg(THD *thd, Item *a): Item_func_bit(thd, a) {} - longlong val_int(); + Item_func_bit_neg(THD *thd, Item *a): Item_func_bit_operator(thd, a) {} + bool fix_length_and_dec(); const char *func_name() const { return "~"; } enum precedence precedence() const { return NEG_PRECEDENCE; } void print(String *str, enum_query_type query_type) @@ -3156,11 +3252,12 @@ private: }; -class Item_func_bit_xor : public Item_func_bit +class Item_func_bit_xor : public Item_func_bit_operator { public: - Item_func_bit_xor(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {} - longlong val_int(); + Item_func_bit_xor(THD *thd, Item *a, Item *b) + :Item_func_bit_operator(thd, a, b) {} + bool fix_length_and_dec(); const char *func_name() const { return "^"; } enum precedence precedence() const { return BITXOR_PRECEDENCE; } Item *get_copy(THD *thd) diff --git a/sql/my_decimal.h b/sql/my_decimal.h index a7f6fc9e88d..2db08bf01e3 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -195,6 +195,16 @@ public: return res; } longlong to_longlong(bool unsigned_flag) const; + /* + Return the value as a signed or unsigned longlong, depending on the sign. + - Positive values are returned as unsigned. + - Negative values are returned as signed. + This is used by bit SQL operators: | & ^ ~ + as well as by the SQL function BIT_COUNT(). + */ + longlong to_xlonglong() const + { return to_longlong(!sign()); } + // Convert to string returning decimal2string() error code int to_string_native(String *to, uint prec, uint dec, char filler, uint mask= E_DEC_FATAL_ERROR) const; diff --git a/sql/sql_type.h b/sql/sql_type.h index 2f1063a20f6..0850d08c5ae 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -338,6 +338,10 @@ public: double to_double() const { return m_ptr ? m_ptr->to_double() : 0.0; } longlong to_longlong(bool unsigned_flag) { return m_ptr ? m_ptr->to_longlong(unsigned_flag) : 0; } + Longlong_null to_xlonglong_null() + { + return m_ptr ? Longlong_null(m_ptr->to_xlonglong()) : Longlong_null(); + } bool to_bool() const { return m_ptr ? m_ptr->to_bool() : false; } String *to_string(String *to) const { diff --git a/sql/sql_type_int.h b/sql/sql_type_int.h index d3e9d0318cf..9fd4f0c46a0 100644 --- a/sql/sql_type_int.h +++ b/sql/sql_type_int.h @@ -16,6 +16,8 @@ #ifndef SQL_TYPE_INT_INCLUDED #define SQL_TYPE_INT_INCLUDED +#include "my_bit.h" // my_count_bits() + class Null_flag { @@ -43,6 +45,58 @@ public: Longlong_null(longlong nr, bool is_null) :Longlong(nr), Null_flag(is_null) { } + explicit Longlong_null() + :Longlong(0), Null_flag(true) + { } + explicit Longlong_null(longlong nr) + :Longlong(nr), Null_flag(false) + { } + Longlong_null operator|(const Longlong_null &other) const + { + if (is_null() || other.is_null()) + return Longlong_null(); + return Longlong_null(value() | other.value()); + } + Longlong_null operator&(const Longlong_null &other) const + { + if (is_null() || other.is_null()) + return Longlong_null(); + return Longlong_null(value() & other.value()); + } + Longlong_null operator^(const Longlong_null &other) const + { + if (is_null() || other.is_null()) + return Longlong_null(); + return Longlong_null((longlong) (value() ^ other.value())); + } + Longlong_null operator~() const + { + if (is_null()) + return *this; + return Longlong_null((longlong) ~ (ulonglong) value()); + } + Longlong_null operator<<(const Longlong_null &llshift) const + { + if (is_null() || llshift.is_null()) + return Longlong_null(); + uint shift= (uint) llshift.value(); + ulonglong res= ((ulonglong) value()) << shift; + return Longlong_null(shift < sizeof(longlong) * 8 ? (longlong) res : 0); + } + Longlong_null operator>>(const Longlong_null &llshift) const + { + if (is_null() || llshift.is_null()) + return Longlong_null(); + uint shift= (uint) llshift.value(); + ulonglong res= ((ulonglong) value()) >> shift; + return Longlong_null(shift < sizeof(longlong) * 8 ? (longlong) res : 0); + } + Longlong_null bit_count() const + { + if (is_null()) + return *this; + return Longlong_null((longlong) my_count_bits((ulonglong) value())); + } }; |