mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
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.
This commit is contained in:
parent
9441a9cc28
commit
42cd36431b
3 changed files with 144 additions and 3 deletions
|
@ -5838,4 +5838,87 @@ pk a a
|
|||
SET SESSION optimizer_switch = 'outer_join_with_cache=off';
|
||||
SET SESSION join_cache_level = DEFAULT;
|
||||
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;
|
||||
|
|
|
@ -2522,5 +2522,62 @@ SET SESSION join_cache_level = DEFAULT;
|
|||
|
||||
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
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
|
|
@ -7149,7 +7149,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||
used_tables2|= current_map;
|
||||
COND *tmp_cond= make_cond_for_table(on_expr, used_tables2,
|
||||
current_map, FALSE, FALSE);
|
||||
add_cond_and_fix(&tmp_cond, tab->on_precond);
|
||||
if (tab == first_inner_tab && tab->on_precond)
|
||||
add_cond_and_fix(&tmp_cond, tab->on_precond);
|
||||
if (tmp_cond)
|
||||
{
|
||||
JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab;
|
||||
|
@ -7657,7 +7658,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
|
|||
/*
|
||||
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_single_inner_of_semi_join_with_first_match()) ||
|
||||
(tab->is_inner_table_of_outer_join() &&
|
||||
|
@ -7756,7 +7757,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
|
|||
(cache_level <= 6 || no_hashed_cache))
|
||||
goto no_join_cache;
|
||||
|
||||
if (prev_tab->cache and cache_level==7)
|
||||
if (prev_tab->cache && cache_level==7)
|
||||
cache_level= 6;
|
||||
|
||||
if ((rows != HA_POS_ERROR) && !(flags & HA_MRR_USE_DEFAULT_IMPL))
|
||||
|
|
Loading…
Reference in a new issue