diff options
-rw-r--r-- | sql/item_func.h | 8 | ||||
-rw-r--r-- | sql/sql_select.cc | 104 |
2 files changed, 72 insertions, 40 deletions
diff --git a/sql/item_func.h b/sql/item_func.h index c6d6e8826cf..34ffd5b4ca5 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1492,6 +1492,14 @@ public: :Item_func(b), cached_result_type(INT_RESULT), entry(NULL), entry_thread_id(0), delayed_non_constness(delayed), name(a) {} + Item_func_set_user_var(THD *thd, Item_func_set_user_var *item) + :Item_func(thd, 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) + {} + 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 2bbecb9335b..0cb6981bfd8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15966,64 +15966,88 @@ 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(thd, (Item_func_set_user_var*) item); + Item_field *new_field= new Item_field(field); + if (!suv || !new_field) + DBUG_RETURN(true); // Fatal error + /* + 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) - { - char buff[256]; - String str(buff,sizeof(buff),&my_charset_bin); - str.length(0); - item->print(&str, QT_ORDINARY); - item_field->name= sql_strmake(str.ptr(),str.length()); - } -#endif + if (!item_field->name) + { + char buff[256]; + String str(buff,sizeof(buff),&my_charset_bin); + str.length(0); + item->print(&str, QT_ORDINARY); + item_field->name= sql_strmake(str.ptr(),str.length()); } - else - item_field= item; +#endif } + 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); } |