MDEV-5011: ERROR Plugin 'MEMORY' has ref_count=1 after shutdown for SJM queries

- Provide a special execution path for cleanup of degenerate 
  non-merged semi-join children of degenerate selects.
This commit is contained in:
Sergey Petrunya 2013-09-12 13:53:13 +04:00
commit 7e4845beea
6 changed files with 73 additions and 0 deletions

View file

@ -5174,6 +5174,12 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
DBUG_RETURN(1);
table->table= dummy_table;
table->table->pos_in_table_list= table;
/*
Note: the table created above may be freed by:
1. JOIN_TAB::cleanup(), when the parent join is a regular join.
2. cleanup_empty_jtbm_semi_joins(), when the parent join is a
degenerate join (e.g. one with "Impossible where").
*/
setup_table_map(table->table, table, table->jtbm_table_no);
}
else
@ -5206,6 +5212,42 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
}
/*
Cleanup non-merged semi-joins (JBMs) that have empty.
This function is to cleanups for a special case:
Consider a query like
select * from t1 where 1=2 AND t1.col IN (select max(..) ... having 1=2)
For this query, optimization of subquery will short-circuit, and
setup_jtbm_semi_joins() will call create_dummy_tmp_table() so that we have
empty, constant temp.table to stand in as materialized temp. table.
Now, suppose that the upper join is also found to be degenerate. In that
case, no JOIN_TAB array will be produced, and hence, JOIN::cleanup() will
have a problem with cleaning up empty JTBMs (non-empty ones are cleaned up
through Item::cleanup() calls).
*/
void cleanup_empty_jtbm_semi_joins(JOIN *join)
{
List_iterator<TABLE_LIST> li(*join->join_list);
TABLE_LIST *table;
while ((table= li++))
{
if ((table->jtbm_subselect && table->jtbm_subselect->is_jtbm_const_tab))
{
if (table->table)
{
free_tmp_table(join->thd, table->table);
table->table= NULL;
}
}
}
}
/**
Choose an optimal strategy to execute an IN/ALL/ANY subquery predicate
based on cost.

View file

@ -12,6 +12,7 @@ int pull_out_semijoin_tables(JOIN *join);
bool optimize_semijoin_nests(JOIN *join, table_map all_table_map);
bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
Item **join_where);
void cleanup_empty_jtbm_semi_joins(JOIN *join);
// used by Loose_scan_opt
ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest,

View file

@ -10125,6 +10125,11 @@ void JOIN_TAB::cleanup()
{
if (table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
{
/*
Set this to NULL so that cleanup_empty_jtbm_semi_joins() doesn't
attempt to make another free_tmp_table call.
*/
table->pos_in_table_list->table= NULL;
free_tmp_table(join->thd, table);
table= NULL;
}
@ -10461,6 +10466,7 @@ void JOIN::cleanup(bool full)
}
if (full)
{
cleanup_empty_jtbm_semi_joins(this);
/*
Ensure that the following delete_elements() would not be called
twice for the same list.