mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-27624 Wrong result for nested left join using not_exists optimization
This bug affected queries with nested left joins having the same last inner table such that not_exists optimization could be applied to the most inner outer join when optimizer chose to use join buffers. The bug could lead to producing wrong a result set. If the WHERE condition a query contains a conjunctive IS NULL predicate over a non-nullable column of an inner table of a not nested outer join then not_exists optimization can be applied to tho the outer join. With this optimization when looking for matches for a certain record from the outer table of the join the records of the inner table can be ignored right after the first match satisfying the ON condition is found. In the case of nested outer joins having the same last inner table this optimization still can be applied but only if all ON conditions of the embedding outer joins are satisfied. Such check was missing in the code that tried to apply not_exists optimization when join buffers were used for outer join operations. This problem has been already fixed in the patch for bug MDEV-7992. Yet there it was resolved only for the cases when join buffers were not used for outer joins. Approved by Oleksandr Byelkin <sanja@mariadb.com>
This commit is contained in:
@ -2287,11 +2287,7 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
|
||||
int error;
|
||||
enum_nested_loop_state rc= NESTED_LOOP_OK;
|
||||
join_tab->table->null_row= 0;
|
||||
bool check_only_first_match=
|
||||
join_tab->check_only_first_match() &&
|
||||
(!join_tab->first_inner || // semi-join case
|
||||
join_tab->first_inner == join_tab->first_unmatched); // outer join case
|
||||
bool outer_join_first_inner= join_tab->is_first_inner_for_outer_join();
|
||||
bool check_only_first_match= join_tab->check_only_first_match();
|
||||
DBUG_ENTER("JOIN_CACHE::join_matching_records");
|
||||
|
||||
/* Return at once if there are no records in the join buffer */
|
||||
@ -2355,7 +2351,34 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
|
||||
Also those records that must be null complemented are not considered
|
||||
as candidates for matches.
|
||||
*/
|
||||
if ((!check_only_first_match && !outer_join_first_inner) ||
|
||||
|
||||
bool not_exists_opt_is_applicable= true;
|
||||
if (check_only_first_match && join_tab->first_inner)
|
||||
{
|
||||
/*
|
||||
This is the case with not_exists optimization for nested outer join
|
||||
when join_tab is the last inner table for one or more embedding outer
|
||||
joins. To safely use 'not_exists' optimization in this case we have
|
||||
to check that the match flags for all these embedding outer joins are
|
||||
in the 'on' state.
|
||||
(See also a similar check in evaluate_join_record() for the case when
|
||||
join buffer are not used.)
|
||||
*/
|
||||
for (JOIN_TAB *tab= join_tab->first_inner;
|
||||
tab && tab->first_inner && tab->last_inner == join_tab;
|
||||
tab= tab->first_inner->first_upper)
|
||||
{
|
||||
if (get_match_flag_by_pos_from_join_buffer(rec_ptr, tab) !=
|
||||
MATCH_FOUND)
|
||||
{
|
||||
not_exists_opt_is_applicable= false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!check_only_first_match ||
|
||||
(join_tab->first_inner && !not_exists_opt_is_applicable) ||
|
||||
!skip_next_candidate_for_match(rec_ptr))
|
||||
{
|
||||
read_next_candidate_for_match(rec_ptr);
|
||||
|
Reference in New Issue
Block a user