diff options
author | unknown <sanja@askmonty.org> | 2013-11-11 17:28:14 +0200 |
---|---|---|
committer | unknown <sanja@askmonty.org> | 2013-11-11 17:28:14 +0200 |
commit | c98a054fdeab9c2d3a637cf4fce57a2f9756dcc8 (patch) | |
tree | 7799ca0d2534b5ef7eedbca5db25c3c058674a38 /sql | |
parent | c85db2c4943b644c34cc4c67a95cfb5e5f0a09a4 (diff) | |
download | mariadb-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.cc | 11 | ||||
-rw-r--r-- | sql/item_subselect.cc | 38 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 19 |
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); + } } } /* |