Commit 537da13f 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 0599a4e0
...@@ -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
......
...@@ -407,8 +407,10 @@ void JOIN_CACHE::set_constants() ...@@ -407,8 +407,10 @@ void JOIN_CACHE::set_constants()
However at this moment we don't know whether we have referenced fields for However at this moment we don't know whether we have referenced fields for
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->is_inner_table_of_outer_join() && (!tab->type == JT_ALL || cache_level <= 4) &&
!tab->is_single_inner_of_outer_join())) ((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_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