mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-19580 Unrelated JOINs corrupt usage of 'WHERE function() IN (subquery)'
Handling of top level conjuncts in WHERE whose used_tables() contained RAND_TABLE_BIT in the function make_join_select() was incorrect. As a result if such a conjunct referred to fields non of which belonged to the last joined table it was pushed twice. (This could be seen for a test case from subselect.test whose output was changed after this patch had been applied. In 10.1 when running EXPLAIN FORMAT=JSON for the query from this test case we clearly see that one of the conjuncts is pushed twice.) This fact by itself was not good. Besides, if such a conjunct was pushed to a table that was the result of materialization of a semi-join the query could return a wrong result set. In particular we could watch it for queries with semi-join subqueries whose left parts used stored functions without "deterministic' specifier.
This commit is contained in:
@ -204,7 +204,8 @@ static COND *make_cond_for_table_from_pred(THD *thd, Item *root_cond,
|
||||
table_map used_table,
|
||||
int join_tab_idx_arg,
|
||||
bool exclude_expensive_cond,
|
||||
bool retain_ref_cond);
|
||||
bool retain_ref_cond,
|
||||
bool is_top_and_level);
|
||||
|
||||
static Item* part_of_refkey(TABLE *form,Field *field);
|
||||
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
|
||||
@ -8922,12 +8923,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
||||
RAND_TABLE_BIT;
|
||||
}
|
||||
|
||||
/*
|
||||
Following force including random expression in last table condition.
|
||||
It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
|
||||
*/
|
||||
if (tab == join->join_tab + last_top_base_tab_idx)
|
||||
current_map|= RAND_TABLE_BIT;
|
||||
used_tables|=current_map;
|
||||
|
||||
if (tab->type == JT_REF && tab->quick &&
|
||||
@ -8968,6 +8963,20 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
||||
{
|
||||
tmp= make_cond_for_table(thd, cond, used_tables, current_map, i,
|
||||
FALSE, FALSE);
|
||||
if (tab == join->join_tab + last_top_base_tab_idx)
|
||||
{
|
||||
/*
|
||||
This pushes conjunctive conditions of WHERE condition such that:
|
||||
- their used_tables() contain RAND_TABLE_BIT
|
||||
- the conditions does not refer to any fields
|
||||
(such like rand() > 0.5)
|
||||
*/
|
||||
table_map rand_table_bit= (table_map) RAND_TABLE_BIT;
|
||||
COND *rand_cond= make_cond_for_table(thd, cond, used_tables,
|
||||
rand_table_bit, -1,
|
||||
FALSE, FALSE);
|
||||
add_cond_and_fix(thd, &tmp, rand_cond);
|
||||
}
|
||||
}
|
||||
/* Add conditions added by add_not_null_conds(). */
|
||||
if (tab->select_cond)
|
||||
@ -9283,8 +9292,24 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
||||
psergey: have put the -1 below. It's bad, will need to fix it.
|
||||
*/
|
||||
COND *tmp_cond= make_cond_for_table(thd, on_expr, used_tables2,
|
||||
current_map, /*(tab - first_tab)*/ -1,
|
||||
FALSE, FALSE);
|
||||
current_map,
|
||||
/*(tab - first_tab)*/ -1,
|
||||
FALSE, FALSE);
|
||||
if (tab == last_tab)
|
||||
{
|
||||
/*
|
||||
This pushes conjunctive conditions of ON expression of an outer
|
||||
join such that:
|
||||
- their used_tables() contain RAND_TABLE_BIT
|
||||
- the conditions does not refer to any fields
|
||||
(such like rand() > 0.5)
|
||||
*/
|
||||
table_map rand_table_bit= (table_map) RAND_TABLE_BIT;
|
||||
COND *rand_cond= make_cond_for_table(thd, on_expr, used_tables2,
|
||||
rand_table_bit, -1,
|
||||
FALSE, FALSE);
|
||||
add_cond_and_fix(thd, &tmp_cond, rand_cond);
|
||||
}
|
||||
bool is_sjm_lookup_tab= FALSE;
|
||||
if (tab->bush_children)
|
||||
{
|
||||
@ -18824,7 +18849,7 @@ make_cond_for_table(THD *thd, Item *cond, table_map tables,
|
||||
return make_cond_for_table_from_pred(thd, cond, cond, tables, used_table,
|
||||
join_tab_idx_arg,
|
||||
exclude_expensive_cond,
|
||||
retain_ref_cond);
|
||||
retain_ref_cond, true);
|
||||
}
|
||||
|
||||
|
||||
@ -18834,9 +18859,12 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
|
||||
int join_tab_idx_arg,
|
||||
bool exclude_expensive_cond __attribute__
|
||||
((unused)),
|
||||
bool retain_ref_cond)
|
||||
bool retain_ref_cond,
|
||||
bool is_top_and_level)
|
||||
|
||||
{
|
||||
table_map rand_table_bit= (table_map) RAND_TABLE_BIT;
|
||||
|
||||
if (used_table && !(cond->used_tables() & used_table))
|
||||
return (COND*) 0; // Already checked
|
||||
|
||||
@ -18852,11 +18880,28 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
{
|
||||
/*
|
||||
Special handling of top level conjuncts with RAND_TABLE_BIT:
|
||||
if such a conjunct contains a reference to a field that is not
|
||||
an outer field then it is pushed to the corresponding table by
|
||||
the same rule as all other conjuncts. Otherwise, if the conjunct
|
||||
is used in WHERE is is pushed to the last joined table, if is it
|
||||
is used in ON condition of an outer join it is pushed into the
|
||||
last inner table of the outer join. Such conjuncts are pushed in
|
||||
a call of make_cond_for_table_from_pred() with the
|
||||
parameter 'used_table' equal to PSEUDO_TABLE_BITS.
|
||||
*/
|
||||
if (is_top_and_level && used_table == rand_table_bit &&
|
||||
(item->used_tables() & ~OUTER_REF_TABLE_BIT) != rand_table_bit)
|
||||
{
|
||||
/* The conjunct with RAND_TABLE_BIT has been allready pushed */
|
||||
continue;
|
||||
}
|
||||
Item *fix=make_cond_for_table_from_pred(thd, root_cond, item,
|
||||
tables, used_table,
|
||||
join_tab_idx_arg,
|
||||
join_tab_idx_arg,
|
||||
exclude_expensive_cond,
|
||||
retain_ref_cond);
|
||||
retain_ref_cond, false);
|
||||
if (fix)
|
||||
new_cond->argument_list()->push_back(fix);
|
||||
}
|
||||
@ -18880,6 +18925,13 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
|
||||
}
|
||||
else
|
||||
{ // Or list
|
||||
if (is_top_and_level && used_table == rand_table_bit &&
|
||||
(cond->used_tables() & ~OUTER_REF_TABLE_BIT) != rand_table_bit)
|
||||
{
|
||||
/* This top level formula with RAND_TABLE_BIT has been already pushed */
|
||||
return (COND*) 0;
|
||||
}
|
||||
|
||||
Item_cond_or *new_cond=new Item_cond_or;
|
||||
if (!new_cond)
|
||||
return (COND*) 0; // OOM /* purecov: inspected */
|
||||
@ -18891,7 +18943,7 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
|
||||
tables, 0L,
|
||||
join_tab_idx_arg,
|
||||
exclude_expensive_cond,
|
||||
retain_ref_cond);
|
||||
retain_ref_cond, false);
|
||||
if (!fix)
|
||||
return (COND*) 0; // Always true
|
||||
new_cond->argument_list()->push_back(fix);
|
||||
@ -18908,6 +18960,13 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
|
||||
}
|
||||
}
|
||||
|
||||
if (is_top_and_level && used_table == rand_table_bit &&
|
||||
(cond->used_tables() & ~OUTER_REF_TABLE_BIT) != rand_table_bit)
|
||||
{
|
||||
/* This top level formula with RAND_TABLE_BIT has been already pushed */
|
||||
return (COND*) 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Because the following test takes a while and it can be done
|
||||
table_count times, we mark each item that we have examined with the result
|
||||
|
Reference in New Issue
Block a user