Bug #52540 | Crash in JOIN_CACHE::set_match_flag_if_none () at sql_join_cache.cc:1883 | ||
---|---|---|---|
Submitted: | 1 Apr 2010 20:27 | Modified: | 21 Nov 2010 19:16 |
Reporter: | Patrick Crews | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S3 (Non-critical) |
Version: | mysql-6.0-codebase-bugfixing | OS: | Any |
Assigned to: | Guilhem Bichot | CPU Architecture: | Any |
Tags: | assertion, crashing bug, optimizer_join_cache_level, optimizer_switch |
[1 Apr 2010 20:27]
Patrick Crews
[1 Apr 2010 20:30]
Patrick Crews
Full crash output
Attachment: bug52540_crash_output.txt (text/plain), 12.34 KiB.
[1 Apr 2010 20:30]
Patrick Crews
Full MTR test case with original + simplified queries (simplified=query0)
Attachment: bug52540_test.txt (text/plain), 20.13 KiB.
[1 Apr 2010 22:12]
Sveta Smirnova
Thank you for the report. Verified as described.
[3 May 2010 8:19]
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/107162 3846 Guilhem Bichot 2010-05-03 Fix for BUG#52540 "Crash in JOIN_CACHE::set_match_flag_if_none () at sql_join_cache.cc:1883" @ mysql-test/t/join_cache.test minimal test case for bug @ sql/sql_select.cc As said in a comment in this file: "For a nested outer join/semi-join, currently, we either use join buffers for all inner tables or for none of them.". This is enforced by check_join_cache_usage(): for (JOIN_TAB *first_inner= tab->first_inner; first_inner; first_inner= first_inner->first_upper) { if (first_inner != tab && !first_inner->use_join_cache) goto no_join_cache; } i.e. if the first table in this join nest doesn't use join cache, or the first table of the upper containing join nest doesn't, go to label "no_join_cache" and thus: 1) don't use join cache for the current table 2) disable join cache for all previous tables of this nest and upper containing nests (via revise_cache_usage()). In the bug's scenario, before the fix, EXPLAIN showed this plan: t2, t1(with join buffering), t3, t4(with join buffering). * join buffering was decided for t1 * it was rejected for t3, because t3 is accessed with EQ_REF (join buffering with EQ_REF requires BKA, which we don't have at levels <=4): check_join_cache_usage() did "return 0", forgetting to disable join buffering for previous tables of the join nest i.e. t1 * join buffering was decided for t4, and allowed as it was observed that the first table of the upper nest (t1) had join buffering (so it was believed that all tables in between had join buffering). * at execution time, JOIN_CACHE:set_match_flag_if_none() would walk back the list of join buffers from t4 to t1: while (cache->join_tab != first_inner) { cache= cache->prev_cache; DBUG_ASSERT(cache); But t4 had prev_cache==0 (as previous table t1 wasn't doing join buffering), hence the assertion failure. This loop above assumed again that all previous tables should be doing join buffering. The fix is to make sure that when join buffering is rejected because of EQ_REF, we disable join buffering for previous tables, so that assumptions are true.
[10 May 2010 11:53]
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/107834 3873 Guilhem Bichot 2010-05-10 Fix for BUG#52540 "Crash in JOIN_CACHE::set_match_flag_if_none () at sql_join_cache.cc:1883" @ mysql-test/t/join_cache.test minimal test case for bug @ sql/sql_select.cc As said in a comment in this file: "For a nested outer join/semi-join, currently, we either use join buffers for all inner tables or for none of them.". This is enforced by check_join_cache_usage(): for (JOIN_TAB *first_inner= tab->first_inner; first_inner; first_inner= first_inner->first_upper) { if (first_inner != tab && !first_inner->use_join_cache) goto no_join_cache; } i.e. if the first table in this join nest doesn't use join cache, or the first table of the upper containing join nest doesn't, go to label "no_join_cache" and thus: 1) don't use join cache for the current table 2) disable join cache for all previous tables of this nest and upper containing nests (via revise_cache_usage()). In the bug's scenario, before the fix, EXPLAIN showed this plan: t2, t1(with join buffering), t3, t4(with join buffering). * join buffering was decided for t1 * it was rejected for t3, because t3 is accessed with EQ_REF (join buffering with EQ_REF requires BKA, which we don't have at levels <=4): check_join_cache_usage() did "return 0", forgetting to disable join buffering for previous tables of the join nest i.e. t1 * join buffering was decided for t4, and allowed as it was observed that the first table of the upper nest (t1) had join buffering (so it was believed that all tables in between had join buffering). * at execution time, JOIN_CACHE:set_match_flag_if_none() would walk back the list of join buffers from t4 to t1: while (cache->join_tab != first_inner) { cache= cache->prev_cache; DBUG_ASSERT(cache); But t4 had prev_cache==0 (as previous table t1 wasn't doing join buffering), hence the assertion failure. This loop above assumed again that all previous tables should be doing join buffering. The fix is to make sure that when join buffering is rejected because of EQ_REF, we disable join buffering for previous tables, so that assumptions are true.
[10 May 2010 11:53]
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/107835 3846 Guilhem Bichot 2010-05-10 Fix for BUG#52540 "Crash in JOIN_CACHE::set_match_flag_if_none () at sql_join_cache.cc:1883" @ mysql-test/t/join_cache.test minimal test case for bug @ sql/sql_select.cc As said in a comment in this file: "For a nested outer join/semi-join, currently, we either use join buffers for all inner tables or for none of them.". This is enforced by check_join_cache_usage(): for (JOIN_TAB *first_inner= tab->first_inner; first_inner; first_inner= first_inner->first_upper) { if (first_inner != tab && !first_inner->use_join_cache) goto no_join_cache; } i.e. if the first table in this join nest doesn't use join cache, or the first table of the upper containing join nest doesn't, go to label "no_join_cache" and thus: 1) don't use join cache for the current table 2) disable join cache for all previous tables of this nest and upper containing nests (via revise_cache_usage()). In the bug's scenario, before the fix, EXPLAIN showed this plan: t2, t1(with join buffering), t3, t4(with join buffering). * join buffering was decided for t1 * it was rejected for t3, because t3 is accessed with EQ_REF (join buffering with EQ_REF requires BKA, which we don't have at levels <=4): check_join_cache_usage() did "return 0", forgetting to disable join buffering for previous tables of the join nest i.e. t1 * join buffering was decided for t4, and allowed as it was observed that the first table of the upper nest (t1) had join buffering (so it was believed that all tables in between had join buffering). * at execution time, JOIN_CACHE:set_match_flag_if_none() would walk back the list of join buffers from t4 to t1: while (cache->join_tab != first_inner) { cache= cache->prev_cache; DBUG_ASSERT(cache); But t4 had prev_cache==0 (as previous table t1 wasn't doing join buffering), hence the assertion failure. This loop above assumed again that all previous tables should be doing join buffering. The fix is to make sure that when join buffering is rejected because of EQ_REF, we disable join buffering for previous tables, so that assumptions are true.
[11 May 2010 8:25]
Guilhem Bichot
queued to 6.0-codebase-bugfixing
[14 May 2010 15:58]
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/108366 3160 Guilhem Bichot 2010-05-10 Fix for BUG#52540 "Crash in JOIN_CACHE::set_match_flag_if_none () at sql_join_cache.cc:1883" (Backporting of guilhem@mysql.com-20100510092844-9fjd9g9ivk7258oj ) @ mysql-test/t/join_cache.test minimal test case for bug @ sql/sql_select.cc As said in a comment in this file: "For a nested outer join/semi-join, currently, we either use join buffers for all inner tables or for none of them.". This is enforced by check_join_cache_usage(): for (JOIN_TAB *first_inner= tab->first_inner; first_inner; first_inner= first_inner->first_upper) { if (first_inner != tab && !first_inner->use_join_cache) goto no_join_cache; } i.e. if the first table in this join nest doesn't use join cache, or the first table of the upper containing join nest doesn't, go to label "no_join_cache" and thus: 1) don't use join cache for the current table 2) disable join cache for all previous tables of this nest and upper containing nests (via revise_cache_usage()). In the bug's scenario, before the fix, EXPLAIN showed this plan: t2, t1(with join buffering), t3, t4(with join buffering). * join buffering was decided for t1 * it was rejected for t3, because t3 is accessed with EQ_REF (join buffering with EQ_REF requires BKA, which we don't have at levels <=4): check_join_cache_usage() did "return 0", forgetting to disable join buffering for previous tables of the join nest i.e. t1 * join buffering was decided for t4, and allowed as it was observed that the first table of the upper nest (t1) had join buffering (so it was believed that all tables in between had join buffering). * at execution time, JOIN_CACHE:set_match_flag_if_none() would walk back the list of join buffers from t4 to t1: while (cache->join_tab != first_inner) { cache= cache->prev_cache; DBUG_ASSERT(cache); But t4 had prev_cache==0 (as previous table t1 wasn't doing join buffering), hence the assertion failure. This loop above assumed again that all previous tables should be doing join buffering. The fix is to make sure that when join buffering is rejected because of EQ_REF, we disable join buffering for previous tables, so that assumptions are true.
[14 May 2010 18:17]
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/108376 3161 Guilhem Bichot 2010-05-10 Fix for BUG#52540 "Crash in JOIN_CACHE::set_match_flag_if_none () at sql_join_cache.cc:1883" (Backporting of guilhem@mysql.com-20100510092844-9fjd9g9ivk7258oj ) @ mysql-test/t/join_cache.test minimal test case for bug @ sql/sql_select.cc As said in a comment in this file: "For a nested outer join/semi-join, currently, we either use join buffers for all inner tables or for none of them.". This is enforced by check_join_cache_usage(): for (JOIN_TAB *first_inner= tab->first_inner; first_inner; first_inner= first_inner->first_upper) { if (first_inner != tab && !first_inner->use_join_cache) goto no_join_cache; } i.e. if the first table in this join nest doesn't use join cache, or the first table of the upper containing join nest doesn't, go to label "no_join_cache" and thus: 1) don't use join cache for the current table 2) disable join cache for all previous tables of this nest and upper containing nests (via revise_cache_usage()). In the bug's scenario, before the fix, EXPLAIN showed this plan: t2, t1(with join buffering), t3, t4(with join buffering). * join buffering was decided for t1 * it was rejected for t3, because t3 is accessed with EQ_REF (join buffering with EQ_REF requires BKA, which we don't have at levels <=4): check_join_cache_usage() did "return 0", forgetting to disable join buffering for previous tables of the join nest i.e. t1 * join buffering was decided for t4, and allowed as it was observed that the first table of the upper nest (t1) had join buffering (so it was believed that all tables in between had join buffering). * at execution time, JOIN_CACHE:set_match_flag_if_none() would walk back the list of join buffers from t4 to t1: while (cache->join_tab != first_inner) { cache= cache->prev_cache; DBUG_ASSERT(cache); But t4 had prev_cache==0 (as previous table t1 wasn't doing join buffering), hence the assertion failure. This loop above assumed again that all previous tables should be doing join buffering. The fix is to make sure that when join buffering is rejected because of EQ_REF, we disable join buffering for previous tables, so that assumptions are true.
[20 May 2010 10:04]
Bugs System
Pushed into 6.0.14-alpha (revid:alik@sun.com-20100520100225-oe4iuu5kuzsx0knq) (version source revid:alik@sun.com-20100520100057-rmn5y3o3ij726bm7) (merge vers: 6.0.14-alpha) (pib:16)
[20 May 2010 20:58]
Guilhem Bichot
"for values of optimizer_join_cache_level smaller or equal to 4, MySQL could crash in queries with outer joins and indexed columns".
[20 May 2010 22:46]
Paul DuBois
Noted in 6.0.14 changelog.
[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)
[21 Nov 2010 19:16]
Paul DuBois
Noted in 5.6.1 changelog.
[23 Nov 2010 2:16]
Paul DuBois
Correction: No 5.6.1 changelog entry. Bug does not appear in any released 5.6.x version.