Commit f067dfe1 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 889e60da
......@@ -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;
......@@ -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;
......@@ -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
}
......
......@@ -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; }
......
......@@ -1497,6 +1497,7 @@ static Item_result set_row(List<Item> &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
......
......@@ -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);
......
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