From 1d8cceae2b16ede9a2ac174dd8a97661eb0bc207 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 29 Oct 2009 17:24:29 +0200 Subject: [PATCH] Bug #42116 : Mysql crash on specific query Queries with nested outer joins may lead to crashes or bad results because an internal data structure is not handled correctly. The optimizer uses bitmaps of nested JOINs to determine if certain table can be placed at a certain place in the JOIN order. It does maintain a bitmap describing in which JOINs last placed table is nested. When it puts a table it makes sure the bit of every JOIN that contains the table in question is set (because JOINs can be nested). It does that by recursively setting the bit for the next enclosing JOIN when this is the first table in the JOIN and recursively resetting the bit if it's the last table in the JOIN. When it removes a table from the join order it should do the opposite : recursively unset the bit if it's the only remaining table in this join and and recursively set the bit if it's removing the last table of a JOIN. There was an error in how the bits was set for the upper levels : when removing a table it was setting the bit for all the enclosing nested JOINs even if there were more tables left in the current JOIN (which practically means that the upper nested JOINs were not affected). Fixed by stopping the recursion at the relevant level. --- mysql-test/r/join.result | 54 ++++++++++++++++++++++++++++++++++++++++ mysql-test/t/join.test | 52 ++++++++++++++++++++++++++++++++++++++ sql/sql_select.cc | 3 +++ 3 files changed, 109 insertions(+) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index b869d1a97b1..7d6ef5b40ba 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -859,4 +859,58 @@ Handler_read_prev 0 Handler_read_rnd 0 Handler_read_rnd_next 5 drop table t1, t2, t3; +# +# Bug #42116: Mysql crash on specific query +# +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT, INDEX (a)); +CREATE TABLE t4 (a INT); +CREATE TABLE t5 (a INT); +CREATE TABLE t6 (a INT); +INSERT INTO t1 VALUES (1), (1), (1); +INSERT INTO t2 VALUES +(2), (2), (2), (2), (2), (2), (2), (2), (2), (2); +INSERT INTO t3 VALUES +(3), (3), (3), (3), (3), (3), (3), (3), (3), (3); +EXPLAIN +SELECT * +FROM +t1 JOIN t2 ON t1.a = t2.a +LEFT JOIN +( +( +t3 LEFT JOIN t4 ON t3.a = t4.a +) +LEFT JOIN +( +t5 LEFT JOIN t6 ON t5.a = t6.a +) +ON t4.a = t5.a +) +ON t1.a = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t3 ref a a 5 test.t1.a 2 Using index +1 SIMPLE t4 ALL NULL NULL NULL NULL 0 +1 SIMPLE t5 ALL NULL NULL NULL NULL 0 +1 SIMPLE t6 ALL NULL NULL NULL NULL 0 +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using where +SELECT * +FROM +t1 JOIN t2 ON t1.a = t2.a +LEFT JOIN +( +( +t3 LEFT JOIN t4 ON t3.a = t4.a +) +LEFT JOIN +( +t5 LEFT JOIN t6 ON t5.a = t6.a +) +ON t4.a = t5.a +) +ON t1.a = t3.a; +a a a a a a +DROP TABLE t1,t2,t3,t4,t5,t6; End of 5.0 tests. diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 6c4de33950e..5b91d89836c 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -660,5 +660,57 @@ explain select * from t1, t2, t3 where t3.a=t1.a and t2.a=t1.b; show status like 'Handler_read%'; drop table t1, t2, t3; +--echo # +--echo # Bug #42116: Mysql crash on specific query +--echo # +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT, INDEX (a)); +CREATE TABLE t4 (a INT); +CREATE TABLE t5 (a INT); +CREATE TABLE t6 (a INT); + +INSERT INTO t1 VALUES (1), (1), (1); + +INSERT INTO t2 VALUES +(2), (2), (2), (2), (2), (2), (2), (2), (2), (2); + +INSERT INTO t3 VALUES +(3), (3), (3), (3), (3), (3), (3), (3), (3), (3); + +EXPLAIN +SELECT * +FROM + t1 JOIN t2 ON t1.a = t2.a + LEFT JOIN + ( + ( + t3 LEFT JOIN t4 ON t3.a = t4.a + ) + LEFT JOIN + ( + t5 LEFT JOIN t6 ON t5.a = t6.a + ) + ON t4.a = t5.a + ) + ON t1.a = t3.a; + +SELECT * +FROM + t1 JOIN t2 ON t1.a = t2.a + LEFT JOIN + ( + ( + t3 LEFT JOIN t4 ON t3.a = t4.a + ) + LEFT JOIN + ( + t5 LEFT JOIN t6 ON t5.a = t6.a + ) + ON t4.a = t5.a + ) + ON t1.a = t3.a; + +DROP TABLE t1,t2,t3,t4,t5,t6; --echo End of 5.0 tests. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3bf67299d58..8136c6f7635 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8640,7 +8640,10 @@ static void restore_prev_nj_state(JOIN_TAB *last) join->cur_embedding_map&= ~last_emb->nested_join->nj_map; else if (last_emb->nested_join->join_list.elements-1 == last_emb->nested_join->counter) + { join->cur_embedding_map|= last_emb->nested_join->nj_map; + break; + } else break; last_emb= last_emb->embedding;