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:
parent
c2b38529a9
commit
7e4845beea
@ -2015,6 +2015,14 @@ SELECT * FROM t1 WHERE 8 IN ( SELECT MIN(pk) FROM t1 ) AND ( pk = a OR pk = b );
|
|||||||
pk a b
|
pk a b
|
||||||
drop table t1;
|
drop table t1;
|
||||||
SET optimizer_switch=@save_optimizer_switch;
|
SET optimizer_switch=@save_optimizer_switch;
|
||||||
|
#
|
||||||
|
# MDEV-5011: ERROR Plugin 'MEMORY' has ref_count=1 after shutdown for SJM queries
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (pk INT, a INT, b INT, PRIMARY KEY(pk)) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (1,3,5),(2,4,6);
|
||||||
|
SELECT * FROM t1 WHERE 8 IN (SELECT MIN(pk) FROM t1) AND (pk = a OR pk = b);
|
||||||
|
pk a b
|
||||||
|
DROP TABLE t1;
|
||||||
# End of 5.3 tests
|
# End of 5.3 tests
|
||||||
set @subselect_mat_test_optimizer_switch_value=null;
|
set @subselect_mat_test_optimizer_switch_value=null;
|
||||||
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
|
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
|
||||||
|
@ -2055,4 +2055,12 @@ SELECT * FROM t1 WHERE 8 IN ( SELECT MIN(pk) FROM t1 ) AND ( pk = a OR pk = b );
|
|||||||
pk a b
|
pk a b
|
||||||
drop table t1;
|
drop table t1;
|
||||||
SET optimizer_switch=@save_optimizer_switch;
|
SET optimizer_switch=@save_optimizer_switch;
|
||||||
|
#
|
||||||
|
# MDEV-5011: ERROR Plugin 'MEMORY' has ref_count=1 after shutdown for SJM queries
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (pk INT, a INT, b INT, PRIMARY KEY(pk)) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (1,3,5),(2,4,6);
|
||||||
|
SELECT * FROM t1 WHERE 8 IN (SELECT MIN(pk) FROM t1) AND (pk = a OR pk = b);
|
||||||
|
pk a b
|
||||||
|
DROP TABLE t1;
|
||||||
# End of 5.3 tests
|
# End of 5.3 tests
|
||||||
|
@ -1698,4 +1698,12 @@ SELECT * FROM t1 WHERE 8 IN ( SELECT MIN(pk) FROM t1 ) AND ( pk = a OR pk = b );
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
SET optimizer_switch=@save_optimizer_switch;
|
SET optimizer_switch=@save_optimizer_switch;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-5011: ERROR Plugin 'MEMORY' has ref_count=1 after shutdown for SJM queries
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (pk INT, a INT, b INT, PRIMARY KEY(pk)) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (1,3,5),(2,4,6);
|
||||||
|
SELECT * FROM t1 WHERE 8 IN (SELECT MIN(pk) FROM t1) AND (pk = a OR pk = b);
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
--echo # End of 5.3 tests
|
--echo # End of 5.3 tests
|
||||||
|
@ -5174,6 +5174,12 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
table->table= dummy_table;
|
table->table= dummy_table;
|
||||||
table->table->pos_in_table_list= 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);
|
setup_table_map(table->table, table, table->jtbm_table_no);
|
||||||
}
|
}
|
||||||
else
|
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
|
Choose an optimal strategy to execute an IN/ALL/ANY subquery predicate
|
||||||
based on cost.
|
based on cost.
|
||||||
|
@ -12,6 +12,7 @@ int pull_out_semijoin_tables(JOIN *join);
|
|||||||
bool optimize_semijoin_nests(JOIN *join, table_map all_table_map);
|
bool optimize_semijoin_nests(JOIN *join, table_map all_table_map);
|
||||||
bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
|
bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
|
||||||
Item **join_where);
|
Item **join_where);
|
||||||
|
void cleanup_empty_jtbm_semi_joins(JOIN *join);
|
||||||
|
|
||||||
// used by Loose_scan_opt
|
// used by Loose_scan_opt
|
||||||
ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest,
|
ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest,
|
||||||
|
@ -10125,6 +10125,11 @@ void JOIN_TAB::cleanup()
|
|||||||
{
|
{
|
||||||
if (table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
|
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);
|
free_tmp_table(join->thd, table);
|
||||||
table= NULL;
|
table= NULL;
|
||||||
}
|
}
|
||||||
@ -10461,6 +10466,7 @@ void JOIN::cleanup(bool full)
|
|||||||
}
|
}
|
||||||
if (full)
|
if (full)
|
||||||
{
|
{
|
||||||
|
cleanup_empty_jtbm_semi_joins(this);
|
||||||
/*
|
/*
|
||||||
Ensure that the following delete_elements() would not be called
|
Ensure that the following delete_elements() would not be called
|
||||||
twice for the same list.
|
twice for the same list.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user