Loading mysql-test/r/user_var.result +9 −0 Original line number Diff line number Diff line Loading @@ -292,3 +292,12 @@ SELECT @a; @a 18446744071710965857 drop table bigfailure; create table t1(f1 int, f2 int); insert into t1 values (1,2),(2,3),(3,1); select @var:=f2 from t1 group by f1 order by f2 desc limit 1; @var:=f2 3 select @var; @var 3 drop table t1; mysql-test/t/user_var.test +10 −0 Original line number Diff line number Diff line Loading @@ -202,3 +202,13 @@ SET @a := (select * from bigfailure where afield = (SELECT afield FROM bigfailur SELECT @a; drop table bigfailure; # # Bug#16861: User defined variable can have a wrong value if a tmp table was # used. # create table t1(f1 int, f2 int); insert into t1 values (1,2),(2,3),(3,1); select @var:=f2 from t1 group by f1 order by f2 desc limit 1; select @var; drop table t1; sql/item_func.cc +30 −12 Original line number Diff line number Diff line Loading @@ -548,7 +548,7 @@ void Item_func::signal_divide_by_null() Item *Item_func::get_tmp_table_item(THD *thd) { if (!with_sum_func && !const_item()) if (!with_sum_func && !const_item() && functype() != SUSERVAR_FUNC) return new Item_field(result_field); return copy_or_same(thd); } Loading Loading @@ -3719,30 +3719,38 @@ my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) */ bool Item_func_set_user_var::check() Item_func_set_user_var::check(bool use_result_field) { DBUG_ENTER("Item_func_set_user_var::check"); if (use_result_field) DBUG_ASSERT(result_field); switch (cached_result_type) { case REAL_RESULT: { save_result.vreal= args[0]->val_real(); save_result.vreal= use_result_field ? result_field->val_real() : args[0]->val_real(); break; } case INT_RESULT: { save_result.vint= args[0]->val_int(); unsigned_flag= args[0]->unsigned_flag; save_result.vint= use_result_field ? result_field->val_int() : args[0]->val_int(); unsigned_flag= use_result_field ? ((Field_num*)result_field)->unsigned_flag: args[0]->unsigned_flag; break; } case STRING_RESULT: { save_result.vstr= args[0]->val_str(&value); save_result.vstr= use_result_field ? result_field->val_str(&value) : args[0]->val_str(&value); break; } case DECIMAL_RESULT: { save_result.vdec= args[0]->val_decimal(&decimal_buff); save_result.vdec= use_result_field ? result_field->val_decimal(&decimal_buff) : args[0]->val_decimal(&decimal_buff); break; } case ROW_RESULT: Loading Loading @@ -3828,7 +3836,7 @@ Item_func_set_user_var::update() double Item_func_set_user_var::val_real() { DBUG_ASSERT(fixed == 1); check(); check(0); update(); // Store expression return entry->val_real(&null_value); } Loading @@ -3836,7 +3844,7 @@ double Item_func_set_user_var::val_real() longlong Item_func_set_user_var::val_int() { DBUG_ASSERT(fixed == 1); check(); check(0); update(); // Store expression return entry->val_int(&null_value); } Loading @@ -3844,7 +3852,7 @@ longlong Item_func_set_user_var::val_int() String *Item_func_set_user_var::val_str(String *str) { DBUG_ASSERT(fixed == 1); check(); check(0); update(); // Store expression return entry->val_str(&null_value, str, decimals); } Loading @@ -3853,7 +3861,7 @@ String *Item_func_set_user_var::val_str(String *str) my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val) { DBUG_ASSERT(fixed == 1); check(); check(0); update(); // Store expression return entry->val_decimal(&null_value, val); } Loading @@ -3878,6 +3886,16 @@ void Item_func_set_user_var::print_as_stmt(String *str) str->append(')'); } bool Item_func_set_user_var::send(Protocol *protocol, String *str_arg) { if (result_field) { check(1); update(); return protocol->store(result_field); } return Item::send(protocol, str_arg); } String * Item_func_get_user_var::val_str(String *str) Loading Loading @@ -4143,7 +4161,7 @@ bool Item_func_get_user_var::set_value(THD *thd, Item_func_set_user_var is not fixed after construction, call fix_fields(). */ return (!suv || suv->fix_fields(thd, it) || suv->check() || suv->update()); return (!suv || suv->fix_fields(thd, it) || suv->check(0) || suv->update()); } Loading sql/item_func.h +4 −2 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ class Item_func :public Item_result_field SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN, NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; Loading Loading @@ -1167,13 +1167,15 @@ class Item_func_set_user_var :public Item_func Item_func_set_user_var(LEX_STRING a,Item *b) :Item_func(b), cached_result_type(INT_RESULT), name(a) {} enum Functype functype() const { return SUSERVAR_FUNC; } double val_real(); 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 unsigned_arg= 0); bool check(); bool send(Protocol *protocol, String *str_arg); bool check(bool use_result_field); bool update(); enum Item_result result_type () const { return cached_result_type; } bool fix_fields(THD *thd, Item **ref); Loading sql/set_var.cc +1 −1 Original line number Diff line number Diff line Loading @@ -3252,7 +3252,7 @@ int set_var_user::check(THD *thd) 0 can be passed as last argument (reference on item) */ return (user_var_item->fix_fields(thd, (Item**) 0) || user_var_item->check()) ? -1 : 0; user_var_item->check(0)) ? -1 : 0; } Loading Loading
mysql-test/r/user_var.result +9 −0 Original line number Diff line number Diff line Loading @@ -292,3 +292,12 @@ SELECT @a; @a 18446744071710965857 drop table bigfailure; create table t1(f1 int, f2 int); insert into t1 values (1,2),(2,3),(3,1); select @var:=f2 from t1 group by f1 order by f2 desc limit 1; @var:=f2 3 select @var; @var 3 drop table t1;
mysql-test/t/user_var.test +10 −0 Original line number Diff line number Diff line Loading @@ -202,3 +202,13 @@ SET @a := (select * from bigfailure where afield = (SELECT afield FROM bigfailur SELECT @a; drop table bigfailure; # # Bug#16861: User defined variable can have a wrong value if a tmp table was # used. # create table t1(f1 int, f2 int); insert into t1 values (1,2),(2,3),(3,1); select @var:=f2 from t1 group by f1 order by f2 desc limit 1; select @var; drop table t1;
sql/item_func.cc +30 −12 Original line number Diff line number Diff line Loading @@ -548,7 +548,7 @@ void Item_func::signal_divide_by_null() Item *Item_func::get_tmp_table_item(THD *thd) { if (!with_sum_func && !const_item()) if (!with_sum_func && !const_item() && functype() != SUSERVAR_FUNC) return new Item_field(result_field); return copy_or_same(thd); } Loading Loading @@ -3719,30 +3719,38 @@ my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) */ bool Item_func_set_user_var::check() Item_func_set_user_var::check(bool use_result_field) { DBUG_ENTER("Item_func_set_user_var::check"); if (use_result_field) DBUG_ASSERT(result_field); switch (cached_result_type) { case REAL_RESULT: { save_result.vreal= args[0]->val_real(); save_result.vreal= use_result_field ? result_field->val_real() : args[0]->val_real(); break; } case INT_RESULT: { save_result.vint= args[0]->val_int(); unsigned_flag= args[0]->unsigned_flag; save_result.vint= use_result_field ? result_field->val_int() : args[0]->val_int(); unsigned_flag= use_result_field ? ((Field_num*)result_field)->unsigned_flag: args[0]->unsigned_flag; break; } case STRING_RESULT: { save_result.vstr= args[0]->val_str(&value); save_result.vstr= use_result_field ? result_field->val_str(&value) : args[0]->val_str(&value); break; } case DECIMAL_RESULT: { save_result.vdec= args[0]->val_decimal(&decimal_buff); save_result.vdec= use_result_field ? result_field->val_decimal(&decimal_buff) : args[0]->val_decimal(&decimal_buff); break; } case ROW_RESULT: Loading Loading @@ -3828,7 +3836,7 @@ Item_func_set_user_var::update() double Item_func_set_user_var::val_real() { DBUG_ASSERT(fixed == 1); check(); check(0); update(); // Store expression return entry->val_real(&null_value); } Loading @@ -3836,7 +3844,7 @@ double Item_func_set_user_var::val_real() longlong Item_func_set_user_var::val_int() { DBUG_ASSERT(fixed == 1); check(); check(0); update(); // Store expression return entry->val_int(&null_value); } Loading @@ -3844,7 +3852,7 @@ longlong Item_func_set_user_var::val_int() String *Item_func_set_user_var::val_str(String *str) { DBUG_ASSERT(fixed == 1); check(); check(0); update(); // Store expression return entry->val_str(&null_value, str, decimals); } Loading @@ -3853,7 +3861,7 @@ String *Item_func_set_user_var::val_str(String *str) my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val) { DBUG_ASSERT(fixed == 1); check(); check(0); update(); // Store expression return entry->val_decimal(&null_value, val); } Loading @@ -3878,6 +3886,16 @@ void Item_func_set_user_var::print_as_stmt(String *str) str->append(')'); } bool Item_func_set_user_var::send(Protocol *protocol, String *str_arg) { if (result_field) { check(1); update(); return protocol->store(result_field); } return Item::send(protocol, str_arg); } String * Item_func_get_user_var::val_str(String *str) Loading Loading @@ -4143,7 +4161,7 @@ bool Item_func_get_user_var::set_value(THD *thd, Item_func_set_user_var is not fixed after construction, call fix_fields(). */ return (!suv || suv->fix_fields(thd, it) || suv->check() || suv->update()); return (!suv || suv->fix_fields(thd, it) || suv->check(0) || suv->update()); } Loading
sql/item_func.h +4 −2 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ class Item_func :public Item_result_field SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN, NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; Loading Loading @@ -1167,13 +1167,15 @@ class Item_func_set_user_var :public Item_func Item_func_set_user_var(LEX_STRING a,Item *b) :Item_func(b), cached_result_type(INT_RESULT), name(a) {} enum Functype functype() const { return SUSERVAR_FUNC; } double val_real(); 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 unsigned_arg= 0); bool check(); bool send(Protocol *protocol, String *str_arg); bool check(bool use_result_field); bool update(); enum Item_result result_type () const { return cached_result_type; } bool fix_fields(THD *thd, Item **ref); Loading
sql/set_var.cc +1 −1 Original line number Diff line number Diff line Loading @@ -3252,7 +3252,7 @@ int set_var_user::check(THD *thd) 0 can be passed as last argument (reference on item) */ return (user_var_item->fix_fields(thd, (Item**) 0) || user_var_item->check()) ? -1 : 0; user_var_item->check(0)) ? -1 : 0; } Loading