mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
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.
This commit is contained in:
parent
941018f8d1
commit
7ddd5418d0
7 changed files with 113 additions and 0 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue