Bug #49198 | Wrong result for second call of procedure with view in subselect | ||
---|---|---|---|
Submitted: | 30 Nov 2009 8:55 | Modified: | 23 Nov 2010 3:06 |
Reporter: | Jørgen Løland | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S3 (Non-critical) |
Version: | 6.0 | OS: | Any |
Assigned to: | Tor Didriksen | CPU Architecture: | Any |
Tags: | optimizer_switch, semijoin, SP, VIEW |
[30 Nov 2009 8:55]
Jørgen Løland
[30 Nov 2009 9:02]
Jørgen Løland
semijoin=off (produces correct result): --------------------------------------- EXPLAIN EXTENDED SELECT t1field FROM t1 WHERE t1field IN ( SELECT v1_field FROM v1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 100.00 Using where; Using index 2 SUBQUERY A index NULL PRIMARY 4 NULL 2 100.00 Using where; Using index 4 SUBQUERY t1 index NULL PRIMARY 4 NULL 2 100.00 Using index Warnings: Note 1003 select `t1`.`t1field` AS `t1field` from `test`.`t1` where <in_optimizer>(`t1`.`t1field`,`t1`.`t1field` in ( <materialize> (select `test`.`A`.`t1field` AS `v1_field` from `test`.`t1` `A` where <in_optimizer>(`test`.`A`.`t1field`,`test`.`A`.`t1field` in ( <materialize> (select `test`.`t1`.`t1field` AS `t1field` from `test`.`t1` ), <primary_index_lookup>(`test`.`A`.`t1field` in <temporary table> on distinct_key where ((`test`.`A`.`t1field` = `materialized subselect`.`t1field`))))) ), <primary_index_lookup>(`t1`.`t1field` in <temporary table> on distinct_key where ((`t1`.`t1field` = `materialized subselect`.`v1_field`))))) semijoin=on: ------------ EXPLAIN EXTENDED SELECT t1field FROM t1 WHERE t1field IN ( SELECT v1_field FROM v1); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 2 100.00 Using where; Using index 1 PRIMARY A eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 100.00 Using index 4 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index Warnings: Note 1003 select `t1`.`t1field` AS `t1field` from `test`.`t1` `A` join `test`.`t1` where ((`test`.`A`.`t1field` = `t1`.`t1field`) and <in_optimizer>(`t1`.`t1field`,<exists>(<primary_index_lookup>(<cache>(`test`.`A`.`t1field`) in t1 on PRIMARY))))
[30 Nov 2009 9:03]
Valeriy Kravchuk
Verified just as described with recent 6.0.14 from bzr on Linux: openxs@suse:/home2/openxs/dbs/6.0-code> bin/mysql -uroot test Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 6.0.14-alpha-debug Source distribution Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> CREATE TABLE t1 ( t1field integer, primary key (t1field)); Query OK, 0 rows affected (0.04 sec) mysql> mysql> CREATE VIEW v1 AS -> SELECT t1field as v1_field -> FROM t1 A -> WHERE A.t1field IN (SELECT t1field FROM t1 ); Query OK, 0 rows affected (0.04 sec) mysql> delimiter // mysql> CREATE PROCEDURE p1 () -> BEGIN -> SELECT t1field -> FROM t1 -> WHERE t1field IN ( SELECT v1_field FROM v1); -> END// Query OK, 0 rows affected (0.01 sec) mysql> delimiter ; mysql> INSERT INTO t1 VALUES(1),(2); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> SELECT t1field -> FROM t1 -> WHERE t1field IN ( SELECT v1_field FROM v1); +---------+ | t1field | +---------+ | 1 | | 2 | +---------+ 2 rows in set (0.01 sec) mysql> CALL p1; +---------+ | t1field | +---------+ | 1 | | 2 | +---------+ 2 rows in set (0.01 sec) Query OK, 0 rows affected (0.01 sec) mysql> CALL p1; +---------+ | t1field | +---------+ | 2 | +---------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> set session optimizer_switch="semijoin=off"; Query OK, 0 rows affected (0.00 sec) mysql> drop procedure p1; Query OK, 0 rows affected (0.01 sec) mysql> delimiter // mysql> CREATE PROCEDURE p1 () -> BEGIN -> SELECT t1field -> FROM t1 -> WHERE t1field IN ( SELECT v1_field FROM v1); -> END// Query OK, 0 rows affected (0.02 sec) mysql> delimiter ; mysql> CALL p1; +---------+ | t1field | +---------+ | 1 | | 2 | +---------+ 2 rows in set (0.01 sec) Query OK, 0 rows affected (0.01 sec) mysql> CALL p1; +---------+ | t1field | +---------+ | 1 | | 2 | +---------+ 2 rows in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> CALL p1; +---------+ | t1field | +---------+ | 1 | | 2 | +---------+ 2 rows in set (0.01 sec) Query OK, 0 rows affected (0.01 sec)
[11 Dec 2009 7:21]
Jørgen Løland
A changeset from the last few days has made the attached test crash on second execution instead of producing a wrong result set. The current revision is: revision-id: alik@sun.com-20091211062703-09sznom962nf54aj date: 2009-12-11 09:27:03 +0300 build-date: 2009-12-11 08:22:24 +0100 revno: 3767 branch-nick: mysql-6.0-codebase-bugfixing
[16 Dec 2009 10:25]
Jørgen Løland
bzr find reports this: # Regression source: roy.lyseng@sun.com-20091208125053-gjhwf9lnq61tawr5 roy.lyseng@sun.com-20091208125053-gjhwf9lnq61tawr5
[16 Dec 2009 10:26]
Jørgen Løland
^ appears to be revision that made the test script crash instead of return wrong result on second execution.
[16 Dec 2009 11:38]
Jørgen Løland
Reverting to 2009-12-07 (before the test started to crash), this diff (found during investigation of bug#49453) produces correct result on the second execution: @@ -6681,11 +6615,9 @@ void Item_outer_ref::fix_after_pullout(s === modified file 'sql/item.cc' @@ -6681,11 +6615,9 @@ void Item_outer_ref::fix_after_pullout(s void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr) { + (*ref)->fix_after_pullout(new_parent, ref); if (depended_from == new_parent) - { - (*ref)->fix_after_pullout(new_parent, ref); depended_from= NULL; - } }
[5 Jan 2010 15:00]
Jørgen Løland
The newly introduced crash has been reported as BUG#50089.
[28 Jan 2010 12:13]
Tor Didriksen
An even simpler test case: CREATE TABLE t1 ( t1field integer, primary key (t1field)); CREATE TABLE t2 ( t2field integer, primary key (t2field)); CREATE VIEW v1 AS SELECT * FROM t2 ; INSERT INTO t1 VALUES(1),(2); INSERT INTO t2 VALUES(1),(2); prepare stmt from " SELECT t1field FROM t1 WHERE t1field IN ( SELECT * FROM v1); "; execute stmt; execute stmt; drop table t1; drop table t2; drop view v1;
[28 Jan 2010 15:00]
Tor Didriksen
With a little extra debug output, we see what happens on the second and subsequent executions: - first we mark t2.t2field as dependent (stack trace below) - then check_simple_equality((`test`.`t1`.`t1field` = `test`.`t2`.`t2field`)) returns FALSE because of this test: if (left_item->type() == Item::FIELD_ITEM && right_item->type() == Item::FIELD_ITEM && !((Item_field*)left_item)->depended_from() && !((Item_field*)right_item)->depended_from()) - we end up with a wrong execution plan T@4 : | | | | | | | | | | >setup_conds T@4 : | | | | | | | | | | | info: thd->mark_used_columns: 1 T@4 : | | | | | | | | | | | >Item_cond::fix_fields T@4 : | | | | | | | | | | | | >Item_func::fix_fields T@4 : | | | | | | | | | | | | | >Item_field::fix_fields T@4 : | | | | | | | | | | | | | | >find_field_in_table T@4 : | | | | | | | | | | | | | | | enter: table: 't1', field name: 't1field' T@4 : | | | | | | | | | | | | | | | >update_field_dependencies T@4 : | | | | | | | | | | | | | | | | note: Field found before T@4 : | | | | | | | | | | | | | | | <update_field_dependencies 5294 T@4 : | | | | | | | | | | | | | | <find_field_in_table 5592 T@4 : | | | | | | | | | | | | | <Item_field::fix_fields 4692 T@4 : | | | | | | | | | | | | | >Item_direct_view_ref::fix_fields T@4 : | | | | | | | | | | | | | | >Item_field::fix_fields T@4 : | | | | | | | | | | | | | | | >find_field_in_table T@4 : | | | | | | | | | | | | | | | | enter: table: 't2', field name: 't2field' T@4 : | | | | | | | | | | | | | | | | >update_field_dependencies T@4 : | | | | | | | | | | | | | | | | <update_field_dependencies 5302 T@4 : | | | | | | | | | | | | | | | <find_field_in_table 5592 T@4 : | | | | | | | | | | | | | | | >Item_field::fix_outer_field T@4 : | | | | | | | | | | | | | | | | >mark_as_dependent T@4 : | | | | | | | | | | | | | | | | | info: set_depended_from this:0x7f2dbc171ab0 val:0x7f2dbc170688 T@4 : | | | | | | | | | | | | | | | | <mark_as_dependent 3851
[29 Jan 2010 15:29]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/98661 3859 Tor Didriksen 2010-01-29 Bug #49198 Wrong result for second call of procedure with view in subselect The problem was that fix_after_pullout() after semijoin conversion wasn't propagated from the view to the underlying table. On subesequent executions of the prepared statement, we would mark the underlying table as 'dependent' and the predicate anlysis would lead to a different (and illegal) execution plan. @ mysql-test/r/subselect_sj.result Add test cases. @ mysql-test/r/subselect_sj_jcl6.result Add test cases. @ mysql-test/t/subselect_sj.test Add test cases. @ sql/item.cc Always propagate the fix_after_pullout() to the referenced object in Item_ref::fix_after_pullout() Add DBUG_ENTER/DBUG_RETURN tracing in misc places. @ sql/item_cmpfunc.cc Add DBUG_ENTER/DBUG_RETURN tracing in misc places. @ sql/item_func.cc Add DBUG_ENTER/DBUG_RETURN tracing in misc places. @ sql/sql_base.cc Do not call DBUG_RETURN(some_function_which_also_has_dbug_trace()) as the corresponding trace/indentation gets messed up. @ sql/sql_select.cc Add DBUG_ENTER/DBUG_RETURN tracing in misc places.
[1 Feb 2010 15:44]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/98836 3860 Tor Didriksen 2010-02-01 Bug #49198 Wrong result for second call of procedure with view in subselect The problem was that fix_after_pullout() after semijoin conversion wasn't propagated from the view to the underlying table. On subesequent executions of the prepared statement, we would mark the underlying table as 'dependent' and the predicate anlysis would lead to a different (and illegal) execution plan. @ mysql-test/r/subselect_sj.result Add test cases. @ mysql-test/r/subselect_sj_jcl6.result Add test cases. @ mysql-test/t/subselect_sj.test Add test cases. @ sql/item.cc Always propagate the fix_after_pullout() to the referenced object in Item_ref::fix_after_pullout() @ sql/sql_base.cc Do not call DBUG_RETURN(some_function_which_also_has_dbug_trace()) as the corresponding trace/indentation gets messed up.
[8 Feb 2010 11:31]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/99581 3872 Tor Didriksen 2010-02-08 Bug #49198 Wrong result for second call of procedure with view in subselect The problem was that fix_after_pullout() after semijoin conversion wasn't propagated from the view to the underlying table. On subesequent executions of the prepared statement, we would mark the underlying table as 'dependent' and the predicate anlysis would lead to a different (and illegal) execution plan. @ mysql-test/r/subselect_sj.result Add test cases. @ mysql-test/r/subselect_sj_jcl6.result Add test cases. @ mysql-test/t/subselect_sj.test Add test cases. @ sql/item.cc Always propagate the fix_after_pullout() to the referenced object in Item_direct_view_ref::fix_after_pullout() @ sql/item.h Add Item_direct_view_ref::fix_after_pullout()
[8 Feb 2010 14:05]
Tor Didriksen
Pushed to bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-6.0-codebase-bugfixing
[13 Feb 2010 8:37]
Bugs System
Pushed into 6.0.14-alpha (revid:alik@sun.com-20100213083436-9pesg4h55w1mekxc) (version source revid:luis.soares@sun.com-20100211135109-t63avry9fqpgyh78) (merge vers: 6.0.14-alpha) (pib:16)
[25 Feb 2010 0:43]
Paul DuBois
Noted in 6.0.14 changelog. With semijoin optimization enabled, the second execution of a prepared statement that referenced a view in a subquery could produce incorrect results.
[25 Feb 2010 8:52]
Sergey Petrunya
It is wrong to put DBUG_ASSERT(NULL == depended_from); into Item_ref::fix_after_pullout(). See BUG#51487 for a counterexample.
[15 Apr 2010 11:12]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/105720 3076 Tor Didriksen 2010-04-15 Bug #49198 Wrong result for second call of procedure with view in subselect Backport of tor.didriksen@sun.com-20100208113127-g8wvxcpc2dppmxxd The problem was that fix_after_pullout() after semijoin conversion wasn't propagated from the view to the underlying table. On subesequent executions of the prepared statement, we would mark the underlying table as 'dependent' and the predicate anlysis would lead to a different (and illegal) execution plan. @ mysql-test/r/subselect_sj.result Add test cases. @ mysql-test/t/subselect_sj.test Add test cases. @ sql/item.cc Always propagate the fix_after_pullout() to the referenced object in Item_direct_view_ref::fix_after_pullout() @ sql/item.h Add Item_direct_view_ref::fix_after_pullout()
[16 Aug 2010 6:33]
Bugs System
Pushed into mysql-next-mr (revid:alik@sun.com-20100816062819-bluwgdq8q4xysmlg) (version source revid:alik@sun.com-20100816062612-enatdwnv809iw3s9) (pib:20)
[13 Nov 2010 16:17]
Bugs System
Pushed into mysql-trunk 5.6.99-m5 (revid:alexander.nozdrin@oracle.com-20101113155825-czmva9kg4n31anmu) (version source revid:vasil.dimov@oracle.com-20100629074804-359l9m9gniauxr94) (merge vers: 5.6.99-m4) (pib:21)
[23 Nov 2010 3:06]
Paul DuBois
Bug does not appear in any released 5.6.x version. No 5.6.1 changelog entry needed.