diff options
-rw-r--r-- | mysql-test/r/subselect_sj2.result | 17 | ||||
-rw-r--r-- | mysql-test/r/subselect_sj2_jcl6.result | 17 | ||||
-rw-r--r-- | mysql-test/t/subselect_sj2.test | 18 | ||||
-rw-r--r-- | sql/item.cc | 1 | ||||
-rw-r--r-- | sql/sql_base.cc | 16 | ||||
-rw-r--r-- | sql/sql_lex.cc | 41 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 |
7 files changed, 110 insertions, 2 deletions
diff --git a/mysql-test/r/subselect_sj2.result b/mysql-test/r/subselect_sj2.result index 036fd6ebb48..e4e66ce01f2 100644 --- a/mysql-test/r/subselect_sj2.result +++ b/mysql-test/r/subselect_sj2.result @@ -747,4 +747,21 @@ LEFT JOIN t2 AS SQ4_alias3 ON SQ4_alias3.f10 GROUP BY field2; field2 drop table t1, t2, t3; +# +# BUG#849763: Wrong result with second execution of prepared statement with semijoin + view +# +CREATE TABLE t1 ( c varchar(1)) engine=innodb; +INSERT INTO t1 VALUES ('r'); +CREATE TABLE t2 ( a integer, b varchar(1), c varchar(1)) engine=innodb; +INSERT INTO t2 VALUES (1,'r','r'); +CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1; +PREPARE st1 FROM 'SELECT * FROM t2 WHERE a = SOME (SELECT a FROM v1 WHERE v1.c = t2.c)'; +EXECUTE st1; +a b c +1 r r +EXECUTE st1; +a b c +1 r r +DROP VIEW v1; +DROP TABLE t1, t2; set optimizer_switch=@subselect_sj2_tmp; diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index a24c2d8f18a..234fd625886 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -758,6 +758,23 @@ LEFT JOIN t2 AS SQ4_alias3 ON SQ4_alias3.f10 GROUP BY field2; field2 drop table t1, t2, t3; +# +# BUG#849763: Wrong result with second execution of prepared statement with semijoin + view +# +CREATE TABLE t1 ( c varchar(1)) engine=innodb; +INSERT INTO t1 VALUES ('r'); +CREATE TABLE t2 ( a integer, b varchar(1), c varchar(1)) engine=innodb; +INSERT INTO t2 VALUES (1,'r','r'); +CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1; +PREPARE st1 FROM 'SELECT * FROM t2 WHERE a = SOME (SELECT a FROM v1 WHERE v1.c = t2.c)'; +EXECUTE st1; +a b c +1 r r +EXECUTE st1; +a b c +1 r r +DROP VIEW v1; +DROP TABLE t1, t2; set optimizer_switch=@subselect_sj2_tmp; set join_cache_level=default; show variables like 'join_cache_level'; diff --git a/mysql-test/t/subselect_sj2.test b/mysql-test/t/subselect_sj2.test index 285146481f4..ed96168a6c8 100644 --- a/mysql-test/t/subselect_sj2.test +++ b/mysql-test/t/subselect_sj2.test @@ -944,4 +944,22 @@ WHERE alias2.f11 IN ( GROUP BY field2; drop table t1, t2, t3; +--echo # +--echo # BUG#849763: Wrong result with second execution of prepared statement with semijoin + view +--echo # +CREATE TABLE t1 ( c varchar(1)) engine=innodb; +INSERT INTO t1 VALUES ('r'); + +CREATE TABLE t2 ( a integer, b varchar(1), c varchar(1)) engine=innodb; +INSERT INTO t2 VALUES (1,'r','r'); + +CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1; + +PREPARE st1 FROM 'SELECT * FROM t2 WHERE a = SOME (SELECT a FROM v1 WHERE v1.c = t2.c)'; +EXECUTE st1; +EXECUTE st1; + +DROP VIEW v1; +DROP TABLE t1, t2; + set optimizer_switch=@subselect_sj2_tmp; diff --git a/sql/item.cc b/sql/item.cc index 02263106fe8..a4cd292a5b1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4648,6 +4648,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (!outer_fixed && cached_table && cached_table->select_lex && context->select_lex && cached_table->select_lex != context->select_lex && + !context->select_lex->is_merged_child_of(cached_table->select_lex) && is_outer_table(cached_table, context->select_lex)) { int ret; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index bca8167f2b9..e2142bc2734 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6447,11 +6447,25 @@ find_field_in_tables(THD *thd, Item_ident *item, { SELECT_LEX *current_sel= thd->lex->current_select; SELECT_LEX *last_select= table_ref->select_lex; + bool all_merged= TRUE; + for (SELECT_LEX *sl= current_sel; sl && sl!=last_select; + sl=sl->outer_select()) + { + Item *subs= sl->master_unit()->item; + if (subs->type() == Item::SUBSELECT_ITEM && + ((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS && + ((Item_in_subselect*)subs)->in_strategy & SUBS_SEMI_JOIN) + { + continue; + } + all_merged= FALSE; + break; + } /* If the field was an outer referencee, mark all selects using this sub query as dependent on the outer query */ - if (current_sel != last_select) + if (!all_merged && current_sel != last_select) { mark_select_range_as_dependent(thd, last_select, current_sel, found, *ref, item); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 23662339cff..72cf0179449 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3622,6 +3622,47 @@ bool st_select_lex::save_prep_leaf_tables(THD *thd) } +/* + Return true if this select_lex has been converted into a semi-join nest + within 'ancestor'. + + We need a loop to check this because there could be several nested + subselects, like + + SELECT ... FROM grand_parent + WHERE expr1 IN (SELECT ... FROM parent + WHERE expr2 IN ( SELECT ... FROM child) + + which were converted into: + + SELECT ... + FROM grand_parent SEMI_JOIN (parent JOIN child) + WHERE + expr1 AND expr2 + + In this case, both parent and child selects were merged into the parent. +*/ + +bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) +{ + bool all_merged= TRUE; + for (SELECT_LEX *sl= this; sl && sl!=ancestor; + sl=sl->outer_select()) + { + Item *subs= sl->master_unit()->item; + if (subs && subs->type() == Item::SUBSELECT_ITEM && + ((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS && + ((Item_in_subselect*)subs)->in_strategy & SUBS_SEMI_JOIN) + { + continue; + } + all_merged= FALSE; + break; + } + return all_merged; +} + + /** A routine used by the parser to decide whether we are specifying a full partitioning or if only partitions to add or to split. diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0da628b7ca0..4ef24876474 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -907,7 +907,7 @@ public: bool save_leaf_tables(THD *thd); bool save_prep_leaf_tables(THD *thd); - + bool is_merged_child_of(st_select_lex *ancestor); private: /* current index hint kind. used in filling up index_hints */ enum index_hint_type current_index_hint_type; |