diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index 0b1fdf8d0bb..bdf650b97bc 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -1801,4 +1801,35 @@ pk a pk a pk a 7 NULL NULL NULL NULL NULL 8 9 NULL NULL NULL NULL DROP TABLE t1, t2, t3; +CREATE TABLE t1 (a int NOT NULL ); +INSERT INTO t1 VALUES (9), (9); +CREATE TABLE t2 (a int NOT NULL ); +INSERT INTO t2 VALUES (9); +CREATE TABLE t3 (a int NOT NULL, b int); +INSERT INTO t3 VALUES (19,9); +CREATE TABLE t4 (b int) ; +SELECT * FROM t1 LEFT JOIN +((t2 LEFT JOIN t3 ON t2.a=t3.b) LEFT JOIN t4 ON t3.a=t4.b) +ON t1.a=t2.a; +a a a b b +9 9 19 9 NULL +9 9 19 9 NULL +SELECT * FROM t1 LEFT JOIN +((t2 LEFT JOIN t3 ON t2.a=t3.b) LEFT JOIN t4 ON t3.a=t4.b) +ON t1.a=t2.a +WHERE t3.a IS NULL; +a a a b b +EXPLAIN EXTENDED +SELECT * FROM t1 LEFT JOIN +((t2 LEFT JOIN t3 ON t2.a=t3.b) LEFT JOIN t4 ON t3.a=t4.b) +ON t1.a=t2.a +WHERE t3.a IS NULL; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 100.00 Using where +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 100.00 Using where; Not exists +1 SIMPLE t4 ALL NULL NULL NULL NULL 0 0.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`b` AS `b` from `test`.`t1` left join (`test`.`t2` left join `test`.`t3` on(((`test`.`t2`.`a` = `test`.`t1`.`a`) and (`test`.`t3`.`b` = `test`.`t1`.`a`))) left join `test`.`t4` on((`test`.`t4`.`b` = `test`.`t3`.`a`))) on((`test`.`t2`.`a` = `test`.`t1`.`a`)) where isnull(`test`.`t3`.`a`) +DROP TABLE t1,t2,t3,t4; End of 5.0 tests diff --git a/mysql-test/r/join_nested_jcl6.result b/mysql-test/r/join_nested_jcl6.result index d80beb44ef5..d11955226ae 100644 --- a/mysql-test/r/join_nested_jcl6.result +++ b/mysql-test/r/join_nested_jcl6.result @@ -1810,6 +1810,37 @@ pk a pk a pk a 7 NULL NULL NULL NULL NULL 8 9 NULL NULL NULL NULL DROP TABLE t1, t2, t3; +CREATE TABLE t1 (a int NOT NULL ); +INSERT INTO t1 VALUES (9), (9); +CREATE TABLE t2 (a int NOT NULL ); +INSERT INTO t2 VALUES (9); +CREATE TABLE t3 (a int NOT NULL, b int); +INSERT INTO t3 VALUES (19,9); +CREATE TABLE t4 (b int) ; +SELECT * FROM t1 LEFT JOIN +((t2 LEFT JOIN t3 ON t2.a=t3.b) LEFT JOIN t4 ON t3.a=t4.b) +ON t1.a=t2.a; +a a a b b +9 9 19 9 NULL +9 9 19 9 NULL +SELECT * FROM t1 LEFT JOIN +((t2 LEFT JOIN t3 ON t2.a=t3.b) LEFT JOIN t4 ON t3.a=t4.b) +ON t1.a=t2.a +WHERE t3.a IS NULL; +a a a b b +EXPLAIN EXTENDED +SELECT * FROM t1 LEFT JOIN +((t2 LEFT JOIN t3 ON t2.a=t3.b) LEFT JOIN t4 ON t3.a=t4.b) +ON t1.a=t2.a +WHERE t3.a IS NULL; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t2 hash_ALL NULL #hash#$hj 4 test.t1.a 1 100.00 Using where; Using join buffer (flat, BNLH join) +1 SIMPLE t3 hash_ALL NULL #hash#$hj 5 test.t1.a 1 100.00 Using where; Not exists; Using join buffer (incremental, BNLH join) +1 SIMPLE t4 hash_ALL NULL #hash#$hj 5 test.t3.a 0 0.00 Using where; Using join buffer (incremental, BNLH join) +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`b` AS `b` from `test`.`t1` left join (`test`.`t2` left join `test`.`t3` on(((`test`.`t2`.`a` = `test`.`t1`.`a`) and (`test`.`t3`.`b` = `test`.`t1`.`a`))) left join `test`.`t4` on(((`test`.`t4`.`b` = `test`.`t3`.`a`) and (`test`.`t3`.`a` is not null)))) on((`test`.`t2`.`a` = `test`.`t1`.`a`)) where isnull(`test`.`t3`.`a`) +DROP TABLE t1,t2,t3,t4; End of 5.0 tests CREATE TABLE t5 (a int, b int, c int, PRIMARY KEY(a), KEY b_i (b)); CREATE TABLE t6 (a int, b int, c int, PRIMARY KEY(a), KEY b_i (b)); diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index e36d861f8bb..deda56eb8ee 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -1236,5 +1236,35 @@ SELECT t1.pk, t1.a, t2.pk, t2.a,t3.pk, t3.a DROP TABLE t1, t2, t3; +# +# LP BUG#817360: Nested left joins + not-exist optimization +# + +CREATE TABLE t1 (a int NOT NULL ); +INSERT INTO t1 VALUES (9), (9); + +CREATE TABLE t2 (a int NOT NULL ); +INSERT INTO t2 VALUES (9); + +CREATE TABLE t3 (a int NOT NULL, b int); +INSERT INTO t3 VALUES (19,9); + +CREATE TABLE t4 (b int) ; + +SELECT * FROM t1 LEFT JOIN + ((t2 LEFT JOIN t3 ON t2.a=t3.b) LEFT JOIN t4 ON t3.a=t4.b) + ON t1.a=t2.a; +SELECT * FROM t1 LEFT JOIN + ((t2 LEFT JOIN t3 ON t2.a=t3.b) LEFT JOIN t4 ON t3.a=t4.b) + ON t1.a=t2.a + WHERE t3.a IS NULL; +EXPLAIN EXTENDED +SELECT * FROM t1 LEFT JOIN + ((t2 LEFT JOIN t3 ON t2.a=t3.b) LEFT JOIN t4 ON t3.a=t4.b) + ON t1.a=t2.a + WHERE t3.a IS NULL; + +DROP TABLE t1,t2,t3,t4; + --echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7301e51bdbe..d3382ad5965 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15114,7 +15114,6 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, condition is true => a match is found. */ bool found= 1; - bool use_not_exists_opt= 0; while (join_tab->first_unmatched && found) { /* @@ -15130,8 +15129,6 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, first_unmatched->found= 1; for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++) { - if (tab->table->reginfo.not_exists_optimize) - use_not_exists_opt= 1; /* Check all predicates that has just been activated. */ /* Actually all predicates non-guarded by first_unmatched->found @@ -15142,7 +15139,11 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, { /* The condition attached to table tab is false */ if (tab == join_tab) + { found= 0; + if (tab->table->reginfo.not_exists_optimize) + DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); + } else { /* @@ -15150,7 +15151,10 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, not to the last table of the current nest level. */ join->return_tab= tab; - DBUG_RETURN(NESTED_LOOP_OK); + if (tab->table->reginfo.not_exists_optimize) + DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); + else + DBUG_RETURN(NESTED_LOOP_OK); } } } @@ -15164,8 +15168,6 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, join_tab->first_unmatched= first_unmatched; } - if (use_not_exists_opt) - DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); JOIN_TAB *return_tab= join->return_tab; join_tab->found_match= TRUE;