Commit 7ddd5418 authored by unknown's avatar unknown

Fixed bug MDEV-288

CHEAP SQ: Valgrind warnings "Memory lost" with IN and EXISTS nested subquery, materialization+semijoin

Analysis:
The memory leak was a result of the interaction of semi-join optimization
with early optimization of constant subqueries. The function:
setup_jtbm_semi_joins() created a dummy temporary table "dummy_table"
in order to make some JOIN_TAB objects complete. Normally, such temporary
tables are freed inside JOIN_TAB::cleanup.

However, the inner-most subquery is pre-optimized, which allows the
optimization fo the MAX subquery to determine that its WHERE is TRUE,
and thus to compute the result of the MAX during optimization. This
ultimately allows the optimize phase of the outer query to find that
it WHERE clause is FALSE. Once JOIN::optimize finds that the result
set is empty, it sets zero_result_cause, and returns *before* it ever
reached make_join_statistics(). As a result the query plan has no
JOIN_TABs at all. Since the temporary table is supposed to be cleanup
via JOIN_TAB::cleanup, this never happens because there is no JOIN_TAB
for this table. Hence we get a memory leak.

Solution:
Whenever there are no JOIN_TABs, iterate over all table reference in
JOIN::join_list, and free the ones that contain semi-join temporary
tables.
parent 941018f8
......@@ -6700,5 +6700,21 @@ Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 16
drop table t1, t2, t3;
#
# MDEV-288 CHEAP SQ: Valgrind warnings "Memory lost" with IN and EXISTS nested subquery, materialization+semijoin
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0),(8);
CREATE TABLE t2 (b INT PRIMARY KEY);
INSERT INTO t2 VALUES (1),(2);
EXPLAIN
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
3 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
a
drop table t1,t2;
# return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp;
......@@ -6698,6 +6698,22 @@ Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 16
drop table t1, t2, t3;
#
# MDEV-288 CHEAP SQ: Valgrind warnings "Memory lost" with IN and EXISTS nested subquery, materialization+semijoin
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0),(8);
CREATE TABLE t2 (b INT PRIMARY KEY);
INSERT INTO t2 VALUES (1),(2);
EXPLAIN
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
3 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
a
drop table t1,t2;
# return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp;
set optimizer_switch=default;
......
......@@ -6695,6 +6695,22 @@ Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 16
drop table t1, t2, t3;
#
# MDEV-288 CHEAP SQ: Valgrind warnings "Memory lost" with IN and EXISTS nested subquery, materialization+semijoin
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0),(8);
CREATE TABLE t2 (b INT PRIMARY KEY);
INSERT INTO t2 VALUES (1),(2);
EXPLAIN
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
3 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
a
drop table t1,t2;
# return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp;
set @optimizer_switch_for_subselect_test=null;
......@@ -6706,6 +6706,22 @@ Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 16
drop table t1, t2, t3;
#
# MDEV-288 CHEAP SQ: Valgrind warnings "Memory lost" with IN and EXISTS nested subquery, materialization+semijoin
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0),(8);
CREATE TABLE t2 (b INT PRIMARY KEY);
INSERT INTO t2 VALUES (1),(2);
EXPLAIN
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
3 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
a
drop table t1,t2;
# return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp;
set optimizer_switch=default;
......
......@@ -6695,6 +6695,22 @@ Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 16
drop table t1, t2, t3;
#
# MDEV-288 CHEAP SQ: Valgrind warnings "Memory lost" with IN and EXISTS nested subquery, materialization+semijoin
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0),(8);
CREATE TABLE t2 (b INT PRIMARY KEY);
INSERT INTO t2 VALUES (1),(2);
EXPLAIN
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
3 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
a
drop table t1,t2;
# return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp;
set @optimizer_switch_for_subselect_test=null;
......
......@@ -5624,5 +5624,22 @@ show status like '%Handler_read%';
drop table t1, t2, t3;
--echo #
--echo # MDEV-288 CHEAP SQ: Valgrind warnings "Memory lost" with IN and EXISTS nested subquery, materialization+semijoin
--echo #
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0),(8);
CREATE TABLE t2 (b INT PRIMARY KEY);
INSERT INTO t2 VALUES (1),(2);
EXPLAIN
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2 WHERE EXISTS (SELECT * FROM t1));
drop table t1,t2;
--echo # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp;
......@@ -10595,6 +10595,22 @@ void JOIN::cleanup(bool full)
tmp_join->tmp_table_param.save_copy_field= 0;
}
tmp_table_param.cleanup();
if (!join_tab)
{
List_iterator<TABLE_LIST> li(*join_list);
TABLE_LIST *table_ref;
while ((table_ref= li++))
{
if (table_ref->table &&
table_ref->jtbm_subselect &&
table_ref->jtbm_subselect->is_jtbm_const_tab)
{
free_tmp_table(thd, table_ref->table);
table_ref->table= NULL;
}
}
}
}
DBUG_VOID_RETURN;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment