diff --git a/mysql-test/main/ps_mem_leaks.result b/mysql-test/main/ps_mem_leaks.result index a1b6063537e..880d86e3d2c 100644 --- a/mysql-test/main/ps_mem_leaks.result +++ b/mysql-test/main/ps_mem_leaks.result @@ -441,3 +441,28 @@ SET @@debug_dbug=@save_dbug; DROP TABLE t1; DROP PROCEDURE p1; # End of 11.2 tests +# MDEV-36079: Stored routine with a cursor crashes on +# the second execution if a DDL statement happened +CREATE OR REPLACE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +CREATE PROCEDURE p1() +BEGIN +DECLARE va INT DEFAULT 0; +DECLARE cur CURSOR FOR SELECT a FROM t1; +OPEN cur; +FETCH cur INTO va; +SELECT va; +CLOSE cur; +END; +$ +CALL p1; +va +1 +ALTER TABLE t1 MODIFY a INT UNSIGNED; +CALL p1; +va +1 +# Clean up +DROP PROCEDURE p1; +DROP TABLE t1; +# End of 11.8 tests diff --git a/mysql-test/main/ps_mem_leaks.test b/mysql-test/main/ps_mem_leaks.test index 2aba6b87db7..09e91b25538 100644 --- a/mysql-test/main/ps_mem_leaks.test +++ b/mysql-test/main/ps_mem_leaks.test @@ -469,3 +469,35 @@ DROP TABLE t1; DROP PROCEDURE p1; --echo # End of 11.2 tests + +--echo # MDEV-36079: Stored routine with a cursor crashes on +--echo # the second execution if a DDL statement happened +CREATE OR REPLACE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); + +--delimiter $ +CREATE PROCEDURE p1() +BEGIN + DECLARE va INT DEFAULT 0; + DECLARE cur CURSOR FOR SELECT a FROM t1; + + OPEN cur; + FETCH cur INTO va; + SELECT va; + CLOSE cur; +END; +$ + +--delimiter ; + +CALL p1; + +ALTER TABLE t1 MODIFY a INT UNSIGNED; + +CALL p1; + +--echo # Clean up +DROP PROCEDURE p1; +DROP TABLE t1; + +--echo # End of 11.8 tests diff --git a/sql/sp_instr.cc b/sql/sp_instr.cc index a87d1c31756..cc0c9af2888 100644 --- a/sql/sp_instr.cc +++ b/sql/sp_instr.cc @@ -862,6 +862,13 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp, LEX *sp_instr_lex) cleanup_items(cursor_lex->free_list); cursor_free_list= &cursor_lex->free_list; DBUG_ASSERT(thd->lex == sp_instr_lex); + /* + Adjust mem_root of the cursor's Query_arena to point the just created + memory root allocated for re-parsing, else we would have the pointer to + sp_head's memory_root that has already been marked as read_only after + the first successful execution of the stored routine. + */ + cursor_lex->query_arena()->mem_root= m_mem_root_for_reparsing; lex_start(thd); }