Commit 3ccc1d6b authored by Igor Babaev's avatar Igor Babaev

Corrected Evgen's fix for bug #45191.

Made sure that join buffers could be used for inner tables of
any semi-join when the first match strategy is employed.
parent 3752aa72
...@@ -713,9 +713,9 @@ c2 in (select 1 from t3, t2) and ...@@ -713,9 +713,9 @@ c2 in (select 1 from t3, t2) and
c1 in (select convert(c6,char(1)) from t2); c1 in (select convert(c6,char(1)) from t2);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using join buffer
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; Using join buffer
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch(t2) 1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch(t2); Using join buffer
drop table t2, t3; drop table t2, t3;
set join_cache_level=default; set join_cache_level=default;
show variables like 'join_cache_level'; show variables like 'join_cache_level';
......
...@@ -374,8 +374,8 @@ WHERE PNUM IN ...@@ -374,8 +374,8 @@ WHERE PNUM IN
(SELECT PNUM FROM PROJ)); (SELECT PNUM FROM PROJ));
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY STAFF ALL NULL NULL NULL NULL 5 1 PRIMARY STAFF ALL NULL NULL NULL NULL 5
1 PRIMARY PROJ ALL NULL NULL NULL NULL 6 1 PRIMARY PROJ ALL NULL NULL NULL NULL 6 Using join buffer
1 PRIMARY WORKS ALL NULL NULL NULL NULL 12 Using where; FirstMatch(STAFF) 1 PRIMARY WORKS ALL NULL NULL NULL NULL 12 Using where; FirstMatch(STAFF); Using join buffer
SELECT EMPNUM, EMPNAME SELECT EMPNUM, EMPNAME
FROM STAFF FROM STAFF
WHERE EMPNUM IN WHERE EMPNUM IN
......
...@@ -408,7 +408,9 @@ void JOIN_CACHE::set_constants() ...@@ -408,7 +408,9 @@ void JOIN_CACHE::set_constants()
the cache or not. Later when a referenced field is registered for the cache the cache or not. Later when a referenced field is registered for the cache
we adjust the value of the flag 'with_length'. we adjust the value of the flag 'with_length'.
*/ */
with_length= is_key_access() || with_match_flag; with_length= is_key_access() ||
join_tab->is_inner_table_of_semi_join_with_first_match() ||
join_tab->is_inner_table_of_outer_join();
/* /*
At this moment we don't know yet the value of 'referenced_fields', At this moment we don't know yet the value of 'referenced_fields',
but in any case it can't be greater than the value of 'fields'. but in any case it can't be greater than the value of 'fields'.
...@@ -1304,7 +1306,7 @@ bool JOIN_CACHE::get_match_flag_by_pos(uchar *rec_ptr) ...@@ -1304,7 +1306,7 @@ bool JOIN_CACHE::get_match_flag_by_pos(uchar *rec_ptr)
uchar *prev_rec_ptr= prev_cache->get_rec_ref(rec_ptr); uchar *prev_rec_ptr= prev_cache->get_rec_ref(rec_ptr);
return prev_cache->get_match_flag_by_pos(prev_rec_ptr); return prev_cache->get_match_flag_by_pos(prev_rec_ptr);
} }
DBUG_ASSERT(1); DBUG_ASSERT(0);
return FALSE; return FALSE;
} }
...@@ -1538,12 +1540,12 @@ bool JOIN_CACHE::read_referenced_field(CACHE_FIELD *copy, ...@@ -1538,12 +1540,12 @@ bool JOIN_CACHE::read_referenced_field(CACHE_FIELD *copy,
bool JOIN_CACHE::skip_record_if_match() bool JOIN_CACHE::skip_record_if_match()
{ {
DBUG_ASSERT(with_match_flag && with_length); DBUG_ASSERT(with_length);
uint offset= size_of_rec_len; uint offset= size_of_rec_len;
if (prev_cache) if (prev_cache)
offset+= prev_cache->get_size_of_rec_offset(); offset+= prev_cache->get_size_of_rec_offset();
/* Check whether the match flag is on */ /* Check whether the match flag is on */
if (test(*(pos+offset))) if (get_match_flag_by_pos(pos+offset))
{ {
pos+= size_of_rec_len + get_rec_length(pos); pos+= size_of_rec_len + get_rec_length(pos);
return TRUE; return TRUE;
......
...@@ -6352,10 +6352,17 @@ make_outerjoin_info(JOIN *join) ...@@ -6352,10 +6352,17 @@ make_outerjoin_info(JOIN *join)
} }
if (!tab->first_inner) if (!tab->first_inner)
tab->first_inner= nested_join->first_nested; tab->first_inner= nested_join->first_nested;
if (tab->table->reginfo.not_exists_optimize)
tab->first_inner->table->reginfo.not_exists_optimize= 1;
if (++nested_join->counter < nested_join->n_tables) if (++nested_join->counter < nested_join->n_tables)
break; break;
/* Table tab is the last inner table for nested join. */ /* Table tab is the last inner table for nested join. */
nested_join->first_nested->last_inner= tab; nested_join->first_nested->last_inner= tab;
if (tab->first_inner->table->reginfo.not_exists_optimize)
{
for (JOIN_TAB *join_tab= tab->first_inner; join_tab <= tab; join_tab++)
join_tab->table->reginfo.not_exists_optimize= 1;
}
} }
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -7108,19 +7115,15 @@ uint check_join_cache_usage(JOIN_TAB *tab, ...@@ -7108,19 +7115,15 @@ uint check_join_cache_usage(JOIN_TAB *tab,
*/ */
if (tab->use_quick == 2) if (tab->use_quick == 2)
goto no_join_cache; goto no_join_cache;
/*
Use join cache with FirstMatch semi-join strategy only when semi-join
contains only one table.
*/
if (tab->is_inner_table_of_semi_join_with_first_match() &&
!tab->is_single_inner_of_semi_join_with_first_match())
goto no_join_cache;
/* /*
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 &&
(!tab->type == JT_ALL || cache_level <= 4) &&
((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() && (tab->is_inner_table_of_outer_join() &&
!tab->is_single_inner_of_outer_join())) !tab->is_single_inner_of_outer_join())))
goto no_join_cache; goto no_join_cache;
/* /*
......
...@@ -321,8 +321,8 @@ typedef struct st_join_table { ...@@ -321,8 +321,8 @@ typedef struct st_join_table {
} }
bool check_only_first_match() bool check_only_first_match()
{ {
return last_sj_inner_tab == this || return is_inner_table_of_semi_join_with_first_match() ||
(first_inner && first_inner->last_inner == this && (is_inner_table_of_outer_join() &&
table->reginfo.not_exists_optimize); table->reginfo.not_exists_optimize);
} }
bool is_last_inner_table() bool is_last_inner_table()
......
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