summaryrefslogtreecommitdiff
path: root/sql/sql_select.cc
diff options
context:
space:
mode:
authorkonstantin@mysql.com <>2004-10-10 02:39:22 +0400
committerkonstantin@mysql.com <>2004-10-10 02:39:22 +0400
commitdaa4c2495c4ebd7de1d5361e4c6660eb9561caa8 (patch)
treec22f3c078e64a910f14fd3c8078b854931ae0012 /sql/sql_select.cc
parent234c80b6895314206b2631bfe0825f5787890cb3 (diff)
downloadmariadb-git-daa4c2495c4ebd7de1d5361e4c6660eb9561caa8.tar.gz
A fix and test case for Bug#5987 "subselect in bool function
crashes server (prepared statements)": the bug was that all boolean items always recovered its original arguments at statement cleanup stage. This collided with Item_subselect::select_transformer, which tries to permanently change the item tree to use a transformed subselect instead of original one. So we had this call sequence for prepare: mysql_stmt_prepare -> JOIN::prepare -> Item_subselect::fix_fields -> the item tree gets transformed -> Item_bool_rowready_func2::cleanup, item tree is recovered to original state, while it shouldn't have been; mysql_stmt_execute -> attempts to execute a broken tree -> crash. Now instead of bluntly recovering all arguments of bool functions in Item_bool_rowready_func2::cleanup, we recover only those which were changed, and do it in one place. There still would exist a possibility for a collision with subselect tranformation, if permanent and temporary changes were performed at the same stage. But fortunately subselect transformation is always done first, so it doesn't conflict with the optimization done by propogate_cond_constants. Now we have: mysql_stmt_prepare -> JOIN::prepare -> subselect transformation permanently changes the tree -> cleanup doesn't recover anything, because nothing was registered for recovery. mysql_stmt_execute -> JOIN::prepare (the tree is already transformed, so it doesn't change), JOIN::optimize -> propogate_cond_constants -> temporary changes the item tree with constants -> JOIN::execute -> cleanup -> the changes done by propogate_cond_constants are recovered, as they were registered for recovery.
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r--sql/sql_select.cc66
1 files changed, 34 insertions, 32 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 0834f0659da..f2d814ed057 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -4171,8 +4171,9 @@ template class List_iterator<Item_func_match>;
*/
static void
-change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
- Item *cond, Item *field, Item *value)
+change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
+ Item *and_father, Item *cond,
+ Item *field, Item *value)
{
if (cond->type() == Item::COND_ITEM)
{
@@ -4181,7 +4182,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
Item *item;
while ((item=li++))
- change_cond_ref_to_const(save_list,and_level ? cond : item, item,
+ change_cond_ref_to_const(thd, save_list,and_level ? cond : item, item,
field, value);
return;
}
@@ -4189,8 +4190,9 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
return; // Not a boolean function
Item_bool_func2 *func= (Item_bool_func2*) cond;
- Item *left_item= func->arguments()[0];
- Item *right_item= func->arguments()[1];
+ Item **args= func->arguments();
+ Item *left_item= args[0];
+ Item *right_item= args[1];
Item_func::Functype functype= func->functype();
if (right_item->eq(field,0) && left_item != value &&
@@ -4201,7 +4203,8 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
Item *tmp=value->new_item();
if (tmp)
{
- func->arguments()[1] = tmp;
+ thd->register_item_tree_change(args + 1, args[1], &thd->mem_root);
+ args[1]= tmp;
func->update_used_tables();
if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC)
&& and_father != cond && !left_item->const_item())
@@ -4222,13 +4225,15 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
Item *tmp=value->new_item();
if (tmp)
{
- func->arguments()[0] = value = tmp;
+ thd->register_item_tree_change(args, args[0], &thd->mem_root);
+ args[0]= value= tmp;
func->update_used_tables();
if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC)
&& and_father != cond && !right_item->const_item())
{
- func->arguments()[0] = func->arguments()[1]; // For easy check
- func->arguments()[1] = value;
+ args[0]= args[1]; // For easy check
+ thd->register_item_tree_change(args + 1, args[1], &thd->mem_root);
+ args[1]= value;
cond->marker=1;
COND_CMP *tmp2;
if ((tmp2=new COND_CMP(and_father,func)))
@@ -4274,8 +4279,8 @@ static Item *remove_additional_cond(Item* conds)
}
static void
-propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
- COND *cond)
+propagate_cond_constants(THD *thd, I_List<COND_CMP> *save_list,
+ COND *and_father, COND *cond)
{
if (cond->type() == Item::COND_ITEM)
{
@@ -4286,18 +4291,19 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
I_List<COND_CMP> save;
while ((item=li++))
{
- propagate_cond_constants(&save,and_level ? cond : item, item);
+ propagate_cond_constants(thd, &save,and_level ? cond : item, item);
}
if (and_level)
{ // Handle other found items
I_List_iterator<COND_CMP> cond_itr(save);
COND_CMP *cond_cmp;
while ((cond_cmp=cond_itr++))
- if (!cond_cmp->cmp_func->arguments()[0]->const_item())
- change_cond_ref_to_const(&save,cond_cmp->and_level,
- cond_cmp->and_level,
- cond_cmp->cmp_func->arguments()[0],
- cond_cmp->cmp_func->arguments()[1]);
+ {
+ Item **args= cond_cmp->cmp_func->arguments();
+ if (!args[0]->const_item())
+ change_cond_ref_to_const(thd, &save,cond_cmp->and_level,
+ cond_cmp->and_level, args[0], args[1]);
+ }
}
}
else if (and_father != cond && !cond->marker) // In a AND group
@@ -4307,29 +4313,25 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC))
{
Item_func_eq *func=(Item_func_eq*) cond;
- bool left_const= func->arguments()[0]->const_item();
- bool right_const=func->arguments()[1]->const_item();
+ Item **args= func->arguments();
+ bool left_const= args[0]->const_item();
+ bool right_const= args[1]->const_item();
if (!(left_const && right_const) &&
- (func->arguments()[0]->result_type() ==
- (func->arguments()[1]->result_type())))
+ args[0]->result_type() == args[1]->result_type())
{
if (right_const)
{
- func->arguments()[1]=resolve_const_item(func->arguments()[1],
- func->arguments()[0]);
+ resolve_const_item(thd, &args[1], args[0]);
func->update_used_tables();
- change_cond_ref_to_const(save_list,and_father,and_father,
- func->arguments()[0],
- func->arguments()[1]);
+ change_cond_ref_to_const(thd, save_list, and_father, and_father,
+ args[0], args[1]);
}
else if (left_const)
{
- func->arguments()[0]=resolve_const_item(func->arguments()[0],
- func->arguments()[1]);
+ resolve_const_item(thd, &args[0], args[1]);
func->update_used_tables();
- change_cond_ref_to_const(save_list,and_father,and_father,
- func->arguments()[1],
- func->arguments()[0]);
+ change_cond_ref_to_const(thd, save_list, and_father, and_father,
+ args[1], args[0]);
}
}
}
@@ -4346,7 +4348,7 @@ optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value)
{
DBUG_EXECUTE("where", print_where(conds, "original"););
/* change field = field to field = const for each found field = const */
- propagate_cond_constants((I_List<COND_CMP> *) 0, conds, conds);
+ propagate_cond_constants(thd, (I_List<COND_CMP> *) 0, conds, conds);
/*
Remove all instances of item == item
Remove all and-levels where CONST item != CONST item