From a079f20aa80b56c5821d8b43bb102b8ca37dfbad Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Mon, 22 Jan 2007 14:52:23 +0400 Subject: [PATCH] Fix for bug #22026: Warning when using IF statement and large unsigned bigint We use INT_RESULT type if all arguments are of type INT for 'if', 'case', 'coalesce' functions regardless of arguments' unsigned flag, so sometimes we can exceed the INT bounds. --- mysql-test/r/select.result | 30 ++++++++++++++++++++++++++++++ mysql-test/t/select.test | 24 ++++++++++++++++++++++++ sql/item_cmpfunc.cc | 12 +++++++++--- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index d31be4390f7..d41b6d7ceec 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3634,3 +3634,33 @@ INSERT into t1 values (1), (2), (3); SELECT * FROM t1 LIMIT 2, -1; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1' at line 1 DROP TABLE t1; +create table t1 (a bigint unsigned); +insert into t1 values +(if(1, 9223372036854775808, 1)), +(case when 1 then 9223372036854775808 else 1 end), +(coalesce(9223372036854775808, 1)); +select * from t1; +a +9223372036854775808 +9223372036854775808 +9223372036854775808 +drop table t1; +create table t1 select +if(1, 9223372036854775808, 1) i, +case when 1 then 9223372036854775808 else 1 end c, +coalesce(9223372036854775808, 1) co; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` decimal(19,0) NOT NULL default '0', + `c` decimal(19,0) NOT NULL default '0', + `co` decimal(19,0) NOT NULL default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +select +if(1, cast(1111111111111111111 as unsigned), 1) i, +case when 1 then cast(1111111111111111111 as unsigned) else 1 end c, +coalesce(cast(1111111111111111111 as unsigned), 1) co; +i c co +1111111111111111111 1111111111111111111 1111111111111111111 +End of 5.0 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index e8d864b81f9..93174892714 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3123,3 +3123,27 @@ SELECT * FROM t1 LIMIT 2, -1; DROP TABLE t1; +# +# Bug #22026: Warning when using IF statement and large unsigned bigint +# + +create table t1 (a bigint unsigned); +insert into t1 values + (if(1, 9223372036854775808, 1)), + (case when 1 then 9223372036854775808 else 1 end), + (coalesce(9223372036854775808, 1)); +select * from t1; +drop table t1; +create table t1 select + if(1, 9223372036854775808, 1) i, + case when 1 then 9223372036854775808 else 1 end c, + coalesce(9223372036854775808, 1) co; +show create table t1; +drop table t1; +# Ensure we handle big values properly +select + if(1, cast(1111111111111111111 as unsigned), 1) i, + case when 1 then cast(1111111111111111111 as unsigned) else 1 end c, + coalesce(cast(1111111111111111111 as unsigned), 1) co; + +--echo End of 5.0 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 936ae04e93d..f4b99e19864 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -26,13 +26,17 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item); -static Item_result item_store_type(Item_result a,Item_result b) +static Item_result item_store_type(Item_result a, Item *item, + my_bool unsigned_flag) { + Item_result b= item->result_type(); + if (a == STRING_RESULT || b == STRING_RESULT) return STRING_RESULT; else if (a == REAL_RESULT || b == REAL_RESULT) return REAL_RESULT; - else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT) + else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT || + unsigned_flag != item->unsigned_flag) return DECIMAL_RESULT; else return INT_RESULT; @@ -41,6 +45,7 @@ static Item_result item_store_type(Item_result a,Item_result b) static void agg_result_type(Item_result *type, Item **items, uint nitems) { Item **item, **item_end; + my_bool unsigned_flag= 0; *type= STRING_RESULT; /* Skip beginning NULL items */ @@ -49,6 +54,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) if ((*item)->type() != Item::NULL_ITEM) { *type= (*item)->result_type(); + unsigned_flag= (*item)->unsigned_flag; item++; break; } @@ -57,7 +63,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) for (; item < item_end; item++) { if ((*item)->type() != Item::NULL_ITEM) - *type= item_store_type(type[0], (*item)->result_type()); + *type= item_store_type(*type, *item, unsigned_flag); } }