MDEV-34447: Memory leakage is detected on running the test main.ps against the server 11.1
The memory leak happened on second execution of a prepared statement that runs UPDATE statement with correlated subquery in right hand side of the SET clause. In this case, invocation of the method table->stat_records() could return the zero value that results in going into the 'if' branch that handles impossible where condition. The issue is that this condition branch missed saving of leaf tables that has to be performed as first condition optimization activity. Later the PS statement memory root is marked as read only on finishing first time execution of the prepared statement. Next time the same statement is executed it hits the assertion on attempt to allocate a memory on the PS memory root marked as read only. This memory allocation takes place by the sequence of the following invocations: Prepared_statement::execute mysql_execute_command Sql_cmd_dml::execute Sql_cmd_update::execute_inner Sql_cmd_update::update_single_table st_select_lex::save_leaf_tables List<TABLE_LIST>::push_back To fix the issue, add the flag SELECT_LEX::leaf_tables_saved to control whether the method SELECT_LEX::save_leaf_tables() has to be called or it has been already invoked and no more invocation required. Similar issue could take place on running the DELETE statement with the LIMIT clause in PS/SP mode. The reason of memory leak is the same as for UPDATE case and be fixed in the same way.
This commit is contained in:
parent
2f6df93748
commit
e012407397
@ -118,3 +118,33 @@ a
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
# End of 10.6 tests
|
||||
#
|
||||
# MDEV-34447: Memory leakage is detected on running the test main.ps against the server 11.1
|
||||
#
|
||||
CREATE TABLE t1 (id INT, value INT);
|
||||
CREATE TABLE t2 (id INT);
|
||||
PREPARE stmt FROM 'UPDATE t1 SET value = (SELECT 1 FROM t2 WHERE id = t1.id)';
|
||||
EXECUTE stmt;
|
||||
INSERT INTO t1 VALUES (1,10),(2,10),(3,10);
|
||||
INSERT INTO t2 VALUES (1),(2);
|
||||
EXECUTE stmt;
|
||||
SELECT * FROM t1;
|
||||
id value
|
||||
1 1
|
||||
2 1
|
||||
3 NULL
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1, t2;
|
||||
# Memory leak also could take place on running the DELETE statement
|
||||
# with the LIMIT clause. Check it.
|
||||
CREATE TABLE t1 (c1 INT);
|
||||
INSERT INTO t1 (c1) VALUES (1), (2), (3);
|
||||
CREATE PROCEDURE p1(p1 INT)
|
||||
DELETE FROM t1 LIMIT p1;
|
||||
CALL p1(0);
|
||||
CALL p1(1);
|
||||
CALL p1(2);
|
||||
# Clean up
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
# End of 10.11 tests
|
||||
|
@ -134,3 +134,36 @@ DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo # End of 10.6 tests
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34447: Memory leakage is detected on running the test main.ps against the server 11.1
|
||||
--echo #
|
||||
CREATE TABLE t1 (id INT, value INT);
|
||||
CREATE TABLE t2 (id INT);
|
||||
|
||||
PREPARE stmt FROM 'UPDATE t1 SET value = (SELECT 1 FROM t2 WHERE id = t1.id)';
|
||||
EXECUTE stmt;
|
||||
INSERT INTO t1 VALUES (1,10),(2,10),(3,10);
|
||||
INSERT INTO t2 VALUES (1),(2);
|
||||
EXECUTE stmt;
|
||||
SELECT * FROM t1;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--echo # Memory leak also could take place on running the DELETE statement
|
||||
--echo # with the LIMIT clause. Check it.
|
||||
CREATE TABLE t1 (c1 INT);
|
||||
INSERT INTO t1 (c1) VALUES (1), (2), (3);
|
||||
|
||||
CREATE PROCEDURE p1(p1 INT)
|
||||
DELETE FROM t1 LIMIT p1;
|
||||
|
||||
CALL p1(0);
|
||||
CALL p1(1);
|
||||
CALL p1(2);
|
||||
|
||||
--echo # Clean up
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo # End of 10.11 tests
|
||||
|
@ -530,6 +530,12 @@ bool Sql_cmd_delete::delete_from_single_table(THD *thd)
|
||||
if (thd->binlog_for_noop_dml(transactional_table))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (!thd->lex->current_select->leaf_tables_saved)
|
||||
{
|
||||
thd->lex->current_select->save_leaf_tables(thd);
|
||||
thd->lex->current_select->leaf_tables_saved= true;
|
||||
}
|
||||
|
||||
my_ok(thd, 0);
|
||||
DBUG_RETURN(0); // Nothing to delete
|
||||
}
|
||||
@ -902,10 +908,10 @@ cleanup:
|
||||
query_cache_invalidate3(thd, table_list, 1);
|
||||
}
|
||||
|
||||
if (thd->lex->current_select->first_cond_optimization)
|
||||
if (!thd->lex->current_select->leaf_tables_saved)
|
||||
{
|
||||
thd->lex->current_select->save_leaf_tables(thd);
|
||||
thd->lex->current_select->first_cond_optimization= 0;
|
||||
thd->lex->current_select->leaf_tables_saved= true;
|
||||
}
|
||||
|
||||
delete deltempfile;
|
||||
|
@ -1377,10 +1377,10 @@ values_loop_end:
|
||||
::my_ok(thd, info.copied + info.deleted + updated, id, buff);
|
||||
}
|
||||
thd->abort_on_warning= 0;
|
||||
if (thd->lex->current_select->first_cond_optimization)
|
||||
if (!thd->lex->current_select->leaf_tables_saved)
|
||||
{
|
||||
thd->lex->current_select->save_leaf_tables(thd);
|
||||
thd->lex->current_select->first_cond_optimization= 0;
|
||||
thd->lex->current_select->leaf_tables_saved= true;
|
||||
}
|
||||
|
||||
my_free(readbuff);
|
||||
|
@ -3028,6 +3028,7 @@ void st_select_lex::init_query()
|
||||
first_natural_join_processing= 1;
|
||||
first_cond_optimization= 1;
|
||||
first_rownum_optimization= true;
|
||||
leaf_tables_saved= false;
|
||||
no_wrap_view_item= 0;
|
||||
exclude_from_table_unique_test= 0;
|
||||
in_tvc= 0;
|
||||
|
@ -1286,6 +1286,10 @@ public:
|
||||
from the method JOIN::optimize_inner.
|
||||
*/
|
||||
bool first_rownum_optimization:1;
|
||||
/**
|
||||
Flag to guard against double initialization of leaf tables list
|
||||
*/
|
||||
bool leaf_tables_saved:1;
|
||||
/* do not wrap view fields with Item_ref */
|
||||
bool no_wrap_view_item:1;
|
||||
/* exclude this select from check of unique_table() */
|
||||
|
@ -2299,12 +2299,14 @@ JOIN::optimize_inner()
|
||||
|
||||
add_table_function_dependencies(join_list, table_map(-1));
|
||||
|
||||
if (thd->is_error() || select_lex->save_leaf_tables(thd))
|
||||
if (thd->is_error() ||
|
||||
(!select_lex->leaf_tables_saved && select_lex->save_leaf_tables(thd)))
|
||||
{
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
select_lex->leaf_tables_saved= true;
|
||||
build_bitmap_for_nested_joins(join_list, 0);
|
||||
|
||||
sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
|
||||
|
@ -497,6 +497,12 @@ bool Sql_cmd_update::update_single_table(THD *thd)
|
||||
if (thd->binlog_for_noop_dml(transactional_table))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (!thd->lex->current_select->leaf_tables_saved)
|
||||
{
|
||||
thd->lex->current_select->save_leaf_tables(thd);
|
||||
thd->lex->current_select->leaf_tables_saved= true;
|
||||
}
|
||||
|
||||
my_ok(thd); // No matching records
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@ -1251,10 +1257,10 @@ update_end:
|
||||
}
|
||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
|
||||
thd->abort_on_warning= 0;
|
||||
if (thd->lex->current_select->first_cond_optimization)
|
||||
if (!thd->lex->current_select->leaf_tables_saved)
|
||||
{
|
||||
thd->lex->current_select->save_leaf_tables(thd);
|
||||
thd->lex->current_select->first_cond_optimization= 0;
|
||||
thd->lex->current_select->leaf_tables_saved= true;
|
||||
}
|
||||
((multi_update *)result)->set_found(found);
|
||||
((multi_update *)result)->set_updated(updated);
|
||||
|
Loading…
x
Reference in New Issue
Block a user