diff --git a/mysql-test/main/sp_validation.result b/mysql-test/main/sp_validation.result index 8eddb671da3..c9771f8f862 100644 --- a/mysql-test/main/sp_validation.result +++ b/mysql-test/main/sp_validation.result @@ -1911,4 +1911,58 @@ CALL p1; # Clean up DROP PROCEDURE p1; DROP TABLE t1; +# +# MDEV-31799 Unexpected ER_TRG_NO_SUCH_ROW_IN_TRG and server crash after ALTER TABLE +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3),(4); +CREATE TABLE t2 (b INT); +# Check that AFTER DELETE trigger is re-compiled on changing table's metadata +CREATE TRIGGER tr AFTER DELETE ON t1 FOR EACH ROW INSERT INTO t2 (b) VALUES (OLD.a); +DELETE FROM t1 LIMIT 1; +SELECT * FROM t2; +b +1 +ALTER TABLE t2 FORCE; +DELETE FROM t1 LIMIT 1; +SELECT * FROM t2; +b +1 +2 +DELETE FROM t1 LIMIT 1; +SELECT * FROM t2; +b +1 +2 +3 +DROP TRIGGER tr; +# Check that AFTER UPDATE trigger is re-compiled on changing table's metadata +CREATE TRIGGER tr AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t2 (b) VALUES (OLD.a); +# Remove records interted by AFTER DELETE trogger +TRUNCATE TABLE t1; +TRUNCATE TABLE t2; +INSERT INTO t1 VALUES (1); +UPDATE t1 SET a = 2; +# Above statement should insert the row (1) into the table t2 +# Expected output contains one row: (1) +SELECT * FROM t2; +b +1 +ALTER TABLE t2 FORCE; +# The following statement should insert the row (2) into the table t2 +UPDATE t1 SET a = 3; +# Expected output contains two rows: (1), (2) +SELECT * FROM t2; +b +1 +2 +# The following statement should insert the row (3) into the table t2 +UPDATE t1 SET a = 5; +# Expected output contains three rows: (1), (2), (3) +SELECT * FROM t2; +b +1 +2 +3 +DROP TABLE t1, t2; SET sql_mode = default; diff --git a/mysql-test/main/sp_validation.test b/mysql-test/main/sp_validation.test index 9956ae2b75f..dcee453b013 100644 --- a/mysql-test/main/sp_validation.test +++ b/mysql-test/main/sp_validation.test @@ -2713,4 +2713,50 @@ CALL p1; DROP PROCEDURE p1; DROP TABLE t1; +--echo # +--echo # MDEV-31799 Unexpected ER_TRG_NO_SUCH_ROW_IN_TRG and server crash after ALTER TABLE +--echo # +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3),(4); +CREATE TABLE t2 (b INT); +--echo # Check that AFTER DELETE trigger is re-compiled on changing table's metadata +CREATE TRIGGER tr AFTER DELETE ON t1 FOR EACH ROW INSERT INTO t2 (b) VALUES (OLD.a); + +DELETE FROM t1 LIMIT 1; +SELECT * FROM t2; + +ALTER TABLE t2 FORCE; + +DELETE FROM t1 LIMIT 1; +SELECT * FROM t2; + +DELETE FROM t1 LIMIT 1; +SELECT * FROM t2; + +DROP TRIGGER tr; +--echo # Check that AFTER UPDATE trigger is re-compiled on changing table's metadata +CREATE TRIGGER tr AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t2 (b) VALUES (OLD.a); +--echo # Remove records interted by AFTER DELETE trogger +TRUNCATE TABLE t1; +TRUNCATE TABLE t2; +INSERT INTO t1 VALUES (1); +UPDATE t1 SET a = 2; +--echo # Above statement should insert the row (1) into the table t2 +--echo # Expected output contains one row: (1) +SELECT * FROM t2; +ALTER TABLE t2 FORCE; + +--echo # The following statement should insert the row (2) into the table t2 +UPDATE t1 SET a = 3; +--echo # Expected output contains two rows: (1), (2) +SELECT * FROM t2; +--echo # The following statement should insert the row (3) into the table t2 +UPDATE t1 SET a = 5; +--echo # Expected output contains three rows: (1), (2), (3) +SELECT * FROM t2; + +# Cleanup + +DROP TABLE t1, t2; + SET sql_mode = default; diff --git a/sql/sp_instr.cc b/sql/sp_instr.cc index 096c658e7dc..93c2e1abd05 100644 --- a/sql/sp_instr.cc +++ b/sql/sp_instr.cc @@ -722,7 +722,21 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp, LEX *sp_instr_lex) sp_instr_cursor_copy_struct) and in some cases for sp_instr_set. */ if (sp_instr_lex == nullptr) + { thd->lex= new (thd->mem_root) st_lex_local; + lex_start(thd); + if (sp->m_handler->type() == SP_TYPE_TRIGGER) + { + /* + In case the trigger's statement being re-parsed, the correct trigger's + context (trigger event type and action time) should be copied from + trigger's sp_head to the new lex object. + */ + thd->lex->trg_chistics.action_time= + thd->spcont->m_sp->m_trg->action_time; + thd->lex->trg_chistics.event= thd->spcont->m_sp->m_trg->event; + } + } else { sp_lex_cursor* cursor_lex= sp_instr_lex->get_lex_for_cursor(); @@ -742,8 +756,6 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp, LEX *sp_instr_lex) DBUG_ASSERT(thd->lex == sp_instr_lex); } - lex_start(thd); - thd->lex->sphead= sp; thd->lex->spcont= m_ctx;