summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sanja@montyprogram.com>2012-10-09 17:36:02 +0300
committerunknown <sanja@montyprogram.com>2012-10-09 17:36:02 +0300
commit4304dbc464d425e54b0d802568838592cb625b26 (patch)
treedd9046c5f97ecbd9ec2ccd85811fbc5273a7bb08 /sql
parent72ab07c1cba0565a8ef043931610a2510a85cfd5 (diff)
downloadmariadb-git-4304dbc464d425e54b0d802568838592cb625b26.tar.gz
MDEV-616 fix (MySQL fix accepted)
Diffstat (limited to 'sql')
-rw-r--r--sql/item_func.h9
-rw-r--r--sql/sql_select.cc90
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);
}