Commit 002696b6 authored by evgen@moonbone.local's avatar evgen@moonbone.local
Browse files

Merge epotemkin@bk-internal.mysql.com:/home/bk/mysql-5.0-opt

into  moonbone.local:/mnt/gentoo64/work/24989-bug-5.0-opt-mysql
parents b6bb988d 8de5603d
Loading
Loading
Loading
Loading
+66 −0
Original line number Diff line number Diff line
@@ -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;
+106 −0
Original line number Diff line number Diff line
@@ -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;
+3 −9
Original line number Diff line number Diff line
@@ -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);

@@ -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);

@@ -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 {
+5 −0
Original line number Diff line number Diff line
@@ -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
@@ -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);

+15 −3
Original line number Diff line number Diff line
@@ -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),
@@ -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;

@@ -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)
@@ -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--)
  {
@@ -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;
@@ -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