Commit f067dfe1 authored by unknown's avatar unknown
Browse files

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
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -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;
+31 −0
Original line number Diff line number Diff line
@@ -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;
+17 −7
Original line number Diff line number Diff line
@@ -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:
    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
}

+2 −4
Original line number Diff line number Diff line
@@ -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
@@ -1167,7 +1165,7 @@ class Item_func_set_user_var :public Item_func
  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);
  		   CHARSET_INFO *cs, Derivation dv, bool unsigned_arg= 0);
  bool check();
  bool update();
  enum Item_result result_type () const { return cached_result_type; }
+1 −0
Original line number Diff line number Diff line
@@ -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
Loading