diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index fea4e94ec4c..7ff7779aa83 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -1947,6 +1947,26 @@ select bug6022(5)| bug6022(5) 0 drop function bug6022| +drop procedure if exists bug6029| +create procedure bug6029() +begin +declare exit handler for 1136 select '1136'; +declare exit handler for sqlstate '23000' select 'sqlstate 23000'; +declare continue handler for sqlexception select 'sqlexception'; +insert into t3 values (1); +insert into t3 values (1,2); +end| +create table t3 (s1 int, primary key (s1))| +insert into t3 values (1)| +call bug6029()| +sqlstate 23000 +sqlstate 23000 +delete from t3| +call bug6029()| +1136 +1136 +drop procedure bug6029| +drop table t3| drop table if exists fac| create table fac (n int unsigned not null primary key, f bigint unsigned)| create procedure ifac(n int unsigned) diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 7b673d27025..654d8966255 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -2109,6 +2109,32 @@ end| select bug6022(5)| drop function bug6022| +# +# BUG#6029: Stored procedure specific handlers should have priority +# +--disable_warnings +drop procedure if exists bug6029| +--enable_warnings + +create procedure bug6029() +begin + declare exit handler for 1136 select '1136'; + declare exit handler for sqlstate '23000' select 'sqlstate 23000'; + declare continue handler for sqlexception select 'sqlexception'; + + insert into t3 values (1); + insert into t3 values (1,2); +end| + +create table t3 (s1 int, primary key (s1))| +insert into t3 values (1)| +call bug6029()| +delete from t3| +call bug6029()| + +drop procedure bug6029| +drop table t3| + # # Some "real" examples diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 169c9809383..51a1bb2e550 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -56,7 +56,7 @@ sp_rcontext::set_item_eval(uint idx, Item *i, enum_field_types type) } } -int +bool sp_rcontext::find_handler(uint sql_errno, MYSQL_ERROR::enum_warning_level level) { @@ -66,9 +66,9 @@ sp_rcontext::find_handler(uint sql_errno, return 1; // Already got one const char *sqlstate= mysql_errno_to_sqlstate(sql_errno); - int i= m_hcount, found= 0; + int i= m_hcount, found= -1; - while (!found && i--) + while (i--) { sp_cond_type_t *cond= m_handler[i].cond; @@ -76,31 +76,36 @@ sp_rcontext::find_handler(uint sql_errno, { case sp_cond_type_t::number: if (sql_errno == cond->mysqlerr) - found= 1; + found= i; // Always the most specific break; case sp_cond_type_t::state: - if (strcmp(sqlstate, cond->sqlstate) == 0) - found= 1; + if (strcmp(sqlstate, cond->sqlstate) == 0 && + (found < 0 || m_handler[found].cond->type > sp_cond_type_t::number)) + found= i; break; case sp_cond_type_t::warning: - if (sqlstate[0] == '0' && sqlstate[1] == '1' || - level == MYSQL_ERROR::WARN_LEVEL_WARN) - found= 1; + if ((sqlstate[0] == '0' && sqlstate[1] == '1' || + level == MYSQL_ERROR::WARN_LEVEL_WARN) && + (found < 0 || m_handler[found].cond->type > sp_cond_type_t::state)) + found= i; break; case sp_cond_type_t::notfound: - if (sqlstate[0] == '0' && sqlstate[1] == '2') - found= 1; + if (sqlstate[0] == '0' && sqlstate[1] == '2' && + (found < 0 || m_handler[found].cond->type > sp_cond_type_t::state)) + found= i; break; case sp_cond_type_t::exception: - if (sqlstate[0] != '0' || sqlstate[1] > '2' || - level == MYSQL_ERROR::WARN_LEVEL_ERROR) - found= 1; + if ((sqlstate[0] != '0' || sqlstate[1] > '2' || + level == MYSQL_ERROR::WARN_LEVEL_ERROR) && + (found < 0 || m_handler[found].cond->type > sp_cond_type_t::state)) + found= i; break; } } - if (found) - m_hfound= i; - return found; + if (found < 0) + return FALSE; + m_hfound= found; + return TRUE; } void diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index fff10ff3d0a..8e818ab76d1 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -122,7 +122,7 @@ class sp_rcontext : public Sql_alloc } // Returns 1 if a handler was found, 0 otherwise. - int + bool find_handler(uint sql_errno,MYSQL_ERROR::enum_warning_level level); // Returns handler type and sets *ip to location if one was found