summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sanja@askmonty.org>2013-11-11 17:28:14 +0200
committerunknown <sanja@askmonty.org>2013-11-11 17:28:14 +0200
commitc98a054fdeab9c2d3a637cf4fce57a2f9756dcc8 (patch)
tree7799ca0d2534b5ef7eedbca5db25c3c058674a38 /sql
parentc85db2c4943b644c34cc4c67a95cfb5e5f0a09a4 (diff)
downloadmariadb-git-c98a054fdeab9c2d3a637cf4fce57a2f9756dcc8.tar.gz
MDEV-5153: Server crashes in Item_ref::fix_fields on 2nd execution of PS with LEFT JOIN and MERGE view or SELECT SQ
1. Transformation of row IN subquery made the same as single value. 2. replace_where_subcondition() made working on several layers of OR/AND because it called on expression before fix_fields().
Diffstat (limited to 'sql')
-rw-r--r--sql/item_cmpfunc.cc11
-rw-r--r--sql/item_subselect.cc38
-rw-r--r--sql/opt_subselect.cc19
3 files changed, 40 insertions, 28 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 22554c71d90..49e56a46e84 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1436,9 +1436,11 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg)
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
{
+ DBUG_ENTER("Item_in_optimizer::fix_left");
if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) ||
(!cache && !(cache= Item_cache::get_cache(args[0]))))
- return 1;
+ DBUG_RETURN(1);
+ DBUG_PRINT("info", ("actual fix fields"));
cache->setup(args[0]);
if (cache->cols() == 1)
@@ -1460,10 +1462,13 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"SUBQUERY in ROW in left expression of IN/ALL/ANY");
- return 1;
+ DBUG_RETURN(1);
}
if (args[0]->element_index(i)->used_tables())
+ {
((Item_cache *)cache->element_index(i))->set_used_tables(OUTER_REF_TABLE_BIT);
+ cache->set_used_tables(OUTER_REF_TABLE_BIT);
+ }
else
((Item_cache *)cache->element_index(i))->set_used_tables(0);
}
@@ -1477,7 +1482,7 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
cache->store(args[0]);
cache->cache_value();
}
- return 0;
+ DBUG_RETURN(0);
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 0a4a06f8676..edb3f71583c 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -2177,11 +2177,11 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
DBUG_RETURN(true);
Item *item_eq=
new Item_func_eq(new
- Item_ref(&select_lex->context,
- (*optimizer->get_cache())->
- addr(i),
- (char *)"<no matter>",
- (char *)in_left_expr_name),
+ Item_direct_ref(&select_lex->context,
+ (*optimizer->get_cache())->
+ addr(i),
+ (char *)"<no matter>",
+ (char *)in_left_expr_name),
new
Item_ref(&select_lex->context,
select_lex->ref_pointer_array + i,
@@ -2462,7 +2462,7 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg)
bool
Item_in_subselect::select_in_like_transformer(JOIN *join)
{
- Query_arena *arena, backup;
+ Query_arena *arena= 0, backup;
SELECT_LEX *current= thd->lex->current_select;
const char *save_where= thd->where;
bool trans_res= true;
@@ -2484,9 +2484,6 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
}
}
- if (changed)
- DBUG_RETURN(false);
-
thd->where= "IN/ALL/ANY subquery";
/*
@@ -2497,25 +2494,29 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
note: we won't need Item_in_optimizer when handling degenerate cases
like "... IN (SELECT 1)"
*/
+ arena= thd->activate_stmt_arena_if_needed(&backup);
if (!optimizer)
{
- arena= thd->activate_stmt_arena_if_needed(&backup);
result= (!(optimizer= new Item_in_optimizer(left_expr, this)));
- if (arena)
- thd->restore_active_arena(arena, &backup);
if (result)
- goto err;
+ goto out;
}
thd->lex->current_select= current->return_after_parsing();
- result= (!left_expr->fixed &&
- left_expr->fix_fields(thd, optimizer->arguments()));
+ result= optimizer->fix_left(thd, optimizer->arguments());
/* fix_fields can change reference to left_expr, we need reassign it */
left_expr= optimizer->arguments()[0];
-
thd->lex->current_select= current;
+
+ if (changed)
+ {
+ trans_res= false;
+ goto out;
+ }
+
+
if (result)
- goto err;
+ goto out;
/*
Both transformers call fix_fields() only for Items created inside them,
@@ -2524,7 +2525,6 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
of Item, we have to call fix_fields() for it only with original arena to
avoid memory leack)
*/
- arena= thd->activate_stmt_arena_if_needed(&backup);
if (left_expr->cols() == 1)
trans_res= single_value_transformer(join);
else
@@ -2539,9 +2539,9 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
}
trans_res= row_value_transformer(join);
}
+out:
if (arena)
thd->restore_active_arena(arena, &backup);
-err:
thd->where= save_where;
DBUG_RETURN(trans_res);
}
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index bedf770d3d9..c5f692f8128 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1252,11 +1252,11 @@ void get_delayed_table_estimates(TABLE *table,
@brief Replaces an expression destructively inside the expression tree of
the WHERE clase.
- @note Because of current requirements for semijoin flattening, we do not
- need to recurse here, hence this function will only examine the top-level
- AND conditions. (see JOIN::prepare, comment starting with "Check if the
- subquery predicate can be executed via materialization".
-
+ @note We substitute AND/OR structure because it was copied by
+ copy_andor_structure and some changes could be done in the copy but
+ should be left permanent, also there could be several layers of AND over
+ AND and OR over OR because ::fix_field() possibly is not called.
+
@param join The top-level query.
@param old_cond The expression to be replaced.
@param new_cond The expression to be substituted.
@@ -1284,13 +1284,20 @@ static bool replace_where_subcondition(JOIN *join, Item **expr,
Item *item;
while ((item= li++))
{
- if (item == old_cond)
+ if (item == old_cond)
{
li.replace(new_cond);
if (do_fix_fields)
new_cond->fix_fields(join->thd, li.ref());
return FALSE;
}
+ else if (item->type() == Item::COND_ITEM)
+ {
+ DBUG_ASSERT(!(*expr)->fixed);
+ replace_where_subcondition(join, li.ref(),
+ old_cond, new_cond,
+ do_fix_fields);
+ }
}
}
/*