Commit 504802f3 authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

MDEV-7846: postreview fix

parent 54b99817
...@@ -1442,6 +1442,12 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg) ...@@ -1442,6 +1442,12 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg)
bool Item_in_optimizer::fix_left(THD *thd, Item **ref) bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
{ {
DBUG_ENTER("Item_in_optimizer::fix_left"); DBUG_ENTER("Item_in_optimizer::fix_left");
/*
Here we will store pointer on place of main storage of left expression.
For usual IN (ALL/ANY) it is subquery left_expr.
For other cases (MAX/MIN optimization, non-transformed EXISTS (10.0))
it is args[0].
*/
Item **ref0= args; Item **ref0= args;
if (args[1]->type() == Item::SUBSELECT_ITEM && if (args[1]->type() == Item::SUBSELECT_ITEM &&
((Item_subselect *)args[1])->is_in_predicate()) ((Item_subselect *)args[1])->is_in_predicate())
...@@ -1455,12 +1461,17 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref) ...@@ -1455,12 +1461,17 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
next execution we need to copy args[1]->left_expr again. next execution we need to copy args[1]->left_expr again.
*/ */
ref0= &(((Item_in_subselect *)args[1])->left_expr); ref0= &(((Item_in_subselect *)args[1])->left_expr);
args[0]= ((Item_in_subselect *)args[1])->left_expr;
} }
if ((!(*ref0)->fixed && (*ref0)->fix_fields(thd, ref0)) || if ((!(*ref0)->fixed && (*ref0)->fix_fields(thd, ref0)) ||
(!cache && !(cache= Item_cache::get_cache(*ref0)))) (!cache && !(cache= Item_cache::get_cache(*ref0))))
DBUG_RETURN(1); DBUG_RETURN(1);
/*
During fix_field() expression could be substituted.
So we copy changes before use
*/
if (args[0] != (*ref0)) if (args[0] != (*ref0))
current_thd->change_item_tree(args, (*ref0)); args[0]= (*ref0);
DBUG_PRINT("info", ("actual fix fields")); DBUG_PRINT("info", ("actual fix fields"));
cache->setup(args[0]); cache->setup(args[0]);
......
...@@ -449,6 +449,11 @@ protected: ...@@ -449,6 +449,11 @@ protected:
Item **having_item); Item **having_item);
public: public:
Item *left_expr; Item *left_expr;
/*
Important for PS/SP: left_expr_orig is the item that left_expr originally
pointed at. That item is allocated on the statement arena, while
left_expr could later be changed to something on the execution arena.
*/
Item *left_expr_orig; Item *left_expr_orig;
/* Priority of this predicate in the convert-to-semi-join-nest process. */ /* Priority of this predicate in the convert-to-semi-join-nest process. */
int sj_convert_priority; int sj_convert_priority;
......
...@@ -1592,6 +1592,15 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) ...@@ -1592,6 +1592,15 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
if (subq_pred->left_expr->cols() == 1) if (subq_pred->left_expr->cols() == 1)
{ {
nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr); nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr);
/*
Create Item_func_eq. Note that
1. this is done on the statement, not execution, arena
2. if it's a PS then this happens only once - on the first execution.
On following re-executions, the item will be fix_field-ed normally.
3. Thus it should be created as if it was fix_field'ed, in particular
all pointers to items in the execution arena should be protected
with thd->change_item_tree
*/
Item_func_eq *item_eq= Item_func_eq *item_eq=
new Item_func_eq(subq_pred->left_expr_orig, subq_lex->ref_pointer_array[0]); new Item_func_eq(subq_pred->left_expr_orig, subq_lex->ref_pointer_array[0]);
if (subq_pred->left_expr_orig != subq_pred->left_expr) if (subq_pred->left_expr_orig != subq_pred->left_expr)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment