mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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
This commit is contained in:
@ -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);
|
|||||||
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,
|
|||||||
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()
|
|||||||
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()
|
|||||||
|
|
||||||
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,
|
|||||||
((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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
str->set(*(double*) value, decimals, &my_charset_bin);
|
str->set(*(double*) value, decimals, &my_charset_bin);
|
||||||
break;
|
break;
|
||||||
case INT_RESULT:
|
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;
|
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()
|
|||||||
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()
|
|||||||
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)
|
|||||||
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,
|
|||||||
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
|
|||||||
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
|
||||||
@ -1166,8 +1164,8 @@ public:
|
|||||||
longlong val_int();
|
longlong val_int();
|
||||||
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,
|
|||||||
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
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user