Loading mysql-test/r/innodb-big.result +66 −0 Original line number Diff line number Diff line Loading @@ -32,3 +32,69 @@ select sum(id) from t3; sum(id) 2199024304128 drop table t1,t2,t3,t4; CREATE TABLE t1 (f1 int NOT NULL) ENGINE=InnoDB; CREATE TABLE t2 (f2 int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; CREATE TRIGGER t1_bi before INSERT ON t1 FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @a:= 'deadlock'; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception'; INSERT INTO t2 (f2) VALUES (1); DELETE FROM t2 WHERE f2 = 1; END;| CREATE PROCEDURE proc24989() BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @b:= 'deadlock'; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception'; INSERT INTO t2 (f2) VALUES (1); DELETE FROM t2 WHERE f2 = 1; END;| create procedure proc24989_2() deterministic begin declare continue handler for sqlexception select 'Outer handler' as 'exception'; insert into t1 values(1); select "continued"; end| start transaction; insert into t1 values(1); start transaction; insert into t2 values(123); insert into t1 values(1); insert into t1 values(1); ERROR 40001: Deadlock found when trying to get lock; try restarting transaction select @a; @a NULL select * from t2; f2 commit; start transaction; insert into t1 values(1); start transaction; insert into t2 values(123); call proc24989(); insert into t1 values(1); select @a,@b; @a @b exception deadlock select * from t2; f2 commit; start transaction; insert into t1 values(1); start transaction; insert into t2 values(123); call proc24989_2(); insert into t1 values(1); commit; exception Outer handler continued continued select * from t2; f2 drop procedure proc24989; drop procedure proc24989_2; drop table t1,t2; mysql-test/t/innodb-big.test +106 −0 Original line number Diff line number Diff line Loading @@ -44,3 +44,109 @@ INSERT INTO t3 SELECT concat(id),id from t2 ORDER BY -id; INSERT INTO t4 SELECT * from t3 ORDER BY concat(a); select sum(id) from t3; drop table t1,t2,t3,t4; # # Bug#24989: The DEADLOCK error is improperly handled by InnoDB. # CREATE TABLE t1 (f1 int NOT NULL) ENGINE=InnoDB; CREATE TABLE t2 (f2 int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; DELIMITER |; CREATE TRIGGER t1_bi before INSERT ON t1 FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @a:= 'deadlock'; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception'; INSERT INTO t2 (f2) VALUES (1); DELETE FROM t2 WHERE f2 = 1; END;| CREATE PROCEDURE proc24989() BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @b:= 'deadlock'; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception'; INSERT INTO t2 (f2) VALUES (1); DELETE FROM t2 WHERE f2 = 1; END;| create procedure proc24989_2() deterministic begin declare continue handler for sqlexception select 'Outer handler' as 'exception'; insert into t1 values(1); select "continued"; end| DELIMITER ;| connect (con1,localhost,root,,); connect (con2,localhost,root,,); connection con1; start transaction; insert into t1 values(1); connection con2; start transaction; insert into t2 values(123); send insert into t1 values(1); connection con1; --sleep 1 insert into t1 values(1); connection con2; --error 1213 reap; select @a; # check that the whole transaction was rolled back select * from t2; connection con1; commit; start transaction; insert into t1 values(1); connection con2; start transaction; insert into t2 values(123); send call proc24989(); connection con1; --sleep 1 insert into t1 values(1); connection con2; reap; select @a,@b; # check that the whole transaction was rolled back select * from t2; connection con1; commit; start transaction; insert into t1 values(1); connection con2; start transaction; insert into t2 values(123); send call proc24989_2(); connection con1; --sleep 1 insert into t1 values(1); commit; connection con2; reap; # check that the whole transaction was rolled back select * from t2; disconnect con1; disconnect con2; connection default; drop procedure proc24989; drop procedure proc24989_2; drop table t1,t2; sql/ha_innodb.cc +3 −9 Original line number Diff line number Diff line Loading @@ -455,9 +455,7 @@ convert_error_code_to_mysql( tell it also to MySQL so that MySQL knows to empty the cached binlog for this transaction */ if (thd) { ha_rollback(thd); } mark_transaction_to_rollback(thd, TRUE); return(HA_ERR_LOCK_DEADLOCK); Loading @@ -467,9 +465,7 @@ convert_error_code_to_mysql( latest SQL statement in a lock wait timeout. Previously, we rolled back the whole transaction. */ if (thd && row_rollback_on_timeout) { ha_rollback(thd); } mark_transaction_to_rollback(thd, row_rollback_on_timeout); return(HA_ERR_LOCK_WAIT_TIMEOUT); Loading Loading @@ -521,9 +517,7 @@ convert_error_code_to_mysql( tell it also to MySQL so that MySQL knows to empty the cached binlog for this transaction */ if (thd) { ha_rollback(thd); } mark_transaction_to_rollback(thd, TRUE); return(HA_ERR_LOCK_TABLE_FULL); } else { Loading sql/handler.cc +5 −0 Original line number Diff line number Diff line Loading @@ -821,6 +821,9 @@ int ha_rollback_trans(THD *thd, bool all) } } #endif /* USING_TRANSACTIONS */ if (all) thd->transaction_rollback_request= FALSE; /* If a non-transactional table was updated, warn; don't warn if this is a slave thread (because when a slave thread executes a ROLLBACK, it has Loading Loading @@ -858,6 +861,8 @@ int ha_autocommit_or_rollback(THD *thd, int error) if (ha_commit_stmt(thd)) error=1; } else if (thd->transaction_rollback_request && !thd->in_sub_stmt) (void) ha_rollback(thd); else (void) ha_rollback_stmt(thd); Loading sql/sp_rcontext.cc +15 −3 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx, m_var_items(0), m_return_value_fld(return_value_fld), m_return_value_set(FALSE), in_sub_stmt(FALSE), m_hcount(0), m_hsp(0), m_ihsp(0), Loading Loading @@ -67,6 +68,8 @@ sp_rcontext::~sp_rcontext() bool sp_rcontext::init(THD *thd) { in_sub_stmt= thd->in_sub_stmt; if (init_var_table(thd) || init_var_items()) return TRUE; Loading Loading @@ -191,7 +194,7 @@ sp_rcontext::set_return_value(THD *thd, Item **return_value_item) */ bool sp_rcontext::find_handler(uint sql_errno, sp_rcontext::find_handler(THD *thd, uint sql_errno, MYSQL_ERROR::enum_warning_level level) { if (m_hfound >= 0) Loading @@ -200,6 +203,15 @@ sp_rcontext::find_handler(uint sql_errno, const char *sqlstate= mysql_errno_to_sqlstate(sql_errno); int i= m_hcount, found= -1; /* If this is a fatal sub-statement error, and this runtime context corresponds to a sub-statement, no CONTINUE/EXIT handlers from this context are applicable: try to locate one in the outer scope. */ if (thd->is_fatal_sub_stmt_error && in_sub_stmt) i= 0; /* Search handlers from the latest (innermost) to the oldest (outermost) */ while (i--) { Loading Loading @@ -252,7 +264,7 @@ sp_rcontext::find_handler(uint sql_errno, */ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR) return m_prev_runtime_ctx->find_handler(sql_errno, level); return m_prev_runtime_ctx->find_handler(thd, sql_errno, level); return FALSE; } m_hfound= found; Loading Loading @@ -298,7 +310,7 @@ sp_rcontext::handle_error(uint sql_errno, elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR; } if (find_handler(sql_errno, elevated_level)) if (find_handler(thd, sql_errno, elevated_level)) { if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR) { Loading Loading
mysql-test/r/innodb-big.result +66 −0 Original line number Diff line number Diff line Loading @@ -32,3 +32,69 @@ select sum(id) from t3; sum(id) 2199024304128 drop table t1,t2,t3,t4; CREATE TABLE t1 (f1 int NOT NULL) ENGINE=InnoDB; CREATE TABLE t2 (f2 int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; CREATE TRIGGER t1_bi before INSERT ON t1 FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @a:= 'deadlock'; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception'; INSERT INTO t2 (f2) VALUES (1); DELETE FROM t2 WHERE f2 = 1; END;| CREATE PROCEDURE proc24989() BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @b:= 'deadlock'; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception'; INSERT INTO t2 (f2) VALUES (1); DELETE FROM t2 WHERE f2 = 1; END;| create procedure proc24989_2() deterministic begin declare continue handler for sqlexception select 'Outer handler' as 'exception'; insert into t1 values(1); select "continued"; end| start transaction; insert into t1 values(1); start transaction; insert into t2 values(123); insert into t1 values(1); insert into t1 values(1); ERROR 40001: Deadlock found when trying to get lock; try restarting transaction select @a; @a NULL select * from t2; f2 commit; start transaction; insert into t1 values(1); start transaction; insert into t2 values(123); call proc24989(); insert into t1 values(1); select @a,@b; @a @b exception deadlock select * from t2; f2 commit; start transaction; insert into t1 values(1); start transaction; insert into t2 values(123); call proc24989_2(); insert into t1 values(1); commit; exception Outer handler continued continued select * from t2; f2 drop procedure proc24989; drop procedure proc24989_2; drop table t1,t2;
mysql-test/t/innodb-big.test +106 −0 Original line number Diff line number Diff line Loading @@ -44,3 +44,109 @@ INSERT INTO t3 SELECT concat(id),id from t2 ORDER BY -id; INSERT INTO t4 SELECT * from t3 ORDER BY concat(a); select sum(id) from t3; drop table t1,t2,t3,t4; # # Bug#24989: The DEADLOCK error is improperly handled by InnoDB. # CREATE TABLE t1 (f1 int NOT NULL) ENGINE=InnoDB; CREATE TABLE t2 (f2 int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; DELIMITER |; CREATE TRIGGER t1_bi before INSERT ON t1 FOR EACH ROW BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @a:= 'deadlock'; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception'; INSERT INTO t2 (f2) VALUES (1); DELETE FROM t2 WHERE f2 = 1; END;| CREATE PROCEDURE proc24989() BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @b:= 'deadlock'; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception'; INSERT INTO t2 (f2) VALUES (1); DELETE FROM t2 WHERE f2 = 1; END;| create procedure proc24989_2() deterministic begin declare continue handler for sqlexception select 'Outer handler' as 'exception'; insert into t1 values(1); select "continued"; end| DELIMITER ;| connect (con1,localhost,root,,); connect (con2,localhost,root,,); connection con1; start transaction; insert into t1 values(1); connection con2; start transaction; insert into t2 values(123); send insert into t1 values(1); connection con1; --sleep 1 insert into t1 values(1); connection con2; --error 1213 reap; select @a; # check that the whole transaction was rolled back select * from t2; connection con1; commit; start transaction; insert into t1 values(1); connection con2; start transaction; insert into t2 values(123); send call proc24989(); connection con1; --sleep 1 insert into t1 values(1); connection con2; reap; select @a,@b; # check that the whole transaction was rolled back select * from t2; connection con1; commit; start transaction; insert into t1 values(1); connection con2; start transaction; insert into t2 values(123); send call proc24989_2(); connection con1; --sleep 1 insert into t1 values(1); commit; connection con2; reap; # check that the whole transaction was rolled back select * from t2; disconnect con1; disconnect con2; connection default; drop procedure proc24989; drop procedure proc24989_2; drop table t1,t2;
sql/ha_innodb.cc +3 −9 Original line number Diff line number Diff line Loading @@ -455,9 +455,7 @@ convert_error_code_to_mysql( tell it also to MySQL so that MySQL knows to empty the cached binlog for this transaction */ if (thd) { ha_rollback(thd); } mark_transaction_to_rollback(thd, TRUE); return(HA_ERR_LOCK_DEADLOCK); Loading @@ -467,9 +465,7 @@ convert_error_code_to_mysql( latest SQL statement in a lock wait timeout. Previously, we rolled back the whole transaction. */ if (thd && row_rollback_on_timeout) { ha_rollback(thd); } mark_transaction_to_rollback(thd, row_rollback_on_timeout); return(HA_ERR_LOCK_WAIT_TIMEOUT); Loading Loading @@ -521,9 +517,7 @@ convert_error_code_to_mysql( tell it also to MySQL so that MySQL knows to empty the cached binlog for this transaction */ if (thd) { ha_rollback(thd); } mark_transaction_to_rollback(thd, TRUE); return(HA_ERR_LOCK_TABLE_FULL); } else { Loading
sql/handler.cc +5 −0 Original line number Diff line number Diff line Loading @@ -821,6 +821,9 @@ int ha_rollback_trans(THD *thd, bool all) } } #endif /* USING_TRANSACTIONS */ if (all) thd->transaction_rollback_request= FALSE; /* If a non-transactional table was updated, warn; don't warn if this is a slave thread (because when a slave thread executes a ROLLBACK, it has Loading Loading @@ -858,6 +861,8 @@ int ha_autocommit_or_rollback(THD *thd, int error) if (ha_commit_stmt(thd)) error=1; } else if (thd->transaction_rollback_request && !thd->in_sub_stmt) (void) ha_rollback(thd); else (void) ha_rollback_stmt(thd); Loading
sql/sp_rcontext.cc +15 −3 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx, m_var_items(0), m_return_value_fld(return_value_fld), m_return_value_set(FALSE), in_sub_stmt(FALSE), m_hcount(0), m_hsp(0), m_ihsp(0), Loading Loading @@ -67,6 +68,8 @@ sp_rcontext::~sp_rcontext() bool sp_rcontext::init(THD *thd) { in_sub_stmt= thd->in_sub_stmt; if (init_var_table(thd) || init_var_items()) return TRUE; Loading Loading @@ -191,7 +194,7 @@ sp_rcontext::set_return_value(THD *thd, Item **return_value_item) */ bool sp_rcontext::find_handler(uint sql_errno, sp_rcontext::find_handler(THD *thd, uint sql_errno, MYSQL_ERROR::enum_warning_level level) { if (m_hfound >= 0) Loading @@ -200,6 +203,15 @@ sp_rcontext::find_handler(uint sql_errno, const char *sqlstate= mysql_errno_to_sqlstate(sql_errno); int i= m_hcount, found= -1; /* If this is a fatal sub-statement error, and this runtime context corresponds to a sub-statement, no CONTINUE/EXIT handlers from this context are applicable: try to locate one in the outer scope. */ if (thd->is_fatal_sub_stmt_error && in_sub_stmt) i= 0; /* Search handlers from the latest (innermost) to the oldest (outermost) */ while (i--) { Loading Loading @@ -252,7 +264,7 @@ sp_rcontext::find_handler(uint sql_errno, */ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR) return m_prev_runtime_ctx->find_handler(sql_errno, level); return m_prev_runtime_ctx->find_handler(thd, sql_errno, level); return FALSE; } m_hfound= found; Loading Loading @@ -298,7 +310,7 @@ sp_rcontext::handle_error(uint sql_errno, elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR; } if (find_handler(sql_errno, elevated_level)) if (find_handler(thd, sql_errno, elevated_level)) { if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR) { Loading