summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/subselect_mat.result8
-rw-r--r--mysql-test/r/subselect_sj_mat.result8
-rw-r--r--mysql-test/t/subselect_sj_mat.test8
-rw-r--r--sql/opt_subselect.cc42
-rw-r--r--sql/opt_subselect.h1
-rw-r--r--sql/sql_select.cc6
6 files changed, 73 insertions, 0 deletions
diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result
index 088d09c6dde..e1c9df3b00b 100644
--- a/mysql-test/r/subselect_mat.result
+++ b/mysql-test/r/subselect_mat.result
@@ -2029,6 +2029,14 @@ SELECT * FROM t1 WHERE 8 IN ( SELECT MIN(pk) FROM t1 ) AND ( pk = a OR pk = b );
pk a b
drop table t1;
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
set @subselect_mat_test_optimizer_switch_value=null;
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result
index 6f1694944d8..bcdd82b790c 100644
--- a/mysql-test/r/subselect_sj_mat.result
+++ b/mysql-test/r/subselect_sj_mat.result
@@ -2069,4 +2069,12 @@ SELECT * FROM t1 WHERE 8 IN ( SELECT MIN(pk) FROM t1 ) AND ( pk = a OR pk = b );
pk a b
drop table t1;
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
diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test
index 935c0e76937..e9226b8884f 100644
--- a/mysql-test/t/subselect_sj_mat.test
+++ b/mysql-test/t/subselect_sj_mat.test
@@ -1717,4 +1717,12 @@ SELECT * FROM t1 WHERE 8 IN ( SELECT MIN(pk) FROM t1 ) AND ( pk = a OR pk = b );
drop table t1;
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
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 85df9a47152..c9bc0289ba9 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -5231,6 +5231,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
@@ -5263,6 +5269,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.
diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h
index 7b8f3142851..1e8b4cc50a1 100644
--- a/sql/opt_subselect.h
+++ b/sql/opt_subselect.h
@@ -28,6 +28,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,
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b7ba2fb7b58..b5ecaecda89 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -10314,6 +10314,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;
}
@@ -10727,6 +10732,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.