Skip to content

Commit cc831f1

Browse files
committed
MDEV-36079: Stored routine with a cursor crashes on the second execution if a DDL statement happened
Attempt to run a cursor after change in metadata of tables it depends on resulted in firing assertion on allocating a memory from a memory root marked as read only. On every execution of a cursor its Query_arena is set up as a statement arena (see sp_lex_keeper::cursor_reset_lex_and_exec_core()). As a consequence, any memory allocations happened on execution of the cursor's query should be taken from the cursor's memory root. The reason of allocating a memory from the memory root marked as read only is that the cursor's memory root points to a memory root of sp_head that could be already marked as read only after first successful execution and this relation isn't changed on re-parsing of the cursor's query. To fix the issue, memory root of cursor is adjusted in the method sp_lex_instr::parse_expr() to point to the new memory root just created for re-parsing of failed query.
1 parent 98a75d1 commit cc831f1

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

mysql-test/main/ps_mem_leaks.result

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,3 +441,28 @@ SET @@debug_dbug=@save_dbug;
441441
DROP TABLE t1;
442442
DROP PROCEDURE p1;
443443
# End of 11.2 tests
444+
# MDEV-36079: Stored routine with a cursor crashes on
445+
# the second execution if a DDL statement happened
446+
CREATE OR REPLACE TABLE t1 (a INT);
447+
INSERT INTO t1 VALUES (1);
448+
CREATE PROCEDURE p1()
449+
BEGIN
450+
DECLARE va INT DEFAULT 0;
451+
DECLARE cur CURSOR FOR SELECT a FROM t1;
452+
OPEN cur;
453+
FETCH cur INTO va;
454+
SELECT va;
455+
CLOSE cur;
456+
END;
457+
$
458+
CALL p1;
459+
va
460+
1
461+
ALTER TABLE t1 MODIFY a INT UNSIGNED;
462+
CALL p1;
463+
va
464+
1
465+
# Clean up
466+
DROP PROCEDURE p1;
467+
DROP TABLE t1;
468+
# End of 11.8 tests

mysql-test/main/ps_mem_leaks.test

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,35 @@ DROP TABLE t1;
469469
DROP PROCEDURE p1;
470470

471471
--echo # End of 11.2 tests
472+
473+
--echo # MDEV-36079: Stored routine with a cursor crashes on
474+
--echo # the second execution if a DDL statement happened
475+
CREATE OR REPLACE TABLE t1 (a INT);
476+
INSERT INTO t1 VALUES (1);
477+
478+
--delimiter $
479+
CREATE PROCEDURE p1()
480+
BEGIN
481+
DECLARE va INT DEFAULT 0;
482+
DECLARE cur CURSOR FOR SELECT a FROM t1;
483+
484+
OPEN cur;
485+
FETCH cur INTO va;
486+
SELECT va;
487+
CLOSE cur;
488+
END;
489+
$
490+
491+
--delimiter ;
492+
493+
CALL p1;
494+
495+
ALTER TABLE t1 MODIFY a INT UNSIGNED;
496+
497+
CALL p1;
498+
499+
--echo # Clean up
500+
DROP PROCEDURE p1;
501+
DROP TABLE t1;
502+
503+
--echo # End of 11.8 tests

sql/sp_instr.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,13 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp, LEX *sp_instr_lex)
862862
cleanup_items(cursor_lex->free_list);
863863
cursor_free_list= &cursor_lex->free_list;
864864
DBUG_ASSERT(thd->lex == sp_instr_lex);
865+
/*
866+
Adjust mem_root of the cursor's Query_arena to point the just created
867+
memory root allocated for re-parsing, else we would have the pointer to
868+
sp_head's memory_root that has already been marked as read_only after
869+
the first successful execution of the stored routine.
870+
*/
871+
cursor_lex->query_arena()->mem_root= m_mem_root_for_reparsing;
865872
lex_start(thd);
866873
}
867874

0 commit comments

Comments
 (0)