diff --git a/mysql-test/main/sp_validation.result b/mysql-test/main/sp_validation.result index 192a5e1d24083..55892172ea3af 100644 --- a/mysql-test/main/sp_validation.result +++ b/mysql-test/main/sp_validation.result @@ -2142,3 +2142,24 @@ ERROR HY000: The target table v1 of the DELETE is not updatable # Clean up DROP VIEW v1; DROP TABLE t1; +# +# MDEV-37335: crash on re-parsing an sp_instr_set that does not own its LEX +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +CREATE PROCEDURE p() +BEGIN +DECLARE b,c INT DEFAULT (SELECT a FROM t1); +SELECT b, c; +END +$ +CALL p(); +b c +1 1 +ALTER TABLE t1 MODIFY a BIGINT; +CALL p(); +b c +1 1 +# Clean up +DROP PROCEDURE p; +DROP TABLE t1; diff --git a/mysql-test/main/sp_validation.test b/mysql-test/main/sp_validation.test index fc84c6de97523..f2087e68968f0 100644 --- a/mysql-test/main/sp_validation.test +++ b/mysql-test/main/sp_validation.test @@ -2952,4 +2952,32 @@ UPDATE t1 SET a = 4; DROP VIEW v1; DROP TABLE t1; +--echo # +--echo # MDEV-37335: crash on re-parsing an sp_instr_set that does not own its LEX +--echo # +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); + +--delimiter $ +CREATE PROCEDURE p() +BEGIN + DECLARE b,c INT DEFAULT (SELECT a FROM t1); + SELECT b, c; +END +$ +--delimiter ; + +CALL p(); + +ALTER TABLE t1 MODIFY a BIGINT; + +# The instruction assigning the variable b doesn't own the LEX shared with +# the instruction assigning the variable c, so re-parsing it after a metadata +# change used to run the code path intended for cursor instructions. +CALL p(); + +--echo # Clean up +DROP PROCEDURE p; +DROP TABLE t1; + --enable_ps2_protocol diff --git a/sql/sp_instr.cc b/sql/sp_instr.cc index 5dd02473522a0..6c86b4201d1d4 100644 --- a/sql/sp_instr.cc +++ b/sql/sp_instr.cc @@ -487,9 +487,10 @@ int sp_lex_keeper::validate_lex_and_exec_core(THD *thd, uint *nextp, if (!lex) return true; /* - m_lex != nullptr in case it points to sp_lex_cursor. + m_lex != nullptr in case it points to sp_lex_cursor, and also when + this instruction shares a LEX owned by a sibling instruction. */ - if (m_lex == nullptr) + if (m_lex == nullptr || !m_lex->get_lex_for_cursor()) set_lex(lex); m_first_execution= true; @@ -896,8 +897,10 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp, LEX *sp_instr_lex) /* sp_instr_lex != nullptr for cursor relating SP instructions (sp_instr_cpush, sp_instr_cursor_copy_struct) and in some cases for sp_instr_set. + Only the cursor ones carry a sp_lex_cursor, which is what the else branch + below expects. */ - if (sp_instr_lex == nullptr) + if (sp_instr_lex == nullptr || !sp_instr_lex->get_lex_for_cursor()) { lex_local= new (thd->mem_root) st_lex_local; thd->lex= lex_local;