#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<MYSQL_ERROR> 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<MYSQL_ERROR> 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<Item> &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<Item> &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 ||
Attachment: [text/bzr-bundle] bzr/alik@sun.com-20100721141446-rvvvwuudafxhnd03.bundle
Thread |
---|
• bzr commit into mysql-trunk-bugfixing branch (alik:3133) Bug#23032 | Alexander Nozdrin | 21 Jul |