diff options
author | unknown <sanja@montyprogram.com> | 2012-10-09 17:36:02 +0300 |
---|---|---|
committer | unknown <sanja@montyprogram.com> | 2012-10-09 17:36:02 +0300 |
commit | 4304dbc464d425e54b0d802568838592cb625b26 (patch) | |
tree | dd9046c5f97ecbd9ec2ccd85811fbc5273a7bb08 /sql | |
parent | 72ab07c1cba0565a8ef043931610a2510a85cfd5 (diff) | |
download | mariadb-git-4304dbc464d425e54b0d802568838592cb625b26.tar.gz |
MDEV-616 fix (MySQL fix accepted)
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item_func.h | 9 | ||||
-rw-r--r-- | sql/sql_select.cc | 90 |
2 files changed, 67 insertions, 32 deletions
diff --git a/sql/item_func.h b/sql/item_func.h index 27f20dac002..4a31eb2da4e 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1441,6 +1441,15 @@ public: :Item_func(b), cached_result_type(INT_RESULT), entry(NULL), entry_thread_id(0), name(a) {} + Item_func_set_user_var(Item_func_set_user_var *item) + :Item_func(item), cached_result_type(item->cached_result_type), + entry(item->entry), entry_thread_id(item->entry_thread_id), + value(item->value), decimal_buff(item->decimal_buff), + null_item(item->null_item), save_result(item->save_result), + name(item->name) + { + //fixed= 1; + } enum Functype functype() const { return SUSERVAR_FUNC; } double val_real(); longlong val_int(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2a6c60af85f..cc377500b2c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -16237,40 +16237,66 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, res_selected_fields.empty(); res_all_fields.empty(); - uint i, border= all_fields.elements - elements; - for (i= 0; (item= it++); i++) + uint border= all_fields.elements - elements; + for (uint i= 0; (item= it++); i++) { Field *field; - - if ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) || - (item->type() == Item::FUNC_ITEM && - ((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC)) + if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) item_field= item; - else + else if (item->type() == Item::FIELD_ITEM) + item_field= item->get_tmp_table_item(thd); + else if (item->type() == Item::FUNC_ITEM && + ((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC) { - if (item->type() == Item::FIELD_ITEM) + field= item->get_tmp_table_field(); + if (field != NULL) { - item_field= item->get_tmp_table_item(thd); + /* + Replace "@:=<expression>" with "@:=<tmp table column>". Otherwise, + we would re-evaluate <expression>, and if expression were + a subquery, this would access already-unlocked tables. + */ + Item_func_set_user_var* suv= + new Item_func_set_user_var((Item_func_set_user_var*) item); + Item_field *new_field= new Item_field(field); + if (!suv || !new_field || suv->fix_fields(thd, (Item**)&suv)) + DBUG_RETURN(true); // Fatal error + ((Item *)suv)->name= item->name; + /* + We are replacing the argument of Item_func_set_user_var after its + value has been read. The argument's null_value should be set by + now, so we must set it explicitly for the replacement argument + since the null_value may be read without any preceeding call to + val_*(). + */ + new_field->update_null_value(); + List<Item> list; + list.push_back(new_field); + suv->set_arguments(list); + item_field= suv; } - else if ((field= item->get_tmp_table_field())) + else + item_field= item; + } + else if ((field= item->get_tmp_table_field())) + { + if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) + item_field= ((Item_sum*) item)->result_item(field); + else + item_field= (Item*) new Item_field(field); + if (!item_field) + DBUG_RETURN(true); // Fatal error + + if (item->real_item()->type() != Item::FIELD_ITEM) + field->orig_table= 0; + item_field->name= item->name; + if (item->type() == Item::REF_ITEM) { - if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) - item_field= ((Item_sum*) item)->result_item(field); - else - item_field= (Item*) new Item_field(field); - if (!item_field) - DBUG_RETURN(TRUE); // Fatal error - - if (item->real_item()->type() != Item::FIELD_ITEM) - field->orig_table= 0; - item_field->name= item->name; - if (item->type() == Item::REF_ITEM) - { - Item_field *ifield= (Item_field *) item_field; - Item_ref *iref= (Item_ref *) item; - ifield->table_name= iref->table_name; - ifield->db_name= iref->db_name; - } + Item_field *ifield= (Item_field *) item_field; + Item_ref *iref= (Item_ref *) item; + ifield->table_name= iref->table_name; + ifield->db_name= iref->db_name; + } #ifndef DBUG_OFF if (!item_field->name) { @@ -16282,20 +16308,20 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, item_field->name= sql_strmake(str.ptr(),str.length()); } #endif - } - else - item_field= item; } + else + item_field= item; + res_all_fields.push_back(item_field); ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]= item_field; } List_iterator_fast<Item> itr(res_all_fields); - for (i= 0; i < border; i++) + for (uint i= 0; i < border; i++) itr++; itr.sublist(res_selected_fields, elements); - DBUG_RETURN(FALSE); + DBUG_RETURN(false); } |