At file:///home/psergey/dev/mysql-next-fix-subq/ ------------------------------------------------------------ revno: 2818 revision-id: psergey@askmonty.org-20090708095341-9i08n2r8igulpxzz parent: psergey@askmonty.org-20090706143329-72s3e73rov2f5tml committer: Sergey Petrunya <psergey@askmonty.org> branch nick: mysql-next-fix-subq timestamp: Wed 2009-07-08 13:53:41 +0400 message: BUG#31480: Incorrect result for nested subquery when executed via semi join Make the fix work with prepared statements: - collect/save ancestor_used_tables and furthest_correlated_ancestor only at PREPARE phase (at execute() we are unable to tell what table_map the outer reference would tell. since it would be the same anyway, we save it at PREPARE phase) === modified file 'sql/item_subselect.cc' --- a/sql/item_subselect.cc 2009-07-06 14:26:03 +0000 +++ b/sql/item_subselect.cc 2009-07-08 09:53:41 +0000 @@ -39,8 +39,8 @@ Item_subselect::Item_subselect(): Item_result_field(), value_assigned(0), thd(0), substitution(0), engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0), - const_item_cache(1), inside_fix_fields(0), engine_changed(0), changed(0), - is_correlated(FALSE) + const_item_cache(1), inside_first_fix_fields(0), ancestor_used_tables(0), + engine_changed(0), changed(0), is_correlated(FALSE) { with_subselect= 1; reset(); @@ -158,6 +158,7 @@ DBUG_RETURN(RES_OK); } + void Item_subselect::set_depth() { uint n= 0; @@ -166,6 +167,7 @@ this->depth= n - 1; } + bool Item_subselect::fix_fields(THD *thd_param, Item **ref) { char const *save_where= thd_param->where; @@ -175,23 +177,25 @@ DBUG_ASSERT(fixed == 0); engine->set_thd((thd= thd_param)); - if (!inside_fix_fields) + if (!ancestor_used_tables) { set_depth(); - if (!(ancestor_used_tables= (table_map*)thd->calloc((1+depth) * - sizeof(table_map)))) + if (!(ancestor_used_tables= + (table_map*)alloc_root(thd->stmt_arena->mem_root, + (1+depth)*sizeof(table_map)))) return TRUE; furthest_correlated_ancestor= 0; + inside_first_fix_fields= TRUE; } if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res)) return TRUE; - inside_fix_fields++; res= engine->prepare(); - + // all transformation is done (used by prepared statements) changed= 1; + inside_first_fix_fields= FALSE; if (!res) { @@ -220,14 +224,12 @@ if (!(*ref)->fixed) ret= (*ref)->fix_fields(thd, ref); thd->where= save_where; - inside_fix_fields--; return ret; } // Is it one field subselect? if (engine->cols() > max_columns) { my_error(ER_OPERAND_COLUMNS, MYF(0), 1); - inside_fix_fields--; return TRUE; } fix_length_and_dec(); @@ -244,12 +246,23 @@ fixed= 1; err: - inside_fix_fields--; thd->where= save_where; return res; } +void Item_subselect::mark_as_dependent(uint n_levels, table_map dep_map) +{ + if (inside_first_fix_fields) + { + is_correlated= TRUE; + furthest_correlated_ancestor= max(furthest_correlated_ancestor, n_levels); + if (n_levels > 1) + ancestor_used_tables[n_levels - 2]= dep_map; + } +} + + /* Adjust attributes after our parent select has been merged into grandparent === modified file 'sql/item_subselect.h' --- a/sql/item_subselect.h 2009-07-06 07:57:39 +0000 +++ b/sql/item_subselect.h 2009-07-08 09:53:41 +0000 @@ -68,7 +68,7 @@ /* cache of constant state */ bool const_item_cache; - int inside_fix_fields; + int inside_first_fix_fields; public: /* Depth of the subquery predicate. @@ -140,6 +140,7 @@ return null_value; } bool fix_fields(THD *thd, Item **ref); + void mark_as_dependent(uint n_levels, table_map dep_map); void fix_after_pullout(st_select_lex *new_parent, uint parent_tables, Item **ref); virtual bool exec(); === modified file 'sql/sql_lex.cc' --- a/sql/sql_lex.cc 2009-07-06 07:57:39 +0000 +++ b/sql/sql_lex.cc 2009-07-08 09:53:41 +0000 @@ -1929,13 +1929,7 @@ } Item_subselect *subquery_predicate= s->master_unit()->item; if (subquery_predicate) - { - subquery_predicate->is_correlated= TRUE; - subquery_predicate->furthest_correlated_ancestor= - max(subquery_predicate->furthest_correlated_ancestor, n_levels); - if (n_levels > 1) - subquery_predicate->ancestor_used_tables[n_levels - 2]= dep_map; - } + subquery_predicate->mark_as_dependent(n_levels, dep_map); n_levels--; } }