mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Fixed LP bug #817360.
This problem could be observed for queries with nested outer joins for which the not_exist optimization were applicable. The problem was caused by the code of the patch for bug #49322 that erroneously forced the return to the previous nested loop level when the join algorithm successfully builds a partial record for an embedded outer to which the not_exist optimization could be applied. Actually the immediate return to the previous nested loops level is correct only if this partial record is rejected by a predicate pushed down to one of the inner tables of this outer join. Otherwise attempts to find extensions of this record must be made.
This commit is contained in:
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user