From 2992d531b040d9addc9153d95d3c65917c1e32c0 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Wed, 19 Jul 2023 18:31:01 +0700 Subject: [PATCH] MDEV-31661: Assertion `thd->lex == sp_instr_lex' failed in LEX* sp_lex_instr::parse_expr(THD*, sp_head*, LEX*) This is the follow-up patch for the task MDEV-5816 that fixes assert failure that happened after recompilation of a stored routine containing a cursor on its second execution. The reason of assertion hit is that a state of the SP instruction sp_instr_cpush wasn't reset after its SQL statement re-compiled. To fix the issue the virtual method sp_lex_instr::on_after_expr_parsing is overridden in the derived class sp_instr_cpush. Implementation of this method does resetting of the data member sp_instr_cpush::m_metadata_changed Additionally, implementation of the method sp_instr_set_trigger_field::on_after_expr_parsing has been slightly modified to set the data member sp_instr_set_trigger_field::value just before successful return. This data member is used to check whether this SP instruction is still valid or should be re-compiled. Resetting this data member before an instance of the class Item_trigger_field be successfully allocated theoretically could lead to clearing of instruction's state despite the fact that memory allocation was failed. --- mysql-test/main/sp_validation.result | 21 +++++++++++++++++++ mysql-test/main/sp_validation.test | 31 ++++++++++++++++++++++++++++ sql/sp_instr.cc | 8 ++++--- sql/sp_instr.h | 6 ++++++ 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/sp_validation.result b/mysql-test/main/sp_validation.result index 5aa2d6d9ed2..8eddb671da3 100644 --- a/mysql-test/main/sp_validation.result +++ b/mysql-test/main/sp_validation.result @@ -1890,4 +1890,25 @@ SET @@debug_dbug=@orig_dbug; DROP TABLE t1; DROP TABLE t2; DROP VIEW v1; +# +# MDEV-31661: Assertion `thd->lex == sp_instr_lex' failed in LEX* sp_lex_instr::parse_expr(THD*, sp_head*, LEX*) +# +CREATE OR REPLACE PROCEDURE p1() +BEGIN +DECLARE c CURSOR FOR SELECT * FROM t1; +OPEN c; +CLOSE c; +END; +$ +CALL p1; +ERROR 42S02: Table 'test.t1' doesn't exist +CREATE TABLE t1 (id INT); +CALL p1; +# Second execution of the stored procedure p1() after the dependent +# table t1 has been created resulted in assert failure for server built +# with debug +CALL p1; +# Clean up +DROP PROCEDURE p1; +DROP TABLE t1; SET sql_mode = default; diff --git a/mysql-test/main/sp_validation.test b/mysql-test/main/sp_validation.test index 3dc17dab0da..9956ae2b75f 100644 --- a/mysql-test/main/sp_validation.test +++ b/mysql-test/main/sp_validation.test @@ -2682,4 +2682,35 @@ SET @@debug_dbug=@orig_dbug; DROP TABLE t1; DROP TABLE t2; DROP VIEW v1; + +--echo # +--echo # MDEV-31661: Assertion `thd->lex == sp_instr_lex' failed in LEX* sp_lex_instr::parse_expr(THD*, sp_head*, LEX*) +--echo # + +--delimiter $ + +CREATE OR REPLACE PROCEDURE p1() +BEGIN + DECLARE c CURSOR FOR SELECT * FROM t1; + OPEN c; + CLOSE c; +END; +$ + +--delimiter ; + +--error ER_NO_SUCH_TABLE +CALL p1; +CREATE TABLE t1 (id INT); + +CALL p1; +--echo # Second execution of the stored procedure p1() after the dependent +--echo # table t1 has been created resulted in assert failure for server built +--echo # with debug +CALL p1; + +--echo # Clean up +DROP PROCEDURE p1; +DROP TABLE t1; + SET sql_mode = default; diff --git a/sql/sp_instr.cc b/sql/sp_instr.cc index f8bc34c3df0..096c658e7dc 100644 --- a/sql/sp_instr.cc +++ b/sql/sp_instr.cc @@ -1209,20 +1209,22 @@ bool sp_instr_set_trigger_field::on_after_expr_parsing(THD *thd) { DBUG_ASSERT(thd->lex->current_select->item_list.elements == 1); - value= thd->lex->current_select->item_list.head(); - DBUG_ASSERT(value != nullptr); + Item *val= thd->lex->current_select->item_list.head(); + DBUG_ASSERT(val != nullptr); trigger_field = new (thd->mem_root) Item_trigger_field(thd, thd->lex->current_context(), Item_trigger_field::NEW_ROW, m_trigger_field_name, UPDATE_ACL, false); - if (!value || !trigger_field) + if (!val || !trigger_field) return true; thd->spcont->m_sp->m_cur_instr_trig_field_items.link_in_list( trigger_field, &trigger_field->next_trg_field); + value= val; + return false; } diff --git a/sql/sp_instr.h b/sql/sp_instr.h index 777c441755f..8a7ad48d145 100644 --- a/sql/sp_instr.h +++ b/sql/sp_instr.h @@ -1238,6 +1238,12 @@ protected: return m_cursor_stmt; } + bool on_after_expr_parsing(THD *) override + { + m_metadata_changed= false; + return false; + } + private: uint m_cursor; /**< Frame offset (for debugging) */ /**