Commit 0a4faecb authored by unknown's avatar unknown

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:
  Update test results
mysql-test/t/user_var.test:
  Add test case
sql/item_func.cc:
  Add unsigned_flag to user_var_entry. Used when 'type' is INT_RESULT
  Pass unsigned_flag to 'update_hash' if type is INT_RESULT
sql/item_func.h:
  Removed unused variable save_buff
  Add parameter unsigned_arg to 'update_hash'
sql/item_subselect.cc:
  Propagate unsigned_flag to Item_singlerow_subselect from the items in the select to the cached items.
sql/sql_class.h:
  Add unsigned_flag to user_var_entry. Used when 'type' is INT_RESULT
parent 8d5280cf
...@@ -256,3 +256,39 @@ t1 CREATE TABLE `t1` ( ...@@ -256,3 +256,39 @@ t1 CREATE TABLE `t1` (
`@first_var` longtext `@first_var` longtext
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; 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;
...@@ -171,3 +171,34 @@ set @first_var= cast(NULL as CHAR); ...@@ -171,3 +171,34 @@ set @first_var= cast(NULL as CHAR);
create table t1 select @first_var; create table t1 select @first_var;
show create table t1; show create table t1;
drop 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;
...@@ -3408,6 +3408,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, ...@@ -3408,6 +3408,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
entry->length=0; entry->length=0;
entry->update_query_id=0; entry->update_query_id=0;
entry->collation.set(NULL, DERIVATION_IMPLICIT); 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 If we are here, we were called from a SET or a query which sets a
variable. Imagine it is this: variable. Imagine it is this:
...@@ -3494,6 +3495,7 @@ Item_func_set_user_var::fix_length_and_dec() ...@@ -3494,6 +3495,7 @@ Item_func_set_user_var::fix_length_and_dec()
type - type of new value type - type of new value
cs - charset info for new value cs - charset info for new value
dv - derivation for new value dv - derivation for new value
unsigned_arg - indiates if a value of type INT_RESULT is unsigned
RETURN VALUE RETURN VALUE
False - success, True - failure False - success, True - failure
...@@ -3501,7 +3503,8 @@ Item_func_set_user_var::fix_length_and_dec() ...@@ -3501,7 +3503,8 @@ Item_func_set_user_var::fix_length_and_dec()
static bool static bool
update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, 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) if (set_null)
{ {
...@@ -3549,6 +3552,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, ...@@ -3549,6 +3552,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
((my_decimal*)entry->value)->fix_buffer_pointer(); ((my_decimal*)entry->value)->fix_buffer_pointer();
entry->length= length; entry->length= length;
entry->collation.set(cs, dv); entry->collation.set(cs, dv);
entry->unsigned_flag= unsigned_arg;
} }
entry->type=type; entry->type=type;
return 0; return 0;
...@@ -3557,7 +3561,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, ...@@ -3557,7 +3561,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
bool bool
Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type, 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 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, ...@@ -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) if ((null_value= args[0]->null_value) && null_item)
type= entry->type; // Don't change type of item type= entry->type; // Don't change type of item
if (::update_hash(entry, (null_value= args[0]->null_value), 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 current_thd->fatal_error(); // Probably end of memory
null_value= 1; null_value= 1;
...@@ -3648,7 +3653,10 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, ...@@ -3648,7 +3653,10 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
str->set(*(double*) value, decimals, &my_charset_bin); str->set(*(double*) value, decimals, &my_charset_bin);
break; break;
case INT_RESULT: case INT_RESULT:
if (!unsigned_flag)
str->set(*(longlong*) value, &my_charset_bin); str->set(*(longlong*) value, &my_charset_bin);
else
str->set(*(ulonglong*) value, &my_charset_bin);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str); my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str);
...@@ -3719,6 +3727,7 @@ Item_func_set_user_var::check() ...@@ -3719,6 +3727,7 @@ Item_func_set_user_var::check()
case INT_RESULT: case INT_RESULT:
{ {
save_result.vint= args[0]->val_int(); save_result.vint= args[0]->val_int();
unsigned_flag= args[0]->unsigned_flag;
break; break;
} }
case STRING_RESULT: case STRING_RESULT:
...@@ -3774,7 +3783,8 @@ Item_func_set_user_var::update() ...@@ -3774,7 +3783,8 @@ Item_func_set_user_var::update()
case INT_RESULT: case INT_RESULT:
{ {
res= update_hash((void*) &save_result.vint, sizeof(save_result.vint), 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; break;
} }
case STRING_RESULT: case STRING_RESULT:
...@@ -4141,7 +4151,7 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) ...@@ -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) void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs)
{ {
if (::update_hash(entry, TRUE, 0, 0, STRING_RESULT, 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 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, ...@@ -4150,7 +4160,7 @@ void Item_user_var_as_out_param::set_value(const char *str, uint length,
CHARSET_INFO* cs) CHARSET_INFO* cs)
{ {
if (::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, 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 current_thd->fatal_error(); // Probably end of memory
} }
......
...@@ -1154,8 +1154,6 @@ class Item_func_set_user_var :public Item_func ...@@ -1154,8 +1154,6 @@ class Item_func_set_user_var :public Item_func
String *vstr; String *vstr;
my_decimal *vdec; my_decimal *vdec;
} save_result; } save_result;
String save_buff;
public: public:
LEX_STRING name; // keep it public LEX_STRING name; // keep it public
...@@ -1167,7 +1165,7 @@ class Item_func_set_user_var :public Item_func ...@@ -1167,7 +1165,7 @@ class Item_func_set_user_var :public Item_func
String *val_str(String *str); String *val_str(String *str);
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
bool update_hash(void *ptr, uint length, enum Item_result type, bool update_hash(void *ptr, uint length, enum Item_result type,
CHARSET_INFO *cs, Derivation dv); CHARSET_INFO *cs, Derivation dv, bool unsigned_arg= 0);
bool check(); bool check();
bool update(); bool update();
enum Item_result result_type () const { return cached_result_type; } enum Item_result result_type () const { return cached_result_type; }
......
...@@ -1497,6 +1497,7 @@ static Item_result set_row(List<Item> &item_list, Item *item, ...@@ -1497,6 +1497,7 @@ static Item_result set_row(List<Item> &item_list, Item *item,
item->max_length= sel_item->max_length; item->max_length= sel_item->max_length;
res_type= sel_item->result_type(); res_type= sel_item->result_type();
item->decimals= sel_item->decimals; item->decimals= sel_item->decimals;
item->unsigned_flag= sel_item->unsigned_flag;
*maybe_null= sel_item->maybe_null; *maybe_null= sel_item->maybe_null;
if (!(row[i]= Item_cache::get_cache(res_type))) if (!(row[i]= Item_cache::get_cache(res_type)))
return STRING_RESULT; // we should return something return STRING_RESULT; // we should return something
......
...@@ -1954,6 +1954,7 @@ class user_var_entry ...@@ -1954,6 +1954,7 @@ class user_var_entry
ulong length; ulong length;
query_id_t update_query_id, used_query_id; query_id_t update_query_id, used_query_id;
Item_result type; Item_result type;
bool unsigned_flag;
double val_real(my_bool *null_value); double val_real(my_bool *null_value);
longlong val_int(my_bool *null_value); longlong val_int(my_bool *null_value);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment