From: Alexander Nozdrin Date: July 21 2010 2:14pm Subject: bzr commit into mysql-trunk-bugfixing branch (alik:3133) Bug#23032 List-Archive: http://lists.mysql.com/commits/114045 X-Bug: 23032 Message-Id: <20100721141456.CA1FB40567@quad> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="Boundary_(ID_C3PA5Z+o+hTxL75EP8s0nw)" --Boundary_(ID_C3PA5Z+o+hTxL75EP8s0nw) MIME-version: 1.0 Content-type: text/plain; CHARSET=US-ASCII Content-transfer-encoding: 7BIT Content-disposition: inline #At file:///mnt/raid/alik/MySQL/bzr/00/bug23032/mysql-trunk-bugfixing-bug23032/ based on revid:jonathan.perkin@stripped 3133 Alexander Nozdrin 2010-07-21 Preliminary patch for Bug#23032 (Handlers declared in a SP do not handle warnings generated in sub-SP). modified: mysql-test/r/signal.result mysql-test/r/sp-error.result mysql-test/r/sp.result mysql-test/t/signal.test mysql-test/t/sp-error.test mysql-test/t/sp.test sql/sp_head.cc sql/sp_pcontext.h sql/sp_rcontext.cc sql/sp_rcontext.h sql/sql_class.cc sql/sql_class.h sql/sql_delete.cc sql/sql_error.cc sql/sql_error.h sql/sql_insert.cc sql/sql_parse.cc sql/sql_select.cc sql/sql_update.cc === modified file 'mysql-test/r/signal.result' --- a/mysql-test/r/signal.result 2010-02-23 18:43:26 +0000 +++ b/mysql-test/r/signal.result 2010-07-21 14:14:46 +0000 @@ -2135,15 +2135,17 @@ DECLARE x CONDITION FOR SQLSTATE '42000' DECLARE EXIT HANDLER FOR x BEGIN SELECT '2'; +SHOW WARNINGS; RESIGNAL x SET MYSQL_ERRNO = 9999; END; BEGIN DECLARE EXIT HANDLER FOR x BEGIN SELECT '1'; +SHOW WARNINGS; RESIGNAL x SET SCHEMA_NAME = 'test', -MYSQL_ERRNO= 1231; +MYSQL_ERRNO= 1232; END; /* Raises ER_WRONG_VALUE_FOR_VAR : 1231, SQLSTATE 42000 */ SET @@sql_mode=NULL; @@ -2156,6 +2158,7 @@ DECLARE x CONDITION for SQLSTATE '42000' DECLARE EXIT HANDLER FOR x BEGIN SELECT '3'; +SHOW WARNINGS; RESIGNAL x SET MESSAGE_TEXT = 'Hi, I am a useless error message', MYSQL_ERRNO = 9999; @@ -2166,15 +2169,21 @@ $$ CALL peter_p2() $$ 1 1 +Level Code Message 2 2 +Level Code Message +Error 1231 Variable 'sql_mode' can't be set to the value of 'NULL' 3 3 +Level Code Message +Error 1231 Variable 'sql_mode' can't be set to the value of 'NULL' +Error 1232 Variable 'sql_mode' can't be set to the value of 'NULL' ERROR 42000: Hi, I am a useless error message show warnings $$ Level Code Message Error 1231 Variable 'sql_mode' can't be set to the value of 'NULL' -Error 1231 Variable 'sql_mode' can't be set to the value of 'NULL' +Error 1232 Variable 'sql_mode' can't be set to the value of 'NULL' Error 9999 Variable 'sql_mode' can't be set to the value of 'NULL' Error 9999 Hi, I am a useless error message drop procedure peter_p1 $$ === modified file 'mysql-test/r/sp-error.result' --- a/mysql-test/r/sp-error.result 2010-02-24 13:52:27 +0000 +++ b/mysql-test/r/sp-error.result 2010-07-21 14:14:46 +0000 @@ -1714,3 +1714,114 @@ DROP PROCEDURE p1; DROP VIEW v1; DROP TABLE t1; End of 5.1 tests +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +CREATE PROCEDURE p1() +BEGIN +SELECT CAST('10 ' as unsigned integer); +SELECT 1; +CALL p2(); +END| +CREATE PROCEDURE p2() +BEGIN +SELECT CAST('10 ' as unsigned integer); +END| +CALL p1(); +CAST('10 ' as unsigned integer) +10 +1 +1 +CAST('10 ' as unsigned integer) +10 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '10 ' +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +DROP PROCEDURE IF EXISTS p5; +DROP PROCEDURE IF EXISTS p6; +CREATE PROCEDURE p1() +BEGIN +DECLARE c INT DEFAULT 0; +DECLARE CONTINUE HANDLER FOR SQLWARNING SET c = c + 1; +CALL p2(); +CALL p3(); +CALL p4(); +SELECT c; +SELECT @@warning_count; +SHOW WARNINGS; +END| +CREATE PROCEDURE p2() +BEGIN +SELECT CAST('10 ' as unsigned integer); +END| +CREATE PROCEDURE p3() +BEGIN +SELECT CAST('10 ' as unsigned integer); +SELECT 1; +END| +CREATE PROCEDURE p4() +BEGIN +SELECT CAST('10 ' as unsigned integer); +CALL p2(); +END| +CREATE PROCEDURE p5() +BEGIN +SELECT CAST('10 ' as unsigned integer); +SHOW WARNINGS; +END| +CREATE PROCEDURE P6() +BEGIN +DECLARE c INT DEFAULT 0; +DECLARE CONTINUE HANDLER FOR SQLWARNING SET c = c + 1; +CALL p5(); +SELECT c; +END| +CALL p1(); +CAST('10 ' as unsigned integer) +10 +CAST('10 ' as unsigned integer) +10 +1 +1 +CAST('10 ' as unsigned integer) +10 +CAST('10 ' as unsigned integer) +10 +c +3 +@@warning_count +0 +Level Code Message +CALL p6(); +CAST('10 ' as unsigned integer) +10 +Level Code Message +Warning 1292 Truncated incorrect INTEGER value: '10 ' +c +1 +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP PROCEDURE p3; +DROP PROCEDURE p4; +DROP PROCEDURE p5; +DROP PROCEDURE p6; +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; +CREATE TABLE t1 (a INT, b INT NOT NULL); +CREATE PROCEDURE p1() +BEGIN +DECLARE CONTINUE HANDLER FOR SQLWARNING SELECT 'warning'; +DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT 'exception'; +INSERT INTO t1 VALUES (CAST('10 ' AS SIGNED), NULL); +END| +CALL p1(); +exception +exception +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '10 ' +DROP TABLE t1; +DROP PROCEDURE p1; === modified file 'mysql-test/r/sp.result' --- a/mysql-test/r/sp.result 2010-05-14 05:28:51 +0000 +++ b/mysql-test/r/sp.result 2010-07-21 14:14:46 +0000 @@ -4546,6 +4546,8 @@ drop procedure if exists bug15231_1| drop procedure if exists bug15231_2| drop procedure if exists bug15231_3| drop procedure if exists bug15231_4| +drop procedure if exists bug15231_5| +drop procedure if exists bug15231_6| create table t3 (id int not null)| create procedure bug15231_1() begin @@ -4568,7 +4570,7 @@ end| create procedure bug15231_3() begin declare exit handler for sqlwarning -select 'Caught it (wrong)' as 'Result'; +select 'Caught it (correct)' as 'Result'; call bug15231_4(); end| create procedure bug15231_4() @@ -4576,6 +4578,20 @@ begin declare x decimal(2,1); set x = 'zap'; select 'Missed it (correct)' as 'Result'; +show warnings; +end| +create procedure bug15231_5() +begin +declare exit handler for sqlwarning +select 'Caught it (wrong)' as 'Result'; +call bug15231_6(); +end| +create procedure bug15231_6() +begin +declare x decimal(2,1); +set x = 'zap'; +select 'Missed it (correct)' as 'Result'; +select id from t3; end| call bug15231_1()| 1 @@ -4583,19 +4599,25 @@ Before NOT FOUND condition is triggered 2 After NOT FOUND condtition is triggered xid xdone -1 0 -Warnings: -Warning 1329 No data - zero rows fetched, selected, or processed +1 1 call bug15231_3()| Result Missed it (correct) -Warnings: +Level Code Message Warning 1366 Incorrect decimal value: 'zap' for column 'x' at row 1 -drop table if exists t3| -drop procedure if exists bug15231_1| -drop procedure if exists bug15231_2| -drop procedure if exists bug15231_3| -drop procedure if exists bug15231_4| +Result +Caught it (correct) +call bug15231_5()| +Result +Missed it (correct) +id +drop table t3| +drop procedure bug15231_1| +drop procedure bug15231_2| +drop procedure bug15231_3| +drop procedure bug15231_4| +drop procedure bug15231_5| +drop procedure bug15231_6| drop procedure if exists bug15011| create table t3 (c1 int primary key)| insert into t3 values (1)| === modified file 'mysql-test/t/signal.test' --- a/mysql-test/t/signal.test 2009-09-10 09:18:29 +0000 +++ b/mysql-test/t/signal.test 2010-07-21 14:14:46 +0000 @@ -2408,6 +2408,7 @@ BEGIN DECLARE EXIT HANDLER FOR x BEGIN SELECT '2'; + SHOW WARNINGS; RESIGNAL x SET MYSQL_ERRNO = 9999; END; @@ -2415,9 +2416,10 @@ BEGIN DECLARE EXIT HANDLER FOR x BEGIN SELECT '1'; + SHOW WARNINGS; RESIGNAL x SET SCHEMA_NAME = 'test', - MYSQL_ERRNO= 1231; + MYSQL_ERRNO= 1232; END; /* Raises ER_WRONG_VALUE_FOR_VAR : 1231, SQLSTATE 42000 */ SET @@sql_mode=NULL; @@ -2431,6 +2433,7 @@ BEGIN DECLARE EXIT HANDLER FOR x BEGIN SELECT '3'; + SHOW WARNINGS; RESIGNAL x SET MESSAGE_TEXT = 'Hi, I am a useless error message', MYSQL_ERRNO = 9999; === modified file 'mysql-test/t/sp-error.test' --- a/mysql-test/t/sp-error.test 2010-02-04 22:08:08 +0000 +++ b/mysql-test/t/sp-error.test 2010-07-21 14:14:46 +0000 @@ -2543,3 +2543,125 @@ DROP TABLE t1; --echo End of 5.1 tests +# +# Bug#23032: Handlers declared in a SP do not handle warnings generated in sub-SP +# + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +--enable_warnings + +delimiter |; + +CREATE PROCEDURE p1() + BEGIN + SELECT CAST('10 ' as unsigned integer); + SELECT 1; + CALL p2(); + END| + +CREATE PROCEDURE p2() + BEGIN + SELECT CAST('10 ' as unsigned integer); + END| + +delimiter ;| + +CALL p1(); + +DROP PROCEDURE p1; +DROP PROCEDURE p2; + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +DROP PROCEDURE IF EXISTS p5; +DROP PROCEDURE IF EXISTS p6; +--enable_warnings + +delimiter |; + +CREATE PROCEDURE p1() + BEGIN + DECLARE c INT DEFAULT 0; + DECLARE CONTINUE HANDLER FOR SQLWARNING SET c = c + 1; + CALL p2(); + CALL p3(); + CALL p4(); + SELECT c; + SELECT @@warning_count; + SHOW WARNINGS; + END| + +CREATE PROCEDURE p2() + BEGIN + SELECT CAST('10 ' as unsigned integer); + END| + +CREATE PROCEDURE p3() + BEGIN + SELECT CAST('10 ' as unsigned integer); + SELECT 1; + END| + +CREATE PROCEDURE p4() + BEGIN + SELECT CAST('10 ' as unsigned integer); + CALL p2(); + END| + +CREATE PROCEDURE p5() + BEGIN + SELECT CAST('10 ' as unsigned integer); + SHOW WARNINGS; + END| + +CREATE PROCEDURE P6() + BEGIN + DECLARE c INT DEFAULT 0; + DECLARE CONTINUE HANDLER FOR SQLWARNING SET c = c + 1; + CALL p5(); + SELECT c; + END| + +delimiter ;| + +CALL p1(); +CALL p6(); + +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP PROCEDURE p3; +DROP PROCEDURE p4; +DROP PROCEDURE p5; +DROP PROCEDURE p6; + +# +# Bug#36185: Incorrect precedence for warning and exception handlers +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; +--enable_warnings + +CREATE TABLE t1 (a INT, b INT NOT NULL); + +delimiter |; + +CREATE PROCEDURE p1() +BEGIN + DECLARE CONTINUE HANDLER FOR SQLWARNING SELECT 'warning'; + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT 'exception'; + INSERT INTO t1 VALUES (CAST('10 ' AS SIGNED), NULL); +END| + +delimiter ;| + +CALL p1(); + +DROP TABLE t1; +DROP PROCEDURE p1; === modified file 'mysql-test/t/sp.test' --- a/mysql-test/t/sp.test 2010-04-13 21:56:19 +0000 +++ b/mysql-test/t/sp.test 2010-07-21 14:14:46 +0000 @@ -5432,6 +5432,8 @@ drop procedure if exists bug15231_1| drop procedure if exists bug15231_2| drop procedure if exists bug15231_3| drop procedure if exists bug15231_4| +drop procedure if exists bug15231_5| +drop procedure if exists bug15231_6| --enable_warnings create table t3 (id int not null)| @@ -5461,7 +5463,7 @@ end| create procedure bug15231_3() begin declare exit handler for sqlwarning - select 'Caught it (wrong)' as 'Result'; + select 'Caught it (correct)' as 'Result'; call bug15231_4(); end| @@ -5472,16 +5474,37 @@ begin set x = 'zap'; select 'Missed it (correct)' as 'Result'; + show warnings; +end| + +create procedure bug15231_5() +begin + declare exit handler for sqlwarning + select 'Caught it (wrong)' as 'Result'; + + call bug15231_6(); +end| + +create procedure bug15231_6() +begin + declare x decimal(2,1); + + set x = 'zap'; + select 'Missed it (correct)' as 'Result'; + select id from t3; end| call bug15231_1()| call bug15231_3()| +call bug15231_5()| -drop table if exists t3| -drop procedure if exists bug15231_1| -drop procedure if exists bug15231_2| -drop procedure if exists bug15231_3| -drop procedure if exists bug15231_4| +drop table t3| +drop procedure bug15231_1| +drop procedure bug15231_2| +drop procedure bug15231_3| +drop procedure bug15231_4| +drop procedure bug15231_5| +drop procedure bug15231_6| # === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2010-06-17 13:31:51 +0000 +++ b/sql/sp_head.cc 2010-07-21 14:14:46 +0000 @@ -1074,6 +1074,127 @@ void sp_head::recursion_level_error(THD /** + Check if an exception has occurred and a handler has been found + + @param thd thread handle + @param ctx runtime context of the stored routine + @param ip location of the found handler + @param instr stored procedure instruction + @param execute_arena per-instruction arena + @param backup_arena per-instruction arena + + @return TRUE if a handler has been found, FALSE otherwise. +*/ + +static bool +find_and_push_handler(THD *thd, sp_rcontext *ctx) +{ + /* Fatal errors are not catchable. Do nothing if killed. */ + if (! ctx || thd->is_fatal_error || thd->killed_errno()) + return FALSE; + + /* Precaution: ditch any previously found handler. */ + ctx->clear_handler(); + + if (thd->is_error()) + { + if (ctx->find_handler(thd, + thd->stmt_da->sql_errno(), + thd->stmt_da->get_sqlstate(), + MYSQL_ERROR::WARN_LEVEL_ERROR, + thd->stmt_da->message())) + { + List_iterator it(thd->warning_info->warn_list()); + MYSQL_ERROR *err; + while ((err= it++)) + { + + if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR || + err->get_sql_errno() != thd->stmt_da->sql_errno() || + strcmp(err->get_sqlstate(), thd->stmt_da->get_sqlstate()) || + strcmp(err->get_message_text(), thd->stmt_da->message())) + continue; + + // This is our error. Because exception handler is found, it should + // be cleared from the warning list. + it.remove(); + thd->warning_info->remove_warning(thd, err); + break; + } + + return TRUE; + } + else + { + ctx->end_partial_result_set= FALSE; + return FALSE; + } + } + + if (thd->warning_info->statement_warn_count()) + { + List_iterator it(thd->warning_info->warn_list()); + MYSQL_ERROR *err; + while ((err= it++)) + { + if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_WARN) + continue; + + if (ctx->find_handler(thd, + err->get_sql_errno(), + err->get_sqlstate(), + err->get_level(), + err->get_message_text())) + { + thd->warning_info->clear_warning_info(thd->warning_info->warn_id()); + return TRUE; + } + } + } + + return FALSE; +} + + +static bool activate_handler(THD *thd, sp_rcontext *ctx, + uint *ip, + sp_instr *instr, + Query_arena *execute_arena, + Query_arena *backup_arena) +{ + int found_handler_index= ctx->get_found_handler_index(); + + if (found_handler_index < 0) + return FALSE; + + const sp_handler_t *found_handler= ctx->get_handler(found_handler_index); + + switch (found_handler->type) { + case SP_HANDLER_NONE: + break; + case SP_HANDLER_CONTINUE: + thd->restore_active_arena(execute_arena, backup_arena); + thd->set_n_backup_active_arena(execute_arena, backup_arena); + ctx->push_hstack(instr->get_cont_dest()); + /* Fall through */ + default: + if (ctx->end_partial_result_set) + thd->protocol->end_partial_result_set(thd); + *ip= found_handler->handler; + ctx->clear_handler(); + ctx->enter_handler(*ip, found_handler_index); + thd->clear_error(); + /* Some errors set thd->killed (e.g. "bad data"). */ + thd->killed= THD::NOT_KILLED; + } + + ctx->end_partial_result_set= FALSE; + + return TRUE; +} + + +/** Execute the routine. The main instruction jump loop is there. Assume the parameters already set. @todo @@ -1094,7 +1215,7 @@ sp_head::execute(THD *thd) LEX_STRING saved_cur_db_name= { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; bool cur_db_changed= FALSE; - sp_rcontext *ctx; + sp_rcontext *ctx= thd->spcont; bool err_status= FALSE; uint ip= 0; ulong save_sql_mode; @@ -1155,8 +1276,6 @@ sp_head::execute(THD *thd) goto done; } - if ((ctx= thd->spcont)) - ctx->clear_handler(); thd->is_slave_error= 0; old_arena= thd->stmt_arena; @@ -1241,7 +1360,6 @@ sp_head::execute(THD *thd) do { sp_instr *i; - uint hip; #if defined(ENABLED_PROFILING) /* @@ -1263,6 +1381,10 @@ sp_head::execute(THD *thd) break; } + /* Reset number of warnings for this query */ + // XXX thd->total_warn_count= 0; + thd->warning_info->reset_for_next_command(); + DBUG_PRINT("execute", ("Instruction %u", ip)); /* @@ -1306,41 +1428,11 @@ sp_head::execute(THD *thd) thd->cleanup_after_query(); free_root(&execute_mem_root, MYF(0)); - /* - Check if an exception has occurred and a handler has been found - Note: We have to check even if err_status == FALSE, since warnings (and - some errors) don't return a non-zero value. We also have to check even - if thd->killed != 0, since some errors return with this even when a - handler has been found (e.g. "bad data"). - */ - if (ctx) - { - uint handler_index; + find_and_push_handler(thd, ctx); - switch (ctx->found_handler(& hip, & handler_index)) { - case SP_HANDLER_NONE: - break; - case SP_HANDLER_CONTINUE: - thd->restore_active_arena(&execute_arena, &backup_arena); - thd->set_n_backup_active_arena(&execute_arena, &backup_arena); - ctx->push_hstack(i->get_cont_dest()); - /* Fall through */ - default: - if (ctx->end_partial_result_set) - thd->protocol->end_partial_result_set(thd); - ip= hip; - err_status= FALSE; - ctx->clear_handler(); - ctx->enter_handler(hip, handler_index); - thd->clear_error(); - thd->is_fatal_error= 0; - thd->killed= THD::NOT_KILLED; - thd->mysys_var->abort= 0; - continue; - } + if (activate_handler(thd, ctx, &ip, i, &execute_arena, &backup_arena)) + err_status= FALSE; - ctx->end_partial_result_set= FALSE; - } } while (!err_status && !thd->killed && !thd->is_fatal_error); #if defined(ENABLED_PROFILING) @@ -3012,23 +3104,14 @@ sp_instr_set::exec_core(THD *thd, uint * { int res= thd->spcont->set_variable(thd, m_offset, &m_value); - if (res && thd->spcont->found_handler_here()) + if (res) { - /* - Failed to evaluate the value, and a handler has been found. Reset the - variable to NULL. - */ + /* Failed to evaluate the value. Reset the variable to NULL. */ if (thd->spcont->set_variable(thd, m_offset, 0)) { /* If this also failed, let's abort. */ - - sp_rcontext *spcont= thd->spcont; - - thd->spcont= NULL; /* Avoid handlers */ - my_error(ER_OUT_OF_RESOURCES, MYF(0)); - spcont->clear_handler(); - thd->spcont= spcont; + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); } } @@ -3561,18 +3644,6 @@ sp_instr_copen::execute(THD *thd, uint * if (thd->stmt_arena->free_list) cleanup_items(thd->stmt_arena->free_list); thd->stmt_arena= old_arena; - /* - Work around the fact that errors in selects are not returned properly - (but instead converted into a warning), so if a condition handler - caught, we have lost the result code. - */ - if (!res) - { - uint dummy1, dummy2; - - if (thd->spcont->found_handler(&dummy1, &dummy2)) - res= -1; - } /* TODO: Assert here that we either have an error or a cursor */ } DBUG_RETURN(res); @@ -3748,13 +3819,11 @@ sp_instr_set_case_expr::exec_core(THD *t { int res= thd->spcont->set_case_expr(thd, m_case_expr_id, &m_case_expr); - if (res && - !thd->spcont->get_case_expr(m_case_expr_id) && - thd->spcont->found_handler_here()) + if (res && !thd->spcont->get_case_expr(m_case_expr_id)) { /* Failed to evaluate the value, the case expression is still not - initialized, and a handler has been found. Set to NULL so we can continue. + initialized. Set to NULL so we can continue. */ Item *null_item= new Item_null(); @@ -3763,13 +3832,7 @@ sp_instr_set_case_expr::exec_core(THD *t thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item)) { /* If this also failed, we have to abort. */ - - sp_rcontext *spcont= thd->spcont; - - thd->spcont= NULL; /* Avoid handlers */ - my_error(ER_OUT_OF_RESOURCES, MYF(0)); - spcont->clear_handler(); - thd->spcont= spcont; + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); } } else === modified file 'sql/sp_pcontext.h' --- a/sql/sp_pcontext.h 2010-03-31 14:05:33 +0000 +++ b/sql/sp_pcontext.h 2010-07-21 14:14:46 +0000 @@ -332,13 +332,6 @@ public: int push_cond(LEX_STRING *name, sp_cond_type_t *val); - inline void - pop_cond(uint num) - { - while (num--) - pop_dynamic(&m_conds); - } - sp_cond_type_t * find_cond(LEX_STRING *name, my_bool scoped=0); === modified file 'sql/sp_rcontext.cc' --- a/sql/sp_rcontext.cc 2010-07-08 21:20:08 +0000 +++ b/sql/sp_rcontext.cc 2010-07-21 14:14:46 +0000 @@ -203,15 +203,8 @@ sp_rcontext::find_handler(THD *thd, uint sql_errno, const char* sqlstate, MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl) + const char* msg) { - if (m_hfound >= 0) - { - *cond_hdl= NULL; - return TRUE; // Already got one - } - int i= m_hcount, found= -1; /* @@ -266,7 +259,18 @@ sp_rcontext::find_handler(THD *thd, break; } } - if (found < 0) + if (found >= 0) + { + DBUG_ASSERT((uint) found < m_root_parsing_ctx->max_handler_index()); + + m_raised_conditions[found].clear(); + m_raised_conditions[found].set(sql_errno, sqlstate, level, msg); + + m_hfound= found; + + return TRUE; + } + else { /* Only "exception conditions" are propagated to handlers in calling @@ -275,70 +279,13 @@ sp_rcontext::find_handler(THD *thd, */ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR) - return m_prev_runtime_ctx->find_handler(thd, - sql_errno, - sqlstate, - level, - msg, - cond_hdl); - *cond_hdl= NULL; - return FALSE; - } - - m_hfound= found; - - MYSQL_ERROR *raised= NULL; - DBUG_ASSERT(m_hfound >= 0); - DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index()); - raised= & m_raised_conditions[m_hfound]; - raised->clear(); - raised->set(sql_errno, sqlstate, level, msg); - - *cond_hdl= raised; - return TRUE; -} - -/* - Handle the error for a given errno. - The severity of the error is adjusted depending of the current sql_mode. - If an handler is present for the error (see find_handler()), - this function will return true. - If a handler is found and if the severity of the error indicate - that the current instruction executed should abort, - the flag thd->net.report_error is also set. - This will cause the execution of the current instruction in a - sp_instr* to fail, and give control to the handler code itself - in the sp_head::execute() loop. - - SYNOPSIS - sql_errno The error code - level Warning level - thd The current thread - - RETURN - TRUE if a handler was found. - FALSE if no handler was found. -*/ -bool -sp_rcontext::handle_condition(THD *thd, - uint sql_errno, - const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl) -{ - MYSQL_ERROR::enum_warning_level elevated_level= level; - + { + return m_prev_runtime_ctx->find_handler(thd, sql_errno, sqlstate, + level, msg); + } - /* Depending on the sql_mode of execution, - warnings may be considered errors */ - if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) && - thd->really_abort_on_warning()) - { - elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR; + return FALSE; } - - return find_handler(thd, sql_errno, sqlstate, elevated_level, msg, cond_hdl); } void === modified file 'sql/sp_rcontext.h' --- a/sql/sp_rcontext.h 2010-03-31 14:05:33 +0000 +++ b/sql/sp_rcontext.h 2010-07-21 14:14:46 +0000 @@ -135,44 +135,45 @@ class sp_rcontext : public Sql_alloc void pop_handlers(uint count); - // Returns 1 if a handler was found, 0 otherwise. + // Returns TRUE if a handler was found, FALSE otherwise. + // + // XXX: + // For warnings: find handler in current runtime context only. If a + // handler is found, it's remembered in m_hfound. It will be executed + // afterwards. + // + // For errors: find handler in the current or in any outer runtime + // contexts. If a handler is found, it's remembered in m_hfound of the + // corresponding runtime context. The handler will be executed in its + // runtime context when the context will be active again (the execution + // will unwind to that context). + // + // For warnings it could be possible to invoke handler right after it was + // found (because warning handlers are located in this runtime context). + // The reason finding and invocation of handlers are separated is error + // handlers -- they can reside in another (outer) runtime context. Thus, + // such handlers can not be invoked/activated until the execution flow + // reaches that outer runtime context again. + bool find_handler(THD *thd, uint sql_errno, const char* sqlstate, MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl); + const char* msg); - // If there is an error handler for this error, handle it and return TRUE. - bool - handle_condition(THD *thd, - uint sql_errno, - const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl); - - // Returns handler type and sets *ip to location if one was found - inline int - found_handler(uint *ip, uint *index) - { - if (m_hfound < 0) - return SP_HANDLER_NONE; - *ip= m_handler[m_hfound].handler; - *index= m_hfound; - return m_handler[m_hfound].type; + inline int get_found_handler_index() const + { + return m_hfound; } - MYSQL_ERROR* raised_condition() const; - - // Returns true if we found a handler in this context - inline bool - found_handler_here() + inline const sp_handler_t *get_handler(uint handler_index) const { - return (m_hfound >= 0); + return &m_handler[handler_index]; } + MYSQL_ERROR* raised_condition() const; + // Clears the handler find state inline void clear_handler() === modified file 'sql/sql_class.cc' --- a/sql/sql_class.cc 2010-07-15 13:47:50 +0000 +++ b/sql/sql_class.cc 2010-07-21 14:14:46 +0000 @@ -848,20 +848,6 @@ MYSQL_ERROR* THD::raise_condition(uint s } } - /* - If a continue handler is found, the error message will be cleared - by the stored procedures code. - */ - if (!is_fatal_error && spcont && - spcont->handle_condition(this, sql_errno, sqlstate, level, msg, &cond)) - { - /* - Do not push any warnings, a handled error must be completely - silenced. - */ - DBUG_RETURN(cond); - } - /* Un-handled conditions */ cond= raise_condition_no_handler(sql_errno, sqlstate, level, msg); @@ -1741,9 +1727,9 @@ bool select_send::send_result_set_metada return res; } -void select_send::abort() +void select_send::abort_result_set() { - DBUG_ENTER("select_send::abort"); + DBUG_ENTER("select_send::abort_result_set"); if (is_result_set_started && thd->spcont) { === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2010-07-15 13:47:50 +0000 +++ b/sql/sql_class.h 2010-07-21 14:14:46 +0000 @@ -2991,7 +2991,7 @@ public: @retval TRUE error, an error message is set */ virtual bool check_simple_select() const; - virtual void abort() {} + virtual void abort_result_set() {} /* Cleanup instance of this class for next execution of a prepared statement/stored procedure. @@ -3034,7 +3034,7 @@ public: bool send_data(List &items); bool send_eof(); virtual bool check_simple_select() const { return FALSE; } - void abort(); + void abort_result_set(); virtual void cleanup(); }; @@ -3126,7 +3126,7 @@ class select_insert :public select_resul virtual bool can_rollback_data() { return 0; } void send_error(uint errcode,const char *err); bool send_eof(); - void abort(); + virtual void abort_result_set(); /* not implemented: select_insert is never re-used in prepared statements */ void cleanup(); }; @@ -3162,7 +3162,7 @@ public: void store_values(List &values); void send_error(uint errcode,const char *err); bool send_eof(); - void abort(); + virtual void abort_result_set(); virtual bool can_rollback_data() { return 1; } // Needed for access from local class MY_HOOKS in prepare(), since thd is proteted. @@ -3496,7 +3496,7 @@ public: { return deleted; } - virtual void abort(); + virtual void abort_result_set(); }; @@ -3547,7 +3547,7 @@ public: { return updated; } - virtual void abort(); + virtual void abort_result_set(); }; class my_var : public Sql_alloc { === modified file 'sql/sql_delete.cc' --- a/sql/sql_delete.cc 2010-07-19 09:21:24 +0000 +++ b/sql/sql_delete.cc 2010-07-21 14:14:46 +0000 @@ -770,9 +770,9 @@ void multi_delete::send_error(uint errco } -void multi_delete::abort() +void multi_delete::abort_result_set() { - DBUG_ENTER("multi_delete::abort"); + DBUG_ENTER("multi_delete::abort_result_set"); /* the error was handled or nothing deleted and no side effects return */ if (error_handled || === modified file 'sql/sql_error.cc' --- a/sql/sql_error.cc 2010-03-31 14:05:33 +0000 +++ b/sql/sql_error.cc 2010-07-21 14:14:46 +0000 @@ -570,6 +570,12 @@ MYSQL_ERROR *Warning_info::push_warning( return cond; } +void Warning_info::remove_warning(THD *thd, const MYSQL_ERROR *warning) +{ + m_warn_count[warning->get_level()]--; + m_statement_warn_count--; +} + /* Push the warning to error list if there is still room in the list === modified file 'sql/sql_error.h' --- a/sql/sql_error.h 2010-03-31 14:05:33 +0000 +++ b/sql/sql_error.h 2010-07-21 14:14:46 +0000 @@ -489,6 +489,8 @@ public: MYSQL_ERROR::enum_warning_level level, const char* msg); + void remove_warning(THD *thd, const MYSQL_ERROR *warning); + /** Set the read only status for this statement area. This is a privileged operation, reserved for the implementation of === modified file 'sql/sql_insert.cc' --- a/sql/sql_insert.cc 2010-07-08 21:20:08 +0000 +++ b/sql/sql_insert.cc 2010-07-21 14:14:46 +0000 @@ -3413,9 +3413,9 @@ bool select_insert::send_eof() DBUG_RETURN(0); } -void select_insert::abort() { +void select_insert::abort_result_set() { - DBUG_ENTER("select_insert::abort"); + DBUG_ENTER("select_insert::abort_result_set"); /* If the creation of the table failed (due to a syntax error, for example), no table will have been opened and therefore 'table' @@ -3952,9 +3952,9 @@ bool select_create::send_eof() } -void select_create::abort() +void select_create::abort_result_set() { - DBUG_ENTER("select_create::abort"); + DBUG_ENTER("select_create::abort_result_set"); /* In select_insert::abort() we roll back the statement, including @@ -3972,7 +3972,7 @@ void select_create::abort() log state. */ tmp_disable_binlog(thd); - select_insert::abort(); + select_insert::abort_result_set(); thd->transaction.stmt.modified_non_trans_table= FALSE; reenable_binlog(thd); /* possible error of writing binary log is ignored deliberately */ === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2010-07-15 13:47:50 +0000 +++ b/sql/sql_parse.cc 2010-07-21 14:14:46 +0000 @@ -3401,7 +3401,7 @@ end_with_restore_list: res|= thd->is_error(); MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted()); if (res) - del_result->abort(); + del_result->abort_result_set(); delete del_result; } else @@ -4858,7 +4858,7 @@ static bool execute_sqlcom_select(THD *t ER_YES, str.ptr()); } if (res) - result->abort(); + result->abort_result_set(); else result->send_eof(); delete result; === modified file 'sql/sql_select.cc' --- a/sql/sql_select.cc 2010-07-19 09:21:24 +0000 +++ b/sql/sql_select.cc 2010-07-21 14:14:46 +0000 @@ -300,7 +300,7 @@ bool handle_select(THD *thd, LEX *lex, s thd->is_error())); res|= thd->is_error(); if (unlikely(res)) - result->abort(); + result->abort_result_set(); MYSQL_SELECT_DONE((int) res, (ulong) thd->limit_found_rows); DBUG_RETURN(res); === modified file 'sql/sql_update.cc' --- a/sql/sql_update.cc 2010-07-19 09:21:24 +0000 +++ b/sql/sql_update.cc 2010-07-21 14:14:46 +0000 @@ -1261,7 +1261,7 @@ bool mysql_multi_update(THD *thd, { /* If we had a another error reported earlier then this will be ignored */ (*result)->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); - (*result)->abort(); + (*result)->abort_result_set(); } thd->abort_on_warning= 0; DBUG_RETURN(res); @@ -1861,7 +1861,7 @@ void multi_update::send_error(uint errco } -void multi_update::abort() +void multi_update::abort_result_set() { /* the error was handled or nothing deleted and no side effects return */ if (error_handled || --Boundary_(ID_C3PA5Z+o+hTxL75EP8s0nw) MIME-version: 1.0 Content-type: text/bzr-bundle; CHARSET=US-ASCII; name="bzr/alik@stripped" Content-transfer-encoding: 7BIT Content-disposition: inline; filename="bzr/alik@stripped" # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: alik@stripped # target_branch: file:///mnt/raid/alik/MySQL/bzr/00/bug23032/mysql-\ # trunk-bugfixing-bug23032/ # testament_sha1: 1bf8e27c98e0432ea3cda0f416186b9c495a2eec # timestamp: 2010-07-21 18:14:56 +0400 # base_revision_id: jonathan.perkin@stripped\ # gqyrtmkgwrjfgsmc # # Begin bundle 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 cA+l4QY/+LuSKcKEh/3/cBg= --Boundary_(ID_C3PA5Z+o+hTxL75EP8s0nw)--