Bug #45989 take 2 : memory leak after explain encounters an
error in the query. Fixes a leak after materializing a GROUP BY subquery to a temp table when the subquery has a blob column in the SELECT list. Fixed by correctly destructing temporary buffers for re-usable queries
This commit is contained in:
parent
8c65b726a5
commit
a89d88dc0a
@ -4615,4 +4615,16 @@ FROM t1,t1 a
|
|||||||
);
|
);
|
||||||
1
|
1
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# Bug #45989 take 2 : memory leak after explain encounters an
|
||||||
|
# error in the query
|
||||||
|
#
|
||||||
|
CREATE TABLE t1(a LONGTEXT);
|
||||||
|
INSERT INTO t1 VALUES (repeat('a',@@global.max_allowed_packet));
|
||||||
|
INSERT INTO t1 VALUES (repeat('b',@@global.max_allowed_packet));
|
||||||
|
EXPLAIN EXTENDED SELECT DISTINCT 1 FROM t1,
|
||||||
|
(SELECT DISTINCTROW a AS away FROM t1 GROUP BY a WITH ROLLUP) AS d1
|
||||||
|
WHERE t1.a = d1.a;
|
||||||
|
ERROR 42S22: Unknown column 'd1.a' in 'where clause'
|
||||||
|
DROP TABLE t1;
|
||||||
End of 5.1 tests.
|
End of 5.1 tests.
|
||||||
|
@ -3600,4 +3600,21 @@ SELECT 1 FROM t1 WHERE a <> SOME
|
|||||||
);
|
);
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug #45989 take 2 : memory leak after explain encounters an
|
||||||
|
--echo # error in the query
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1(a LONGTEXT);
|
||||||
|
INSERT INTO t1 VALUES (repeat('a',@@global.max_allowed_packet));
|
||||||
|
INSERT INTO t1 VALUES (repeat('b',@@global.max_allowed_packet));
|
||||||
|
|
||||||
|
--error ER_BAD_FIELD_ERROR
|
||||||
|
EXPLAIN EXTENDED SELECT DISTINCT 1 FROM t1,
|
||||||
|
(SELECT DISTINCTROW a AS away FROM t1 GROUP BY a WITH ROLLUP) AS d1
|
||||||
|
WHERE t1.a = d1.a;
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
--echo End of 5.1 tests.
|
--echo End of 5.1 tests.
|
||||||
|
@ -2313,6 +2313,12 @@ JOIN::destroy()
|
|||||||
tab->cleanup();
|
tab->cleanup();
|
||||||
}
|
}
|
||||||
tmp_join->tmp_join= 0;
|
tmp_join->tmp_join= 0;
|
||||||
|
/*
|
||||||
|
We need to clean up tmp_table_param for reusable JOINs (having non-zero
|
||||||
|
and different from self tmp_join) because it's not being cleaned up
|
||||||
|
anywhere else (as we need to keep the join is reusable).
|
||||||
|
*/
|
||||||
|
tmp_table_param.cleanup();
|
||||||
tmp_table_param.copy_field= 0;
|
tmp_table_param.copy_field= 0;
|
||||||
DBUG_RETURN(tmp_join->destroy());
|
DBUG_RETURN(tmp_join->destroy());
|
||||||
}
|
}
|
||||||
@ -5838,6 +5844,12 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table)
|
|||||||
const_table_map= 0;
|
const_table_map= 0;
|
||||||
tmp_table_param.field_count= tmp_table_param.sum_func_count=
|
tmp_table_param.field_count= tmp_table_param.sum_func_count=
|
||||||
tmp_table_param.func_count= 0;
|
tmp_table_param.func_count= 0;
|
||||||
|
/*
|
||||||
|
We need to destruct the copy_field (allocated in create_tmp_table())
|
||||||
|
before setting it to 0 if the join is not "reusable".
|
||||||
|
*/
|
||||||
|
if (!tmp_join || tmp_join != this)
|
||||||
|
tmp_table_param.cleanup();
|
||||||
tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
|
tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
|
||||||
first_record= sort_and_group=0;
|
first_record= sort_and_group=0;
|
||||||
send_records= (ha_rows) 0;
|
send_records= (ha_rows) 0;
|
||||||
|
@ -354,7 +354,25 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool no_const_tables;
|
bool no_const_tables;
|
||||||
|
|
||||||
JOIN *tmp_join; ///< copy of this JOIN to be used with temporary tables
|
/**
|
||||||
|
Copy of this JOIN to be used with temporary tables.
|
||||||
|
|
||||||
|
tmp_join is used when the JOIN needs to be "reusable" (e.g. in a subquery
|
||||||
|
that gets re-executed several times) and we know will use temporary tables
|
||||||
|
for materialization. The materialization to a temporary table overwrites the
|
||||||
|
JOIN structure to point to the temporary table after the materialization is
|
||||||
|
done. This is where tmp_join is used : it's a copy of the JOIN before the
|
||||||
|
materialization and is used in restoring before re-execution by overwriting
|
||||||
|
the current JOIN structure with the saved copy.
|
||||||
|
Because of this we should pay extra care of not freeing up helper structures
|
||||||
|
that are referenced by the original contents of the JOIN. We can check for
|
||||||
|
this by making sure the "current" join is not the temporary copy, e.g.
|
||||||
|
!tmp_join || tmp_join != join
|
||||||
|
|
||||||
|
We should free these sub-structures at JOIN::destroy() if the "current" join
|
||||||
|
has a copy is not that copy.
|
||||||
|
*/
|
||||||
|
JOIN *tmp_join;
|
||||||
ROLLUP rollup; ///< Used with rollup
|
ROLLUP rollup; ///< Used with rollup
|
||||||
|
|
||||||
bool select_distinct; ///< Set if SELECT DISTINCT
|
bool select_distinct; ///< Set if SELECT DISTINCT
|
||||||
|
Loading…
x
Reference in New Issue
Block a user