diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index cf358e6a404..7154c689783 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -200,3 +200,10 @@ CEMPNUM EMPMUM1 EMPNUM2 0.00 0 0.00 2.00 2 NULL DROP TABLE t1,t2; +SELECT CASE 1 WHEN 1 THEN 18446744073709551615 ELSE 1 END; +CASE 1 WHEN 1 THEN 18446744073709551615 ELSE 1 END +18446744073709551615 +SELECT COALESCE(18446744073709551615); +COALESCE(18446744073709551615) +18446744073709551615 +End of 4.1 tests diff --git a/mysql-test/r/func_if.result b/mysql-test/r/func_if.result index eef380c8f52..59f8db93084 100644 --- a/mysql-test/r/func_if.result +++ b/mysql-test/r/func_if.result @@ -128,3 +128,10 @@ f1 f2 if(f1, 40.0, 5.00) 0 0 5.00 1 1 40.00 drop table t1; +SELECT IF(1 != 0, 18446744073709551615, 1); +IF(1 != 0, 18446744073709551615, 1) +18446744073709551615 +SELECT IFNULL(NULL, 18446744073709551615); +IFNULL(NULL, 18446744073709551615) +18446744073709551615 +End of 4.1 tests diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index d9437f6c515..4543988a845 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -204,3 +204,10 @@ NULL SELECT GREATEST(1.5E+2,1.3E+2,NULL) FROM DUAL; GREATEST(1.5E+2,1.3E+2,NULL) NULL +SELECT GREATEST(1, 18446744073709551615); +GREATEST(1, 18446744073709551615) +18446744073709551615 +SELECT LEAST(1, 18446744073709551615); +LEAST(1, 18446744073709551615) +1 +End of 4.1 tests diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 1664a907c99..2b9ec8e2164 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -301,3 +301,4 @@ select @var; @var 3 drop table t1; +End of 4.1 tests diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index fbe1ee2b8c8..a22b9cc39f1 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -133,8 +133,6 @@ select min(a), min(case when 1=1 then a else NULL end), from t1 where b=3 group by b; drop table t1; -# End of 4.1 tests - # # Tests for bug #9939: conversion of the arguments for COALESCE and IFNULL @@ -154,3 +152,12 @@ SELECT IFNULL(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; DROP TABLE t1,t2; +# +# Bug #20924: CAST(expr as UNSIGNED) returns SIGNED value when used in various +# functions +# - UNSIGNED values in CASE and COALESCE are treated as SIGNED +# +SELECT CASE 1 WHEN 1 THEN 18446744073709551615 ELSE 1 END; +SELECT COALESCE(18446744073709551615); + +--echo End of 4.1 tests diff --git a/mysql-test/t/func_if.test b/mysql-test/t/func_if.test index beaa371f847..553387b9d42 100644 --- a/mysql-test/t/func_if.test +++ b/mysql-test/t/func_if.test @@ -97,3 +97,18 @@ create table t1 (f1 int, f2 int); insert into t1 values(1,1),(0,0); select f1, f2, if(f1, 40.0, 5.00) from t1 group by f1 order by f2; drop table t1; +# +# Bug #20924: CAST(expr as UNSIGNED) returns SIGNED value when used in various +# functions +# - UNSIGNED values in IF() are treated as SIGNED +# +SELECT IF(1 != 0, 18446744073709551615, 1); + +# +# Bug #20924: CAST(expr as UNSIGNED) returns SIGNED value when used in various +# functions +# - UNSIGNED values in IFNULL() are treated as SIGNED +# +SELECT IFNULL(NULL, 18446744073709551615); + +--echo End of 4.1 tests diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index f2ff47704c9..83432dcc7fc 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -108,8 +108,6 @@ select 5.1 mod 3, 5.1 mod -3, -5.1 mod 3, -5.1 mod -3; select 5 mod 3, 5 mod -3, -5 mod 3, -5 mod -3; -# End of 4.1 tests - # # Bug#6726: NOT BETWEEN parse failure # @@ -127,3 +125,13 @@ SELECT GREATEST(1,NULL) FROM DUAL; SELECT LEAST('xxx','aaa',NULL,'yyy') FROM DUAL; SELECT LEAST(1.1,1.2,NULL,1.0) FROM DUAL; SELECT GREATEST(1.5E+2,1.3E+2,NULL) FROM DUAL; + +# +# Bug #20924: CAST(expr as UNSIGNED) returns SIGNED value when used in various +# functions +# - UNSIGNED values in GREATEST() and LEAST() are treated as SIGNED +# +SELECT GREATEST(1, 18446744073709551615); +SELECT LEAST(1, 18446744073709551615); + +--echo End of 4.1 tests diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index b2a9728de00..192a92fc660 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -144,8 +144,6 @@ select @@version; --replace_column 1 # select @@global.version; -# End of 4.1 tests - # # Bug #6598: problem with cast(NULL as signed integer); # @@ -212,3 +210,5 @@ insert into t1 values (1,2),(2,3),(3,1); select @var:=f2 from t1 group by f1 order by f2 desc limit 1; select @var; drop table t1; + +--echo End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 919a23ed65d..756754dde3c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -730,11 +730,7 @@ int Arg_comparator::compare_int_signed_unsigned() if (!(*b)->null_value) { owner->null_value= 0; - if (sval1 < 0 || (ulonglong)sval1 < uval2) - return -1; - if ((ulonglong)sval1 == uval2) - return 0; - return 1; + return ::compare_int_signed_unsigned(sval1, uval2); } } owner->null_value= 1; @@ -755,13 +751,7 @@ int Arg_comparator::compare_int_unsigned_signed() if (!(*b)->null_value) { owner->null_value= 0; - if (sval2 < 0) - return 1; - if (uval1 < (ulonglong)sval2) - return -1; - if (uval1 == (ulonglong)sval2) - return 0; - return 1; + return ::compare_int_unsigned_signed(uval1, sval2); } } owner->null_value= 1; @@ -1402,11 +1392,13 @@ Item_func_ifnull::int_op() if (!args[0]->null_value) { null_value=0; + unsigned_flag= args[0]->unsigned_flag; return value; } value=args[1]->val_int(); if ((null_value=args[1]->null_value)) return 0; + unsigned_flag= args[1]->unsigned_flag; return value; } @@ -1557,6 +1549,7 @@ Item_func_if::val_int() Item *arg= args[0]->val_bool() ? args[1] : args[2]; longlong value=arg->val_int(); null_value=arg->null_value; + unsigned_flag= arg->unsigned_flag; return value; } @@ -1805,6 +1798,7 @@ longlong Item_func_case::val_int() } res=item->val_int(); null_value=item->null_value; + unsigned_flag= item->unsigned_flag; return res; } @@ -1991,7 +1985,10 @@ longlong Item_func_coalesce::int_op() { longlong res=args[i]->val_int(); if (!args[i]->null_value) + { + unsigned_flag= args[i]->unsigned_flag; return res; + } } null_value=1; return 0; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 47f9f2aa98f..544f1470d9a 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1396,3 +1396,17 @@ inline Item *and_conds(Item *a, Item *b) } Item *and_expressions(Item *a, Item *b, Item **org_item); + +inline int compare_int_signed_unsigned(longlong sval, ulonglong uval) +{ + if (sval < 0 || (ulonglong)sval < uval) + return -1; + if ((ulonglong)sval == uval) + return 0; + return 1; +} + +inline int compare_int_unsigned_signed(ulonglong uval, longlong sval) +{ + return -compare_int_signed_unsigned(sval, uval); +} diff --git a/sql/item_func.cc b/sql/item_func.cc index 579e7f88ee6..4d9893e1bbd 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2152,18 +2152,33 @@ longlong Item_func_min_max::val_int() { DBUG_ASSERT(fixed == 1); longlong value=0; + my_bool arg_unsigned_flag; + my_bool cmp; for (uint i=0; i < arg_count ; i++) { - if (i == 0) - value=args[i]->val_int(); - else - { - longlong tmp=args[i]->val_int(); - if (!args[i]->null_value && (tmp < value ? cmp_sign : -cmp_sign) > 0) - value=tmp; - } + longlong tmp= args[i]->val_int(); if ((null_value= args[i]->null_value)) break; + arg_unsigned_flag= args[i]->unsigned_flag; + if (i == 0) + { + value= tmp; + unsigned_flag= arg_unsigned_flag; + } + else + { + if (unsigned_flag == arg_unsigned_flag) + cmp= tmp < value; + else if (unsigned_flag) + cmp= compare_int_signed_unsigned(tmp, value) < 0; + else + cmp= compare_int_unsigned_signed(tmp, value) < 0; + if ((cmp ? cmp_sign : -cmp_sign) > 0) + { + value= tmp; + unsigned_flag= arg_unsigned_flag; + } + } } return value; } @@ -3799,7 +3814,7 @@ Item_func_set_user_var::update() case REAL_RESULT: { res= update_hash((void*) &save_result.vreal,sizeof(save_result.vreal), - REAL_RESULT, &my_charset_bin, DERIVATION_IMPLICIT); + REAL_RESULT, &my_charset_bin, DERIVATION_IMPLICIT, 0); break; } case INT_RESULT: @@ -3813,23 +3828,23 @@ Item_func_set_user_var::update() { if (!save_result.vstr) // Null value res= update_hash((void*) 0, 0, STRING_RESULT, &my_charset_bin, - DERIVATION_IMPLICIT); + DERIVATION_IMPLICIT, 0); else res= update_hash((void*) save_result.vstr->ptr(), save_result.vstr->length(), STRING_RESULT, save_result.vstr->charset(), - DERIVATION_IMPLICIT); + DERIVATION_IMPLICIT, 0); break; } case DECIMAL_RESULT: { if (!save_result.vdec) // Null value res= update_hash((void*) 0, 0, DECIMAL_RESULT, &my_charset_bin, - DERIVATION_IMPLICIT); + DERIVATION_IMPLICIT, 0); else res= update_hash((void*) save_result.vdec, sizeof(my_decimal), DECIMAL_RESULT, - &my_charset_bin, DERIVATION_IMPLICIT); + &my_charset_bin, DERIVATION_IMPLICIT, 0); break; } case ROW_RESULT: diff --git a/sql/item_func.h b/sql/item_func.h index c15b0b854b0..8abf5d91cd5 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1173,7 +1173,7 @@ public: String *val_str(String *str); my_decimal *val_decimal(my_decimal *); bool update_hash(void *ptr, uint length, enum Item_result type, - CHARSET_INFO *cs, Derivation dv, bool unsigned_arg= 0); + CHARSET_INFO *cs, Derivation dv, bool unsigned_arg); bool send(Protocol *protocol, String *str_arg); void make_field(Send_field *tmp_field); bool check(bool use_result_field); diff --git a/sql/log_event.cc b/sql/log_event.cc index cf5dbb1e77c..219434ab218 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3846,7 +3846,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) a single record and with a single column. Thus, like a column value, it could always have IMPLICIT derivation. */ - e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT); + e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0); free_root(thd->mem_root,0); rli->inc_event_relay_log_pos();