From 9ebf7944e36df42ea5bb61b34e32c8af0f4bc909 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 9 Jun 2006 19:35:54 +0200 Subject: [PATCH] Bug #7498 User variable SET saves SIGNED BIGINT as UNSIGNED BIGINT - Add unsigned flag to user_var_entry, used when 'type' is INT_RESULT - Propagate unsigned flag from the query executed by Item_single_row_subselect --- mysql-test/r/user_var.result | 36 ++++++++++++++++++++++++++++++++++++ mysql-test/t/user_var.test | 31 +++++++++++++++++++++++++++++++ sql/item_func.cc | 24 +++++++++++++++++------- sql/item_func.h | 6 ++---- sql/item_subselect.cc | 1 + sql/sql_class.h | 1 + 6 files changed, 88 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 7439f9132fb..3a197cd2a47 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -256,3 +256,39 @@ t1 CREATE TABLE `t1` ( `@first_var` longtext ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +set @a=18446744071710965857; +select @a; +@a +18446744071710965857 +CREATE TABLE `bigfailure` ( +`afield` BIGINT UNSIGNED NOT NULL +); +INSERT INTO `bigfailure` VALUES (18446744071710965857); +SELECT * FROM bigfailure; +afield +18446744071710965857 +select * from (SELECT afield FROM bigfailure) as b; +afield +18446744071710965857 +select * from bigfailure where afield = (SELECT afield FROM bigfailure); +afield +18446744071710965857 +select * from bigfailure where afield = 18446744071710965857; +afield +18446744071710965857 +select * from bigfailure where afield = 18446744071710965856+1; +afield +18446744071710965857 +SET @a := (SELECT afield FROM bigfailure); +SELECT @a; +@a +18446744071710965857 +SET @a := (select afield from (SELECT afield FROM bigfailure) as b); +SELECT @a; +@a +18446744071710965857 +SET @a := (select * from bigfailure where afield = (SELECT afield FROM bigfailure)); +SELECT @a; +@a +18446744071710965857 +drop table bigfailure; diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index e1b23a1782f..58c52b59a5a 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -171,3 +171,34 @@ set @first_var= cast(NULL as CHAR); create table t1 select @first_var; show create table t1; drop table t1; + +# +# Bug #7498 User variable SET saves SIGNED BIGINT as UNSIGNED BIGINT +# + +# First part, set user var to large number and select it +set @a=18446744071710965857; +select @a; + +# Second part, set user var from large number in table +# then select it +CREATE TABLE `bigfailure` ( + `afield` BIGINT UNSIGNED NOT NULL +); +INSERT INTO `bigfailure` VALUES (18446744071710965857); +SELECT * FROM bigfailure; +select * from (SELECT afield FROM bigfailure) as b; +select * from bigfailure where afield = (SELECT afield FROM bigfailure); +select * from bigfailure where afield = 18446744071710965857; +# This is fixed in 5.0, to be uncommented there +#select * from bigfailure where afield = '18446744071710965857'; +select * from bigfailure where afield = 18446744071710965856+1; + +SET @a := (SELECT afield FROM bigfailure); +SELECT @a; +SET @a := (select afield from (SELECT afield FROM bigfailure) as b); +SELECT @a; +SET @a := (select * from bigfailure where afield = (SELECT afield FROM bigfailure)); +SELECT @a; + +drop table bigfailure; diff --git a/sql/item_func.cc b/sql/item_func.cc index 6ec74560b91..7450451b0d0 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3408,6 +3408,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, entry->length=0; entry->update_query_id=0; entry->collation.set(NULL, DERIVATION_IMPLICIT); + entry->unsigned_flag= 0; /* If we are here, we were called from a SET or a query which sets a variable. Imagine it is this: @@ -3494,6 +3495,7 @@ Item_func_set_user_var::fix_length_and_dec() type - type of new value cs - charset info for new value dv - derivation for new value + unsigned_arg - indiates if a value of type INT_RESULT is unsigned RETURN VALUE False - success, True - failure @@ -3501,7 +3503,8 @@ Item_func_set_user_var::fix_length_and_dec() static bool update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, - Item_result type, CHARSET_INFO *cs, Derivation dv) + Item_result type, CHARSET_INFO *cs, Derivation dv, + bool unsigned_arg) { if (set_null) { @@ -3549,6 +3552,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, ((my_decimal*)entry->value)->fix_buffer_pointer(); entry->length= length; entry->collation.set(cs, dv); + entry->unsigned_flag= unsigned_arg; } entry->type=type; return 0; @@ -3557,7 +3561,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, bool Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type, - CHARSET_INFO *cs, Derivation dv) + CHARSET_INFO *cs, Derivation dv, + bool unsigned_arg) { /* If we set a variable explicitely to NULL then keep the old @@ -3566,7 +3571,7 @@ Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type, if ((null_value= args[0]->null_value) && null_item) type= entry->type; // Don't change type of item if (::update_hash(entry, (null_value= args[0]->null_value), - ptr, length, type, cs, dv)) + ptr, length, type, cs, dv, unsigned_arg)) { current_thd->fatal_error(); // Probably end of memory null_value= 1; @@ -3648,7 +3653,10 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, str->set(*(double*) value, decimals, &my_charset_bin); break; case INT_RESULT: - str->set(*(longlong*) value, &my_charset_bin); + if (!unsigned_flag) + str->set(*(longlong*) value, &my_charset_bin); + else + str->set(*(ulonglong*) value, &my_charset_bin); break; case DECIMAL_RESULT: my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str); @@ -3719,6 +3727,7 @@ Item_func_set_user_var::check() case INT_RESULT: { save_result.vint= args[0]->val_int(); + unsigned_flag= args[0]->unsigned_flag; break; } case STRING_RESULT: @@ -3774,7 +3783,8 @@ Item_func_set_user_var::update() case INT_RESULT: { res= update_hash((void*) &save_result.vint, sizeof(save_result.vint), - INT_RESULT, &my_charset_bin, DERIVATION_IMPLICIT); + INT_RESULT, &my_charset_bin, DERIVATION_IMPLICIT, + unsigned_flag); break; } case STRING_RESULT: @@ -4141,7 +4151,7 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs) { if (::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs, - DERIVATION_IMPLICIT)) + DERIVATION_IMPLICIT, 0 /* unsigned_arg */)) current_thd->fatal_error(); // Probably end of memory } @@ -4150,7 +4160,7 @@ void Item_user_var_as_out_param::set_value(const char *str, uint length, CHARSET_INFO* cs) { if (::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs, - DERIVATION_IMPLICIT)) + DERIVATION_IMPLICIT, 0 /* unsigned_arg */)) current_thd->fatal_error(); // Probably end of memory } diff --git a/sql/item_func.h b/sql/item_func.h index a91d93be8c6..8f90626ad26 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1154,8 +1154,6 @@ class Item_func_set_user_var :public Item_func String *vstr; my_decimal *vdec; } save_result; - String save_buff; - public: LEX_STRING name; // keep it public @@ -1166,8 +1164,8 @@ public: longlong val_int(); 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 update_hash(void *ptr, uint length, enum Item_result type, + CHARSET_INFO *cs, Derivation dv, bool unsigned_arg= 0); bool check(); bool update(); enum Item_result result_type () const { return cached_result_type; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index d93f6501ebb..4e6b168c9e9 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1497,6 +1497,7 @@ static Item_result set_row(List &item_list, Item *item, item->max_length= sel_item->max_length; res_type= sel_item->result_type(); item->decimals= sel_item->decimals; + item->unsigned_flag= sel_item->unsigned_flag; *maybe_null= sel_item->maybe_null; if (!(row[i]= Item_cache::get_cache(res_type))) return STRING_RESULT; // we should return something diff --git a/sql/sql_class.h b/sql/sql_class.h index 0ddba0e6f05..be13084b1ea 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1954,6 +1954,7 @@ class user_var_entry ulong length; query_id_t update_query_id, used_query_id; Item_result type; + bool unsigned_flag; double val_real(my_bool *null_value); longlong val_int(my_bool *null_value);