1
0
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:
Igor Babaev
2019-06-09 10:39:52 -07:00
parent 6660c072ad
commit 6db2ebbb2a
9 changed files with 331 additions and 19 deletions

View File

@ -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