Commit f4d55210 authored by Sergey Petrunya's avatar Sergey Petrunya

BUG#31480: Incorrect result for nested subquery when executed via semi join

- Variant #3 of the fix. It also
 = Unifies code with table elimination's 
 = is able to handle FROM-subquery pullout.
parent 17116d51
...@@ -779,3 +779,48 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -779,3 +779,48 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY it2 ALL NULL NULL NULL NULL 20 Using where; End temporary 1 PRIMARY it2 ALL NULL NULL NULL NULL 20 Using where; End temporary
DROP TABLE ot1, it1, it2; DROP TABLE ot1, it1, it2;
# End of BUG#38075 # End of BUG#38075
#
# BUG#31480: Incorrect result for nested subquery when executed via semi join
#
create table t1 (a int not null, b int not null);
create table t2 (c int not null, d int not null);
create table t3 (e int not null);
insert into t1 values (1,10);
insert into t1 values (2,10);
insert into t1 values (1,20);
insert into t1 values (2,20);
insert into t1 values (3,20);
insert into t1 values (2,30);
insert into t1 values (4,40);
insert into t2 values (2,10);
insert into t2 values (2,20);
insert into t2 values (4,10);
insert into t2 values (5,10);
insert into t2 values (3,20);
insert into t2 values (2,40);
insert into t3 values (10);
insert into t3 values (30);
insert into t3 values (10);
insert into t3 values (20);
explain extended
select a from t1
where a in (select c from t2 where d >= some(select e from t3 where b=e));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Start temporary
1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; End temporary; Using join buffer
3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
Warnings:
Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
show warnings;
Level Code Message
Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
select a from t1
where a in (select c from t2 where d >= some(select e from t3 where b=e));
a
2
2
3
2
drop table t1, t2, t3;
...@@ -783,6 +783,51 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -783,6 +783,51 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY it2 ALL NULL NULL NULL NULL 20 Using where; End temporary; Using join buffer 1 PRIMARY it2 ALL NULL NULL NULL NULL 20 Using where; End temporary; Using join buffer
DROP TABLE ot1, it1, it2; DROP TABLE ot1, it1, it2;
# End of BUG#38075 # End of BUG#38075
#
# BUG#31480: Incorrect result for nested subquery when executed via semi join
#
create table t1 (a int not null, b int not null);
create table t2 (c int not null, d int not null);
create table t3 (e int not null);
insert into t1 values (1,10);
insert into t1 values (2,10);
insert into t1 values (1,20);
insert into t1 values (2,20);
insert into t1 values (3,20);
insert into t1 values (2,30);
insert into t1 values (4,40);
insert into t2 values (2,10);
insert into t2 values (2,20);
insert into t2 values (4,10);
insert into t2 values (5,10);
insert into t2 values (3,20);
insert into t2 values (2,40);
insert into t3 values (10);
insert into t3 values (30);
insert into t3 values (10);
insert into t3 values (20);
explain extended
select a from t1
where a in (select c from t2 where d >= some(select e from t3 where b=e));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Start temporary
1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; End temporary; Using join buffer
3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
Warnings:
Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
show warnings;
Level Code Message
Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
select a from t1
where a in (select c from t2 where d >= some(select e from t3 where b=e));
a
2
2
3
2
drop table t1, t2, t3;
set join_cache_level=default; set join_cache_level=default;
show variables like 'join_cache_level'; show variables like 'join_cache_level';
Variable_name Value Variable_name Value
......
...@@ -681,3 +681,41 @@ WHERE int_nokey IN (SELECT it2.int_key ...@@ -681,3 +681,41 @@ WHERE int_nokey IN (SELECT it2.int_key
DROP TABLE ot1, it1, it2; DROP TABLE ot1, it1, it2;
--echo # End of BUG#38075 --echo # End of BUG#38075
--echo #
--echo # BUG#31480: Incorrect result for nested subquery when executed via semi join
--echo #
create table t1 (a int not null, b int not null);
create table t2 (c int not null, d int not null);
create table t3 (e int not null);
insert into t1 values (1,10);
insert into t1 values (2,10);
insert into t1 values (1,20);
insert into t1 values (2,20);
insert into t1 values (3,20);
insert into t1 values (2,30);
insert into t1 values (4,40);
insert into t2 values (2,10);
insert into t2 values (2,20);
insert into t2 values (4,10);
insert into t2 values (5,10);
insert into t2 values (3,20);
insert into t2 values (2,40);
insert into t3 values (10);
insert into t3 values (30);
insert into t3 values (10);
insert into t3 values (20);
explain extended
select a from t1
where a in (select c from t2 where d >= some(select e from t3 where b=e));
show warnings;
select a from t1
where a in (select c from t2 where d >= some(select e from t3 where b=e));
drop table t1, t2, t3;
...@@ -3647,7 +3647,7 @@ bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, uint fuzzydate) ...@@ -3647,7 +3647,7 @@ bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, uint fuzzydate)
substitution) substitution)
*/ */
static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
Item_ident *resolved_item, Item_ident *resolved_item,
Item_ident *mark_item) Item_ident *mark_item)
{ {
...@@ -3658,7 +3658,9 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, ...@@ -3658,7 +3658,9 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
/* store pointer on SELECT_LEX from which item is dependent */ /* store pointer on SELECT_LEX from which item is dependent */
if (mark_item) if (mark_item)
mark_item->depended_from= last; mark_item->depended_from= last;
current->mark_as_dependent(last, resolved_item); if (current->mark_as_dependent(thd, last, /** resolved_item psergey-thu
**/mark_item))
return TRUE;
if (thd->lex->describe & DESCRIBE_EXTENDED) if (thd->lex->describe & DESCRIBE_EXTENDED)
{ {
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
...@@ -3668,6 +3670,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, ...@@ -3668,6 +3670,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
resolved_item->field_name, resolved_item->field_name,
current->select_number, last->select_number); current->select_number, last->select_number);
} }
return FALSE;
} }
...@@ -4119,6 +4122,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) ...@@ -4119,6 +4122,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ? ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) : (Item_ident*) (*reference) :
0)); 0));
/* /*
A reference to a view field had been found and we A reference to a view field had been found and we
substituted it instead of this Item (find_field_in_tables substituted it instead of this Item (find_field_in_tables
...@@ -4218,7 +4222,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) ...@@ -4218,7 +4222,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
return -1; return -1;
mark_as_dependent(thd, last_checked_context->select_lex, mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this, context->select_lex, rf,
rf); rf);
return 0; return 0;
} }
...@@ -5998,7 +6002,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) ...@@ -5998,7 +6002,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
goto error; goto error;
thd->change_item_tree(reference, fld); thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex, mark_as_dependent(thd, last_checked_context->select_lex,
thd->lex->current_select, this, fld); thd->lex->current_select, fld, fld);
/* /*
A reference is resolved to a nest level that's outer or the same as A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of the nest level of the enclosing set function : adjust the value of
...@@ -6438,7 +6442,7 @@ void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref) ...@@ -6438,7 +6442,7 @@ void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref)
if (depended_from == new_parent) if (depended_from == new_parent)
{ {
*ref= outer_ref; *ref= outer_ref;
outer_ref->fix_after_pullout(new_parent, ref); (*ref)->fix_after_pullout(new_parent, ref);
} }
} }
......
...@@ -1115,7 +1115,9 @@ public: ...@@ -1115,7 +1115,9 @@ public:
/* /*
Class to be used to enumerate all field references in an item tree. Class to be used to enumerate all field references in an item tree. This
includes references to outside but not fields of the tables within a
subquery.
Suggested usage: Suggested usage:
class My_enumerator : public Field_enumerator class My_enumerator : public Field_enumerator
...@@ -2377,6 +2379,8 @@ public: ...@@ -2377,6 +2379,8 @@ public:
} }
bool walk(Item_processor processor, bool walk_subquery, uchar *arg) bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{ return (*ref)->walk(processor, walk_subquery, arg); } { return (*ref)->walk(processor, walk_subquery, arg); }
bool enumerate_field_refs_processor(uchar *arg)
{ return (*ref)->enumerate_field_refs_processor(arg); }
virtual void print(String *str, enum_query_type query_type); virtual void print(String *str, enum_query_type query_type);
bool result_as_longlong() bool result_as_longlong()
{ {
......
...@@ -39,8 +39,8 @@ inline Item * and_items(Item* cond, Item *item) ...@@ -39,8 +39,8 @@ inline Item * and_items(Item* cond, Item *item)
Item_subselect::Item_subselect(): Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), thd(0), substitution(0), Item_result_field(), value_assigned(0), thd(0), substitution(0),
engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0), engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
const_item_cache(1), in_fix_fields(0), engine_changed(0), changed(0), const_item_cache(1), inside_first_fix_fields(0), done_first_fix_fields(FALSE),
is_correlated(FALSE) engine_changed(0), changed(0), is_correlated(FALSE)
{ {
with_subselect= 1; with_subselect= 1;
reset(); reset();
...@@ -167,18 +167,23 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) ...@@ -167,18 +167,23 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param)); engine->set_thd((thd= thd_param));
if (!in_fix_fields) if (!done_first_fix_fields)
refers_to.empty(); {
done_first_fix_fields= TRUE;
inside_first_fix_fields= TRUE;
}
eliminated= FALSE; eliminated= FALSE;
parent_select= thd_param->lex->current_select;
if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res)) if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res))
return TRUE; return TRUE;
in_fix_fields++;
res= engine->prepare(); res= engine->prepare();
// all transformation is done (used by prepared statements) // all transformation is done (used by prepared statements)
changed= 1; changed= 1;
inside_first_fix_fields= FALSE;
if (!res) if (!res)
{ {
...@@ -210,14 +215,12 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) ...@@ -210,14 +215,12 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
if (!(*ref)->fixed) if (!(*ref)->fixed)
ret= (*ref)->fix_fields(thd, ref); ret= (*ref)->fix_fields(thd, ref);
thd->where= save_where; thd->where= save_where;
in_fix_fields--;
return ret; return ret;
} }
// Is it one field subselect? // Is it one field subselect?
if (engine->cols() > max_columns) if (engine->cols() > max_columns)
{ {
my_error(ER_OPERAND_COLUMNS, MYF(0), 1); my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
in_fix_fields--;
return TRUE; return TRUE;
} }
fix_length_and_dec(); fix_length_and_dec();
...@@ -234,7 +237,6 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) ...@@ -234,7 +237,6 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
fixed= 1; fixed= 1;
err: err:
in_fix_fields--;
thd->where= save_where; thd->where= save_where;
return res; return res;
} }
...@@ -242,11 +244,12 @@ err: ...@@ -242,11 +244,12 @@ err:
bool Item_subselect::enumerate_field_refs_processor(uchar *arg) bool Item_subselect::enumerate_field_refs_processor(uchar *arg)
{ {
List_iterator<Item> it(refers_to); List_iterator<Ref_to_outside> it(upper_refs);
Item *item; Ref_to_outside *upper;
while ((item= it++))
while ((upper= it++))
{ {
if (item->walk(&Item::enumerate_field_refs_processor, FALSE, arg)) if (upper->item->walk(&Item::enumerate_field_refs_processor, FALSE, arg))
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
...@@ -258,6 +261,142 @@ bool Item_subselect::mark_as_eliminated_processor(uchar *arg) ...@@ -258,6 +261,142 @@ bool Item_subselect::mark_as_eliminated_processor(uchar *arg)
return FALSE; return FALSE;
} }
bool Item_subselect::mark_as_dependent(THD *thd, st_select_lex *select,
Item *item)
{
if (inside_first_fix_fields)
{
is_correlated= TRUE;
Ref_to_outside *upper;
if (!(upper= new (thd->stmt_arena->mem_root) Ref_to_outside()))
return TRUE;
upper->select= select;
upper->item= item;
if (upper_refs.push_back(upper, thd->stmt_arena->mem_root))
return TRUE;
}
return FALSE;
}
/*
Adjust attributes after our parent select has been merged into grandparent
DESCRIPTION
Subquery is a composite object which may be correlated, that is, it may
have
1. references to tables of the parent select (i.e. one that has the clause
with the subquery predicate)
2. references to tables of the grandparent select
3. references to tables of further ancestors.
Before the pullout, this item indicates:
- #1 with table bits in used_tables()
- #2 and #3 with OUTER_REF_TABLE_BIT.
After parent has been merged with grandparent:
- references to parent and grandparent tables should be indicated with
table bits.
- references to greatgrandparent and further ancestors - with
OUTER_REF_TABLE_BIT.
*/
void Item_subselect::fix_after_pullout(st_select_lex *new_parent, Item **ref)
{
recalc_used_tables(new_parent, TRUE);
parent_select= new_parent;
}
class Field_fixer: public Field_enumerator
{
public:
table_map used_tables; /* Collect used_tables here */
st_select_lex *new_parent; /* Select we're in */
virtual void visit_field(Field *field)
{
//for (TABLE_LIST *tbl= new_parent->leaf_tables; tbl; tbl= tbl->next_local)
//{
// if (tbl->table == field->table)
// {
used_tables|= field->table->map;
// return;
// }
//}
//used_tables |= OUTER_REF_TABLE_BIT;
}
};
/*
Recalculate used_tables_cache
*/
void Item_subselect::recalc_used_tables(st_select_lex *new_parent,
bool after_pullout)
{
List_iterator<Ref_to_outside> it(upper_refs);
Ref_to_outside *upper;
used_tables_cache= 0;
while ((upper= it++))
{
bool found= FALSE;
/*
Check if
1. the upper reference refers to the new immediate parent select, or
2. one of the further ancestors.
We rely on the fact that the tree of selects is modified by some kind of
'flattening', i.e. a process where child selects are merged into their
parents.
The merged selects are removed from the select tree but keep pointers to
their parents.
*/
for (st_select_lex *sel= upper->select; sel; sel= sel->outer_select())
{
/*
If we've reached the new parent select by walking upwards from
reference's original select, this means that the reference is now
referring to the direct parent:
*/
if (sel == new_parent)
{
found= TRUE;
/*
upper->item may be NULL when we've referred to a grouping function,
in which case we don't care about what it's table_map really is,
because item->with_sum_func==1 will ensure correct placement of the
item.
*/
if (upper->item)
{
// Now, iterate over fields and collect used_tables() attribute:
Field_fixer fixer;
fixer.used_tables= 0;
fixer.new_parent= new_parent;
upper->item->walk(&Item::enumerate_field_refs_processor, FALSE,
(uchar*)&fixer);
used_tables_cache |= fixer.used_tables;
/*
if (after_pullout)
upper->item->fix_after_pullout(new_parent, &(upper->item));
upper->item->update_used_tables();
used_tables_cache |= upper->item->used_tables();
*/
}
}
}
if (!found)
used_tables_cache|= OUTER_REF_TABLE_BIT;
}
/*
Don't update const_tables_cache yet as we don't yet know which of the
parent's tables are constant. Parent will call update_used_tables() after
he has done const table detection, and that will be our chance to update
const_tables_cache.
*/
}
bool Item_subselect::walk(Item_processor processor, bool walk_subquery, bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
uchar *argument) uchar *argument)
{ {
...@@ -397,6 +536,7 @@ Item *Item_subselect::get_tmp_table_item(THD *thd_arg) ...@@ -397,6 +536,7 @@ Item *Item_subselect::get_tmp_table_item(THD *thd_arg)
void Item_subselect::update_used_tables() void Item_subselect::update_used_tables()
{ {
recalc_used_tables(parent_select, FALSE);
if (!engine->uncacheable()) if (!engine->uncacheable())
{ {
// did all used tables become static? // did all used tables become static?
...@@ -1843,6 +1983,18 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) ...@@ -1843,6 +1983,18 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
return result || Item_subselect::fix_fields(thd_arg, ref); return result || Item_subselect::fix_fields(thd_arg, ref);
} }
void Item_in_subselect::fix_after_pullout(st_select_lex *new_parent, Item **ref)
{
left_expr->fix_after_pullout(new_parent, &left_expr);
Item_subselect::fix_after_pullout(new_parent, ref);
}
void Item_in_subselect::update_used_tables()
{
Item_subselect::update_used_tables();
left_expr->update_used_tables();
used_tables_cache |= left_expr->used_tables();
}
/** /**
Try to create an engine to compute the subselect via materialization, Try to create an engine to compute the subselect via materialization,
......
...@@ -67,14 +67,32 @@ protected: ...@@ -67,14 +67,32 @@ protected:
bool have_to_be_excluded; bool have_to_be_excluded;
/* cache of constant state */ /* cache of constant state */
bool const_item_cache; bool const_item_cache;
bool inside_first_fix_fields;
bool done_first_fix_fields;
public: public:
/* /* A reference from inside subquery predicate to somewhere outside of it */
References from inside the subquery to the select that this predicate is class Ref_to_outside : public Sql_alloc
in. References to parent selects not included. {
public:
st_select_lex *select; /* Select where the reference is pointing to */
/*
What is being referred. This may be NULL when we're referring to an
aggregate function.
*/
Item *item;
};
/*
References from within this subquery to somewhere outside of it (i.e. to
parent select, grandparent select, etc)
*/ */
List<Item> refers_to; List<Ref_to_outside> upper_refs;
int in_fix_fields; st_select_lex *parent_select;
/*
TRUE<=>Table Elimination has made it redundant to evaluate this select
(and so it is not part of QEP, etc)
*/
bool eliminated; bool eliminated;
/* changed engine indicator */ /* changed engine indicator */
...@@ -117,6 +135,9 @@ public: ...@@ -117,6 +135,9 @@ public:
return null_value; return null_value;
} }
bool fix_fields(THD *thd, Item **ref); bool fix_fields(THD *thd, Item **ref);
bool mark_as_dependent(THD *thd, st_select_lex *select, Item *item);
void fix_after_pullout(st_select_lex *new_parent, Item **ref);
void recalc_used_tables(st_select_lex *new_parent, bool after_pullout);
virtual bool exec(); virtual bool exec();
virtual void fix_length_and_dec(); virtual void fix_length_and_dec();
table_map used_tables() const; table_map used_tables() const;
...@@ -396,6 +417,8 @@ public: ...@@ -396,6 +417,8 @@ public:
bool test_limit(st_select_lex_unit *unit); bool test_limit(st_select_lex_unit *unit);
virtual void print(String *str, enum_query_type query_type); virtual void print(String *str, enum_query_type query_type);
bool fix_fields(THD *thd, Item **ref); bool fix_fields(THD *thd, Item **ref);
void fix_after_pullout(st_select_lex *new_parent, Item **ref);
void update_used_tables();
bool setup_engine(); bool setup_engine();
bool init_left_expr_cache(); bool init_left_expr_cache();
bool is_expensive_processor(uchar *arg); bool is_expensive_processor(uchar *arg);
......
...@@ -350,7 +350,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) ...@@ -350,7 +350,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
sl= sl->master_unit()->outer_select() ) sl= sl->master_unit()->outer_select() )
sl->master_unit()->item->with_sum_func= 1; sl->master_unit()->item->with_sum_func= 1;
} }
thd->lex->current_select->mark_as_dependent(aggr_sel, NULL); thd->lex->current_select->mark_as_dependent(thd, aggr_sel, NULL);
return FALSE; return FALSE;
} }
......
...@@ -1841,9 +1841,8 @@ void st_select_lex_unit::exclude_tree() ...@@ -1841,9 +1841,8 @@ void st_select_lex_unit::exclude_tree()
'last' should be reachable from this st_select_lex_node 'last' should be reachable from this st_select_lex_node
*/ */
void st_select_lex::mark_as_dependent(st_select_lex *last, Item *dependency) bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last, Item *dependency)
{ {
SELECT_LEX *next_to_last;
/* /*
Mark all selects from resolved to 1 before select where was Mark all selects from resolved to 1 before select where was
found table as depended (of select where was found table) found table as depended (of select where was found table)
...@@ -1867,12 +1866,15 @@ void st_select_lex::mark_as_dependent(st_select_lex *last, Item *dependency) ...@@ -1867,12 +1866,15 @@ void st_select_lex::mark_as_dependent(st_select_lex *last, Item *dependency)
sl->uncacheable|= UNCACHEABLE_UNITED; sl->uncacheable|= UNCACHEABLE_UNITED;
} }
} }
next_to_last= s;
Item_subselect *subquery_expr= s->master_unit()->item;
if (subquery_expr && subquery_expr->mark_as_dependent(thd, last,
dependency))
return TRUE;
} }
is_correlated= TRUE; is_correlated= TRUE;
this->master_unit()->item->is_correlated= TRUE; this->master_unit()->item->is_correlated= TRUE;
if (dependency) return FALSE;
next_to_last->master_unit()->item->refers_to.push_back(dependency);
} }
bool st_select_lex_node::set_braces(bool value) { return 1; } bool st_select_lex_node::set_braces(bool value) { return 1; }
......
...@@ -747,7 +747,7 @@ public: ...@@ -747,7 +747,7 @@ public:
return master_unit()->return_after_parsing(); return master_unit()->return_after_parsing();
} }
void mark_as_dependent(st_select_lex *last, Item *dependency); bool mark_as_dependent(THD *thd, st_select_lex *last, Item *dependency);
bool set_braces(bool value); bool set_braces(bool value);
bool inc_in_sum_expr(); bool inc_in_sum_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