diff --git a/mysql-test/main/ps_mem_leaks.result b/mysql-test/main/ps_mem_leaks.result index 2ddf47a992c..309433e1eb7 100644 --- a/mysql-test/main/ps_mem_leaks.result +++ b/mysql-test/main/ps_mem_leaks.result @@ -89,3 +89,33 @@ f DEALLOCATE PREPARE stmt; DROP TABLE t1; # End of 10.4 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.5 tests diff --git a/mysql-test/main/ps_mem_leaks.test b/mysql-test/main/ps_mem_leaks.test index dacb4ecabba..c0404687eb7 100644 --- a/mysql-test/main/ps_mem_leaks.test +++ b/mysql-test/main/ps_mem_leaks.test @@ -110,3 +110,36 @@ DEALLOCATE PREPARE stmt; DROP TABLE t1; --echo # End of 10.4 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.5 tests diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 99da79c599b..ea6b5e6ff66 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -530,6 +530,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if (unlikely(thd->is_error())) DBUG_RETURN(TRUE); + + 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 +909,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; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index cf3ec929d09..46486e09a8b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1373,10 +1373,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); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 2dc5d119fd5..fc39bd858f8 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3023,6 +3023,7 @@ void st_select_lex::init_query() olap= UNSPECIFIED_OLAP_TYPE; having_fix_field= 0; having_fix_field_for_pushed_cond= 0; + leaf_tables_saved= false; context.select_lex= this; context.init(); cond_count= between_count= with_wild= 0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0a88e92d723..e0cb336de5a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1182,6 +1182,10 @@ public: */ bool have_merged_subqueries; + /** + Flag to guard against double initialization of leaf tables list + */ + bool leaf_tables_saved; List leaf_tables; List leaf_tables_exec; List leaf_tables_prep; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 93b53699c9a..ea690422eac 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2054,12 +2054,14 @@ JOIN::optimize_inner() /* Convert all outer joins to inner joins if possible */ conds= simplify_joins(this, join_list, conds, TRUE, FALSE); - 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; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index adb209b7b56..c2868d8165e 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -598,6 +598,13 @@ int mysql_update(THD *thd, { DBUG_RETURN(1); // Error in where } + + 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); } @@ -1366,10 +1373,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; } *found_return= found; *updated_return= updated;