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.
This commit is contained in:
parent
3d5b9792e6
commit
70807d1473
@ -474,4 +474,25 @@ SHOW CREATE TRIGGER db1.trg;
|
|||||||
ERROR 42000: Access denied; you need the TRIGGER privilege for this operation
|
ERROR 42000: Access denied; you need the TRIGGER privilege for this operation
|
||||||
DROP USER 'no_rights'@'localhost';
|
DROP USER 'no_rights'@'localhost';
|
||||||
DROP DATABASE db1;
|
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.
|
End of 5.1 tests.
|
||||||
|
@ -932,4 +932,52 @@ disconnect con1;
|
|||||||
DROP USER 'no_rights'@'localhost';
|
DROP USER 'no_rights'@'localhost';
|
||||||
DROP DATABASE db1;
|
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.
|
--echo End of 5.1 tests.
|
||||||
|
@ -1989,6 +1989,7 @@ bool Table_triggers_list::process_triggers(THD *thd,
|
|||||||
bool err_status;
|
bool err_status;
|
||||||
Sub_statement_state statement_state;
|
Sub_statement_state statement_state;
|
||||||
sp_head *sp_trigger= bodies[event][time_type];
|
sp_head *sp_trigger= bodies[event][time_type];
|
||||||
|
SELECT_LEX *save_current_select;
|
||||||
|
|
||||||
if (sp_trigger == NULL)
|
if (sp_trigger == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -2012,11 +2013,19 @@ bool Table_triggers_list::process_triggers(THD *thd,
|
|||||||
|
|
||||||
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
|
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=
|
err_status=
|
||||||
sp_trigger->execute_trigger(thd,
|
sp_trigger->execute_trigger(thd,
|
||||||
&trigger_table->s->db,
|
&trigger_table->s->db,
|
||||||
&trigger_table->s->table_name,
|
&trigger_table->s->table_name,
|
||||||
&subject_table_grants[event][time_type]);
|
&subject_table_grants[event][time_type]);
|
||||||
|
thd->lex->current_select= save_current_select;
|
||||||
|
|
||||||
thd->restore_sub_statement_state(&statement_state);
|
thd->restore_sub_statement_state(&statement_state);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user