Commit 154bb53b authored by malff/marcsql@weblab.(none)'s avatar malff/marcsql@weblab.(none)

Merge malff@bk-internal.mysql.com:/home/bk/mysql-5.0-runtime

into  weblab.(none):/home/marcsql/TREE/mysql-5.0-8153
parents 9c1b3f57 21f00113
...@@ -4872,8 +4872,6 @@ declare continue handler for sqlexception begin end; ...@@ -4872,8 +4872,6 @@ declare continue handler for sqlexception begin end;
select no_such_function(); select no_such_function();
end| end|
call bug18787()| call bug18787()|
no_such_function()
NULL
drop procedure bug18787| drop procedure bug18787|
create database bug18344_012345678901| create database bug18344_012345678901|
use bug18344_012345678901| use bug18344_012345678901|
...@@ -5220,6 +5218,66 @@ CHARSET(p2) COLLATION(p2) ...@@ -5220,6 +5218,66 @@ CHARSET(p2) COLLATION(p2)
cp1251 cp1251_general_ci cp1251 cp1251_general_ci
CHARSET(p3) COLLATION(p3) CHARSET(p3) COLLATION(p3)
greek greek_general_ci greek greek_general_ci
drop table if exists t3, t4, t5|
drop procedure if exists bug8153_subselect|
drop procedure if exists bug8153_function|
create table t3 (a int)|
create table t4 (a int)|
insert into t3 values (1)|
insert into t4 values (1), (1)|
create procedure bug8153_subselect()
begin
declare continue handler for sqlexception
begin
select 'statement failed';
end;
update t3 set a=a+1 where (select a from t4 where a=1) is null;
select 'statement after update';
end|
call bug8153_subselect()|
statement failed
statement failed
statement after update
statement after update
select * from t3|
a
1
call bug8153_subselect()|
statement failed
statement failed
statement after update
statement after update
select * from t3|
a
1
drop procedure bug8153_subselect|
create procedure bug8153_function_a()
begin
declare continue handler for sqlexception
begin
select 'in continue handler';
end;
select 'reachable code a1';
call bug8153_function_b();
select 'reachable code a2';
end|
create procedure bug8153_function_b()
begin
select 'reachable code b1';
select no_such_function();
select 'unreachable code b2';
end|
call bug8153_function_a()|
reachable code a1
reachable code a1
reachable code b1
reachable code b1
in continue handler
in continue handler
reachable code a2
reachable code a2
drop procedure bug8153_function_a|
drop procedure bug8153_function_b|
use test| use test|
DROP DATABASE mysqltest1| DROP DATABASE mysqltest1|
drop procedure if exists bug19862| drop procedure if exists bug19862|
......
...@@ -6141,6 +6141,68 @@ SET @v3 = 'c'| ...@@ -6141,6 +6141,68 @@ SET @v3 = 'c'|
CALL bug16676_p1('a', @v2, @v3)| CALL bug16676_p1('a', @v2, @v3)|
CALL bug16676_p2('a', @v2, @v3)| CALL bug16676_p2('a', @v2, @v3)|
#
# BUG#8153: Stored procedure with subquery and continue handler, wrong result
#
--disable_warnings
drop table if exists t3, t4, t5|
drop procedure if exists bug8153_subselect|
drop procedure if exists bug8153_function|
--enable_warnings
create table t3 (a int)|
create table t4 (a int)|
insert into t3 values (1)|
insert into t4 values (1), (1)|
## Testing the use case reported in Bug#8153
create procedure bug8153_subselect()
begin
declare continue handler for sqlexception
begin
select 'statement failed';
end;
update t3 set a=a+1 where (select a from t4 where a=1) is null;
select 'statement after update';
end|
call bug8153_subselect()|
select * from t3|
call bug8153_subselect()|
select * from t3|
drop procedure bug8153_subselect|
## Testing extra use cases, found while investigating
## This is related to BUG#18787, with a non local handler
create procedure bug8153_function_a()
begin
declare continue handler for sqlexception
begin
select 'in continue handler';
end;
select 'reachable code a1';
call bug8153_function_b();
select 'reachable code a2';
end|
create procedure bug8153_function_b()
begin
select 'reachable code b1';
select no_such_function();
select 'unreachable code b2';
end|
call bug8153_function_a()|
drop procedure bug8153_function_a|
drop procedure bug8153_function_b|
# Cleanup. # Cleanup.
use test| use test|
......
...@@ -2392,10 +2392,8 @@ static int my_message_sql(uint error, const char *str, myf MyFlags) ...@@ -2392,10 +2392,8 @@ static int my_message_sql(uint error, const char *str, myf MyFlags)
if ((thd= current_thd)) if ((thd= current_thd))
{ {
if (thd->spcont && if (thd->spcont &&
thd->spcont->find_handler(error, MYSQL_ERROR::WARN_LEVEL_ERROR)) thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
{ {
if (! thd->spcont->found_handler_here())
thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -70,13 +70,13 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) ...@@ -70,13 +70,13 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
DBUG_PRINT("info", ("sending error messages prohibited")); DBUG_PRINT("info", ("sending error messages prohibited"));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
if (thd->spcont && thd->spcont->find_handler(sql_errno,
MYSQL_ERROR::WARN_LEVEL_ERROR)) if (thd->spcont &&
thd->spcont->handle_error(sql_errno, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
{ {
if (! thd->spcont->found_handler_here())
thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
thd->query_error= 1; // needed to catch query errors during replication thd->query_error= 1; // needed to catch query errors during replication
if (!err) if (!err)
{ {
...@@ -143,13 +143,12 @@ net_printf_error(THD *thd, uint errcode, ...) ...@@ -143,13 +143,12 @@ net_printf_error(THD *thd, uint errcode, ...)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
if (thd->spcont && thd->spcont->find_handler(errcode, if (thd->spcont &&
MYSQL_ERROR::WARN_LEVEL_ERROR)) thd->spcont->handle_error(errcode, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
{ {
if (! thd->spcont->found_handler_here())
thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
thd->query_error= 1; // needed to catch query errors during replication thd->query_error= 1; // needed to catch query errors during replication
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
query_cache_abort(net); // Safety query_cache_abort(net); // Safety
......
...@@ -260,6 +260,65 @@ sp_rcontext::find_handler(uint sql_errno, ...@@ -260,6 +260,65 @@ sp_rcontext::find_handler(uint sql_errno,
return TRUE; 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
- thd->net.report_error is an optional output.
RETURN
TRUE if a handler was found.
FALSE if no handler was found.
*/
bool
sp_rcontext::handle_error(uint sql_errno,
MYSQL_ERROR::enum_warning_level level,
THD *thd)
{
bool handled= FALSE;
MYSQL_ERROR::enum_warning_level elevated_level= level;
/* 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;
}
if (find_handler(sql_errno, elevated_level))
{
if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
{
/*
Forces to abort the current instruction execution.
NOTE: This code is altering the original meaning of
the net.report_error flag (send an error to the client).
In the context of stored procedures with error handlers,
the flag is reused to cause error propagation,
until the error handler is reached.
No messages will be sent to the client in that context.
*/
thd->net.report_error= 1;
}
handled= TRUE;
}
return handled;
}
void void
sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
......
...@@ -128,6 +128,12 @@ class sp_rcontext : public Sql_alloc ...@@ -128,6 +128,12 @@ class sp_rcontext : public Sql_alloc
bool bool
find_handler(uint sql_errno,MYSQL_ERROR::enum_warning_level level); find_handler(uint sql_errno,MYSQL_ERROR::enum_warning_level level);
// If there is an error handler for this error, handle it and return TRUE.
bool
handle_error(uint sql_errno,
MYSQL_ERROR::enum_warning_level level,
THD *thd);
// Returns handler type and sets *ip to location if one was found // Returns handler type and sets *ip to location if one was found
inline int inline int
found_handler(uint *ip, uint *fp) found_handler(uint *ip, uint *fp)
......
...@@ -139,14 +139,8 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, ...@@ -139,14 +139,8 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
} }
if (thd->spcont && if (thd->spcont &&
thd->spcont->find_handler(code, thd->spcont->handle_error(code, level, thd))
((int) level >=
(int) MYSQL_ERROR::WARN_LEVEL_WARN &&
thd->really_abort_on_warning()) ?
MYSQL_ERROR::WARN_LEVEL_ERROR : level))
{ {
if (! thd->spcont->found_handler_here())
thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
} }
query_cache_abort(&thd->net); query_cache_abort(&thd->net);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment