From 09b87d6293b4b41321ba98366d5d7ade9ad681d3 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 30 Sep 2015 10:05:16 +0400 Subject: [PATCH] MDEV-8871 Wrong result for CREATE TABLE .. SELECT LEAST(unsigned_column,unsigned_column) --- mysql-test/r/func_test.result | 39 +++++++++++++++++++++++++++++++++++ mysql-test/t/func_test.test | 18 ++++++++++++++++ sql/item_func.cc | 25 ++++++++++++++++++++-- 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index af52a2b9149..387b8545f59 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -377,5 +377,44 @@ id k c pad 7 16 a xxx DROP TABLE t1; # +# MDEV-8871 Wrong result for CREATE TABLE .. SELECT LEAST(unsigned_column,unsigned_column) +# +CREATE TABLE t1 (a INT,b INT UNSIGNED); +INSERT INTO t1 VALUES (-2147483648,4294967295); +SELECT a, b, LEAST(a,a), LEAST(b,b), LEAST(a,b), LEAST(b,a), GREATEST(a,b), GREATEST(b,a) FROM t1; +a -2147483648 +b 4294967295 +LEAST(a,a) -2147483648 +LEAST(b,b) 4294967295 +LEAST(a,b) -2147483648 +LEAST(b,a) -2147483648 +GREATEST(a,b) 4294967295 +GREATEST(b,a) 4294967295 +CREATE TABLE t2 AS +SELECT a, b, LEAST(a,a), LEAST(b,b), LEAST(a,b), LEAST(b,a), GREATEST(a,b), GREATEST(b,a) FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) DEFAULT NULL, + `b` int(10) unsigned DEFAULT NULL, + `LEAST(a,a)` int(11) DEFAULT NULL, + `LEAST(b,b)` int(10) unsigned DEFAULT NULL, + `LEAST(a,b)` decimal(10,0) DEFAULT NULL, + `LEAST(b,a)` decimal(10,0) DEFAULT NULL, + `GREATEST(a,b)` decimal(10,0) DEFAULT NULL, + `GREATEST(b,a)` decimal(10,0) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t2; +a -2147483648 +b 4294967295 +LEAST(a,a) -2147483648 +LEAST(b,b) 4294967295 +LEAST(a,b) -2147483648 +LEAST(b,a) -2147483648 +GREATEST(a,b) 4294967295 +GREATEST(b,a) 4294967295 +DROP TABLE t2; +DROP TABLE t1; +# # End of 10.1 tests # diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index 82e421dcb6b..b7bca957e5b 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -220,6 +220,24 @@ SELECT * FROM t1 WHERE id XOR 0; SELECT * FROM t1 IGNORE KEY(PRIMARY) WHERE id XOR 0; DROP TABLE t1; +--echo # +--echo # MDEV-8871 Wrong result for CREATE TABLE .. SELECT LEAST(unsigned_column,unsigned_column) +--echo # +CREATE TABLE t1 (a INT,b INT UNSIGNED); +INSERT INTO t1 VALUES (-2147483648,4294967295); +--vertical_results +SELECT a, b, LEAST(a,a), LEAST(b,b), LEAST(a,b), LEAST(b,a), GREATEST(a,b), GREATEST(b,a) FROM t1; +--horizontal_results +CREATE TABLE t2 AS +SELECT a, b, LEAST(a,a), LEAST(b,b), LEAST(a,b), LEAST(b,a), GREATEST(a,b), GREATEST(b,a) FROM t1; +SHOW CREATE TABLE t2; +--vertical_results +SELECT * FROM t2; +--horizontal_results +DROP TABLE t2; +DROP TABLE t1; + + --echo # --echo # End of 10.1 tests --echo # diff --git a/sql/item_func.cc b/sql/item_func.cc index ea1710ecc24..711d23d9b15 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2823,11 +2823,13 @@ double Item_func_units::val_real() void Item_func_min_max::fix_length_and_dec() { + uint unsigned_count= 0; int max_int_part=0; decimals=0; max_length=0; maybe_null=0; thd= current_thd; + compare_as_dates= find_date_time_item(args, arg_count, 0); cmp_type=args[0]->result_type(); for (uint i=0 ; i < arg_count ; i++) @@ -2835,14 +2837,34 @@ void Item_func_min_max::fix_length_and_dec() set_if_bigger(max_length, args[i]->max_length); set_if_bigger(decimals, args[i]->decimals); set_if_bigger(max_int_part, args[i]->decimal_int_part()); + unsigned_count+= args[i]->unsigned_flag; if (args[i]->maybe_null) maybe_null= 1; cmp_type= item_cmp_type(cmp_type,args[i]->result_type()); } + unsigned_flag= unsigned_count == arg_count; // if all args are unsigned if (cmp_type == STRING_RESULT) agg_arg_charsets_for_string_result_with_comparison(collation, args, arg_count); - else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT)) + else if (cmp_type == INT_RESULT) + { + collation.set_numeric(); + fix_char_length(my_decimal_precision_to_length_no_truncation(max_int_part + + decimals, + decimals, + unsigned_flag)); + if (unsigned_count != 0 && unsigned_count != arg_count) + { + /* + If all args are of INT-alike type, but have different unsigned_flag, + then change type to DECIMAL. + */ + cmp_type= DECIMAL_RESULT; + cached_field_type= MYSQL_TYPE_NEWDECIMAL; + return; + } + } + else if (cmp_type == DECIMAL_RESULT) { collation.set_numeric(); fix_char_length(my_decimal_precision_to_length_no_truncation(max_int_part + @@ -2853,7 +2875,6 @@ void Item_func_min_max::fix_length_and_dec() else if (cmp_type == REAL_RESULT) fix_char_length(float_length(decimals)); - compare_as_dates= find_date_time_item(args, arg_count, 0); if (compare_as_dates) { cached_field_type= compare_as_dates->field_type();