diff options
author | Dmitry Shulga <Dmitry.Shulga@Sun.COM> | 2010-09-07 15:53:46 +0700 |
---|---|---|
committer | Dmitry Shulga <Dmitry.Shulga@Sun.COM> | 2010-09-07 15:53:46 +0700 |
commit | d6f6db6f4cb02fb5a4c6225747af0673bd91ea94 (patch) | |
tree | c8eb3dcb0911e08facc0443d29a06726e0390312 | |
parent | 446cc653c0ab13a6fec8ab54de9f5596389b08bc (diff) | |
download | mariadb-git-d6f6db6f4cb02fb5a4c6225747af0673bd91ea94.tar.gz |
Fixed bug #55421 - Protocol::end_statement(): Assertion `0' on
multi-table UPDATE IGNORE.
The problem was that if there was an active SELECT statement
during trigger execution, an error risen during the execution
may cause a crash. The fix is to temporary reset LEX::current_select
before trigger execution and restore it afterwards. This way
errors risen during the trigger execution are processed as
if there was no active SELECT.
mysql-test/r/trigger_notembedded.result:
added test case result for bug #55421.
mysql-test/t/trigger_notembedded.test:
added test case for bug #55421.
sql/sql_trigger.cc:
Reset thd->lex->current_select before start trigger execution
and restore its original value after execution is finished.
This is neccessery in order to set error status in
diagnostic_area in case of trigger execution failure.
-rw-r--r-- | mysql-test/r/trigger_notembedded.result | 21 | ||||
-rw-r--r-- | mysql-test/t/trigger_notembedded.test | 48 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 9 |
3 files changed, 78 insertions, 0 deletions
diff --git a/mysql-test/r/trigger_notembedded.result b/mysql-test/r/trigger_notembedded.result index d66308a9bd7..cba41660ced 100644 --- a/mysql-test/r/trigger_notembedded.result +++ b/mysql-test/r/trigger_notembedded.result @@ -474,4 +474,25 @@ SHOW CREATE TRIGGER db1.trg; ERROR 42000: Access denied; you need the TRIGGER privilege for this operation DROP USER 'no_rights'@'localhost'; DROP DATABASE db1; +DROP DATABASE IF EXISTS mysqltest_db1; +CREATE DATABASE mysqltest_db1; +USE mysqltest_db1; +GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost; +CREATE TABLE t1 ( +a1 int, +a2 int +); +INSERT INTO t1 VALUES (1, 20); +CREATE TRIGGER mysqltest_db1.upd_t1 +BEFORE UPDATE ON t1 FOR EACH ROW SET new.a2 = 200; +CREATE TABLE t2 ( +a1 int +); +INSERT INTO t2 VALUES (2); +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_u1@localhost; +UPDATE IGNORE t1, t2 SET t1.a1 = 2, t2.a1 = 3 WHERE t1.a1 = 1 AND t2.a1 = 2; +ERROR 42000: TRIGGER command denied to user 'mysqltest_u1'@'localhost' for table 't1' +DROP DATABASE mysqltest_db1; +DROP USER mysqltest_u1@localhost; +USE test; End of 5.1 tests. diff --git a/mysql-test/t/trigger_notembedded.test b/mysql-test/t/trigger_notembedded.test index 7a7e6c6bc85..387944ffb47 100644 --- a/mysql-test/t/trigger_notembedded.test +++ b/mysql-test/t/trigger_notembedded.test @@ -932,4 +932,52 @@ disconnect con1; DROP USER 'no_rights'@'localhost'; DROP DATABASE db1; +# +# Bug#55421 Protocol::end_statement(): Assertion `0' on multi-table UPDATE IGNORE +# To reproduce a crash we need to provoke a trigger execution with +# the following conditions: +# - active SELECT statement during trigger execution +# (i.e. LEX::current_select != NULL); +# - IGNORE option (i.e. LEX::current_select->no_error == TRUE); +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_db1; +--enable_warnings + +CREATE DATABASE mysqltest_db1; +USE mysqltest_db1; + +GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost; + +--connect(con1,localhost,mysqltest_u1,,mysqltest_db1) + +CREATE TABLE t1 ( + a1 int, + a2 int +); +INSERT INTO t1 VALUES (1, 20); + +CREATE TRIGGER mysqltest_db1.upd_t1 +BEFORE UPDATE ON t1 FOR EACH ROW SET new.a2 = 200; + +CREATE TABLE t2 ( + a1 int +); + +INSERT INTO t2 VALUES (2); + +--connection default + +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_u1@localhost; + +--error ER_TABLEACCESS_DENIED_ERROR +UPDATE IGNORE t1, t2 SET t1.a1 = 2, t2.a1 = 3 WHERE t1.a1 = 1 AND t2.a1 = 2; +# Cleanup + +DROP DATABASE mysqltest_db1; +DROP USER mysqltest_u1@localhost; + +--disconnect con1 +--connection default +USE test; + --echo End of 5.1 tests. diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index bf4a46a4c67..9348feaa22a 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1989,6 +1989,7 @@ bool Table_triggers_list::process_triggers(THD *thd, bool err_status; Sub_statement_state statement_state; sp_head *sp_trigger= bodies[event][time_type]; + SELECT_LEX *save_current_select; if (sp_trigger == NULL) return FALSE; @@ -2012,11 +2013,19 @@ bool Table_triggers_list::process_triggers(THD *thd, thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); + /* + Reset current_select before call execute_trigger() and + restore it after return from one. This way error is set + in case of failure during trigger execution. + */ + save_current_select= thd->lex->current_select; + thd->lex->current_select= NULL; err_status= sp_trigger->execute_trigger(thd, &trigger_table->s->db, &trigger_table->s->table_name, &subject_table_grants[event][time_type]); + thd->lex->current_select= save_current_select; thd->restore_sub_statement_state(&statement_state); |