Commit 42cd3643 authored by Igor Babaev's avatar Igor Babaev

Fixed LP bug #675095.

The condition over outer tables extracted from the on expression
for a outer join must be ANDed to the condition pushed to the
first inner table of this outer join only.
Nested outer joins cannot use flat join buffers. So if join_cache_level
is set to 1 then any join algorithm employing join buffers cannot be used
for nested outer joins.
parent 9441a9cc
...@@ -5838,4 +5838,87 @@ pk a a ...@@ -5838,4 +5838,87 @@ pk a a
SET SESSION optimizer_switch = 'outer_join_with_cache=off'; SET SESSION optimizer_switch = 'outer_join_with_cache=off';
SET SESSION join_cache_level = DEFAULT; SET SESSION join_cache_level = DEFAULT;
DROP TABLE t1,t2; DROP TABLE t1,t2;
#
# Bug #675095: nested outer join using join buffer
#
CREATE TABLE t1 (pk int, a1 int) ;
INSERT IGNORE INTO t1 VALUES (2,NULL), (8,0);
CREATE TABLE t2 (pk int, a2 int, c2 int, d2 int) ;
INSERT IGNORE INTO t2 VALUES (9,0,0,2), (1,0,0,7);
CREATE TABLE t3 (pk int, a3 int, c3 int, d3 int) ;
INSERT IGNORE INTO t3 VALUES (9,0,0,2), (1,0,0,7);
CREATE TABLE t4 (pk int, a4 int, INDEX idx(a4)) ;
INSERT IGNORE INTO t4 VALUES (2,NULL), (8,0);
CREATE TABLE t5 (pk int, a5 int) ;
INSERT IGNORE INTO t5 VALUES (2,0), (8,0);
SET SESSION optimizer_switch = 'outer_join_with_cache=on';
SET SESSION join_cache_level = 0;
EXPLAIN EXTENDED
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
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 2 100.00 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where
1 SIMPLE t4 ref idx idx 5 test.t1.a1 2 100.00 Using where
1 SIMPLE t5 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`a1` AS `a1`,`test`.`t2`.`pk` AS `pk`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`c2` AS `c2`,`test`.`t2`.`d2` AS `d2`,`test`.`t3`.`pk` AS `pk`,`test`.`t3`.`a3` AS `a3`,`test`.`t3`.`c3` AS `c3`,`test`.`t3`.`d3` AS `d3`,`test`.`t4`.`pk` AS `pk`,`test`.`t4`.`a4` AS `a4`,`test`.`t5`.`pk` AS `pk`,`test`.`t5`.`a5` AS `a5` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t2`.`d2` = `test`.`t1`.`pk`) and (`test`.`t3`.`a3` = `test`.`t2`.`c2`))) left join `test`.`t4` on(((`test`.`t4`.`a4` = `test`.`t1`.`a1`) and (`test`.`t1`.`a1` is not null))) left join `test`.`t5` on((`test`.`t5`.`a5` = `test`.`t3`.`a3`)) where 1
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
pk a1 pk a2 c2 d2 pk a3 c3 d3 pk a4 pk a5
2 NULL 9 0 0 2 9 0 0 2 NULL NULL 2 0
2 NULL 9 0 0 2 9 0 0 2 NULL NULL 8 0
2 NULL 9 0 0 2 1 0 0 7 NULL NULL 2 0
2 NULL 9 0 0 2 1 0 0 7 NULL NULL 8 0
8 0 NULL NULL NULL NULL NULL NULL NULL NULL 8 0 NULL NULL
SET SESSION join_cache_level = 2;
EXPLAIN EXTENDED
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
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 2 100.00 Using where; Using join buffer (flat, BNL join)
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join)
1 SIMPLE t4 ref idx idx 5 test.t1.a1 2 100.00 Using where
1 SIMPLE t5 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`a1` AS `a1`,`test`.`t2`.`pk` AS `pk`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`c2` AS `c2`,`test`.`t2`.`d2` AS `d2`,`test`.`t3`.`pk` AS `pk`,`test`.`t3`.`a3` AS `a3`,`test`.`t3`.`c3` AS `c3`,`test`.`t3`.`d3` AS `d3`,`test`.`t4`.`pk` AS `pk`,`test`.`t4`.`a4` AS `a4`,`test`.`t5`.`pk` AS `pk`,`test`.`t5`.`a5` AS `a5` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t2`.`d2` = `test`.`t1`.`pk`) and (`test`.`t3`.`a3` = `test`.`t2`.`c2`))) left join `test`.`t4` on(((`test`.`t4`.`a4` = `test`.`t1`.`a1`) and (`test`.`t1`.`a1` is not null))) left join `test`.`t5` on((`test`.`t5`.`a5` = `test`.`t3`.`a3`)) where 1
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
pk a1 pk a2 c2 d2 pk a3 c3 d3 pk a4 pk a5
2 NULL 9 0 0 2 9 0 0 2 NULL NULL 2 0
2 NULL 9 0 0 2 1 0 0 7 NULL NULL 2 0
2 NULL 9 0 0 2 9 0 0 2 NULL NULL 8 0
2 NULL 9 0 0 2 1 0 0 7 NULL NULL 8 0
8 0 NULL NULL NULL NULL NULL NULL NULL NULL 8 0 NULL NULL
SET SESSION join_cache_level = 1;
EXPLAIN EXTENDED
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
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 2 100.00 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where
1 SIMPLE t4 ref idx idx 5 test.t1.a1 2 100.00 Using where
1 SIMPLE t5 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`a1` AS `a1`,`test`.`t2`.`pk` AS `pk`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`c2` AS `c2`,`test`.`t2`.`d2` AS `d2`,`test`.`t3`.`pk` AS `pk`,`test`.`t3`.`a3` AS `a3`,`test`.`t3`.`c3` AS `c3`,`test`.`t3`.`d3` AS `d3`,`test`.`t4`.`pk` AS `pk`,`test`.`t4`.`a4` AS `a4`,`test`.`t5`.`pk` AS `pk`,`test`.`t5`.`a5` AS `a5` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t2`.`d2` = `test`.`t1`.`pk`) and (`test`.`t3`.`a3` = `test`.`t2`.`c2`))) left join `test`.`t4` on(((`test`.`t4`.`a4` = `test`.`t1`.`a1`) and (`test`.`t1`.`a1` is not null))) left join `test`.`t5` on((`test`.`t5`.`a5` = `test`.`t3`.`a3`)) where 1
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
pk a1 pk a2 c2 d2 pk a3 c3 d3 pk a4 pk a5
2 NULL 9 0 0 2 9 0 0 2 NULL NULL 2 0
2 NULL 9 0 0 2 1 0 0 7 NULL NULL 2 0
2 NULL 9 0 0 2 9 0 0 2 NULL NULL 8 0
2 NULL 9 0 0 2 1 0 0 7 NULL NULL 8 0
8 0 NULL NULL NULL NULL NULL NULL NULL NULL 8 0 NULL NULL
SET SESSION optimizer_switch = 'outer_join_with_cache=off';
SET SESSION join_cache_level = DEFAULT;
DROP TABLE t1,t2,t3,t4,t5;
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
...@@ -2522,5 +2522,62 @@ SET SESSION join_cache_level = DEFAULT; ...@@ -2522,5 +2522,62 @@ SET SESSION join_cache_level = DEFAULT;
DROP TABLE t1,t2; DROP TABLE t1,t2;
--echo #
--echo # Bug #675095: nested outer join using join buffer
--echo #
CREATE TABLE t1 (pk int, a1 int) ;
INSERT IGNORE INTO t1 VALUES (2,NULL), (8,0);
CREATE TABLE t2 (pk int, a2 int, c2 int, d2 int) ;
INSERT IGNORE INTO t2 VALUES (9,0,0,2), (1,0,0,7);
CREATE TABLE t3 (pk int, a3 int, c3 int, d3 int) ;
INSERT IGNORE INTO t3 VALUES (9,0,0,2), (1,0,0,7);
CREATE TABLE t4 (pk int, a4 int, INDEX idx(a4)) ;
INSERT IGNORE INTO t4 VALUES (2,NULL), (8,0);
CREATE TABLE t5 (pk int, a5 int) ;
INSERT IGNORE INTO t5 VALUES (2,0), (8,0);
SET SESSION optimizer_switch = 'outer_join_with_cache=on';
SET SESSION join_cache_level = 0;
EXPLAIN EXTENDED
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
SET SESSION join_cache_level = 2;
EXPLAIN EXTENDED
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
SET SESSION join_cache_level = 1;
EXPLAIN EXTENDED
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
SELECT *
FROM ((t1 LEFT JOIN (t2 JOIN t3 ON t2.c2 = t3.a3) ON t1.pk = t2.d2)
LEFT JOIN t4 ON t1.a1 = t4.a4) LEFT JOIN t5 ON t3.a3 = t5.a5;
SET SESSION optimizer_switch = 'outer_join_with_cache=off';
SET SESSION join_cache_level = DEFAULT;
DROP TABLE t1,t2,t3,t4,t5;
# this must be the last command in the file # this must be the last command in the file
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
...@@ -7149,6 +7149,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -7149,6 +7149,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
used_tables2|= current_map; used_tables2|= current_map;
COND *tmp_cond= make_cond_for_table(on_expr, used_tables2, COND *tmp_cond= make_cond_for_table(on_expr, used_tables2,
current_map, FALSE, FALSE); current_map, FALSE, FALSE);
if (tab == first_inner_tab && tab->on_precond)
add_cond_and_fix(&tmp_cond, tab->on_precond); add_cond_and_fix(&tmp_cond, tab->on_precond);
if (tmp_cond) if (tmp_cond)
{ {
...@@ -7657,7 +7658,7 @@ uint check_join_cache_usage(JOIN_TAB *tab, ...@@ -7657,7 +7658,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
/* /*
Non-linked join buffers can't guarantee one match Non-linked join buffers can't guarantee one match
*/ */
if (force_unlinked_cache && if ((force_unlinked_cache || cache_level == 1) &&
((tab->is_inner_table_of_semi_join_with_first_match() && ((tab->is_inner_table_of_semi_join_with_first_match() &&
!tab->is_single_inner_of_semi_join_with_first_match()) || !tab->is_single_inner_of_semi_join_with_first_match()) ||
(tab->is_inner_table_of_outer_join() && (tab->is_inner_table_of_outer_join() &&
...@@ -7756,7 +7757,7 @@ uint check_join_cache_usage(JOIN_TAB *tab, ...@@ -7756,7 +7757,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
(cache_level <= 6 || no_hashed_cache)) (cache_level <= 6 || no_hashed_cache))
goto no_join_cache; goto no_join_cache;
if (prev_tab->cache and cache_level==7) if (prev_tab->cache && cache_level==7)
cache_level= 6; cache_level= 6;
if ((rows != HA_POS_ERROR) && !(flags & HA_MRR_USE_DEFAULT_IMPL)) if ((rows != HA_POS_ERROR) && !(flags & HA_MRR_USE_DEFAULT_IMPL))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment