If one declared several continue handler for the same condition on different level of stored procedures, all of them where executed.
Now we only execute the innermost of them (the most relevant). The solution was to add a 'handled' marker to MYSQL_ERROR and mark all elements for which we have executed a condition handler. When searching for new conditions, we will ignore any marked element. .bzrignore: Ignore error message file mysql-test/r/sp.result: Added testcase for continue handlers. mysql-test/t/sp.test: Added testcase for continue handlers. sql/sp_head.cc: Mark errors for which we will excute a handler as 'handled' Ignore already handled warnings/errors sql/sql_error.cc: Add 'handled' argument to MYSQL_ERROR, so that we can mark the errors/warnings we have handled. sql/sql_error.h: Add 'handled' argument to MYSQL_ERROR, so that we can mark the errors/warnings we have handled.
This commit is contained in:
parent
aa885cea71
commit
d4be9e7bc0
@ -1068,6 +1068,7 @@ vio/viotest.cpp
|
|||||||
ylwrap
|
ylwrap
|
||||||
zlib/*.ds?
|
zlib/*.ds?
|
||||||
sql-bench/test-table-elimination
|
sql-bench/test-table-elimination
|
||||||
|
sql/share/bulgarian
|
||||||
sql/share/czech
|
sql/share/czech
|
||||||
sql/share/danish
|
sql/share/danish
|
||||||
sql/share/dutch
|
sql/share/dutch
|
||||||
|
@ -7916,4 +7916,65 @@ DROP FUNCTION f1;
|
|||||||
DROP FUNCTION f2;
|
DROP FUNCTION f2;
|
||||||
DROP FUNCTION f3;
|
DROP FUNCTION f3;
|
||||||
DROP FUNCTION f4;
|
DROP FUNCTION f4;
|
||||||
|
|
||||||
|
Stored procedures and a condition handler in a nested procedure call
|
||||||
|
doesn't suppress the condition from being passed on to the calling
|
||||||
|
procedure
|
||||||
|
|
||||||
|
drop procedure if exists p1;
|
||||||
|
drop procedure if exists p0;
|
||||||
|
create table t1 (id int);
|
||||||
|
create procedure p1 () begin
|
||||||
|
declare i int default 0;
|
||||||
|
declare continue handler for not found begin
|
||||||
|
select "You should see this message and the warning that generated this" as "message";
|
||||||
|
show warnings;
|
||||||
|
end;
|
||||||
|
select id into i from t1;
|
||||||
|
end$$
|
||||||
|
create procedure p0 () begin
|
||||||
|
declare continue handler for not found begin
|
||||||
|
select "You should NOT see this message" as "message";
|
||||||
|
end;
|
||||||
|
call p1();
|
||||||
|
end$$
|
||||||
|
call p0();
|
||||||
|
message
|
||||||
|
You should see this message and the warning that generated this
|
||||||
|
Level Code Message
|
||||||
|
Warning 1329 No data - zero rows fetched, selected, or processed
|
||||||
|
Warnings:
|
||||||
|
Warning 1329 No data - zero rows fetched, selected, or processed
|
||||||
|
drop procedure p1;
|
||||||
|
drop procedure p0;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
Test if stored procedures propagates errors
|
||||||
|
|
||||||
|
create table t1 (id int primary key);
|
||||||
|
create procedure p1 () begin
|
||||||
|
insert into t1 values(1);
|
||||||
|
insert into t1 values(2);
|
||||||
|
insert into t1 values(2);
|
||||||
|
insert into t1 values(3);
|
||||||
|
end$$
|
||||||
|
create procedure p2 () begin
|
||||||
|
declare x int;
|
||||||
|
select id into x from t1 where id=5;
|
||||||
|
end$$
|
||||||
|
call p1();
|
||||||
|
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Error 1062 Duplicate entry '2' for key 'PRIMARY'
|
||||||
|
select * from t1;
|
||||||
|
id
|
||||||
|
1
|
||||||
|
2
|
||||||
|
call p2();
|
||||||
|
Warnings:
|
||||||
|
Warning 1329 No data - zero rows fetched, selected, or processed
|
||||||
|
drop procedure p1;
|
||||||
|
drop procedure p2;
|
||||||
|
drop table t1;
|
||||||
# End of 5.5 test
|
# End of 5.5 test
|
||||||
|
@ -9209,5 +9209,66 @@ DROP FUNCTION f2;
|
|||||||
DROP FUNCTION f3;
|
DROP FUNCTION f3;
|
||||||
DROP FUNCTION f4;
|
DROP FUNCTION f4;
|
||||||
|
|
||||||
--echo # End of 5.5 test
|
--echo
|
||||||
|
--echo Stored procedures and a condition handler in a nested procedure call
|
||||||
|
--echo doesn't suppress the condition from being passed on to the calling
|
||||||
|
--echo procedure
|
||||||
|
--echo
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop procedure if exists p1;
|
||||||
|
drop procedure if exists p0;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
create table t1 (id int);
|
||||||
|
delimiter $$;
|
||||||
|
create procedure p1 () begin
|
||||||
|
declare i int default 0;
|
||||||
|
declare continue handler for not found begin
|
||||||
|
select "You should see this message and the warning that generated this" as "message";
|
||||||
|
show warnings;
|
||||||
|
end;
|
||||||
|
select id into i from t1;
|
||||||
|
end$$
|
||||||
|
create procedure p0 () begin
|
||||||
|
declare continue handler for not found begin
|
||||||
|
select "You should NOT see this message" as "message";
|
||||||
|
end;
|
||||||
|
call p1();
|
||||||
|
end$$
|
||||||
|
delimiter ;$$
|
||||||
|
call p0();
|
||||||
|
|
||||||
|
drop procedure p1;
|
||||||
|
drop procedure p0;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo Test if stored procedures propagates errors
|
||||||
|
--echo
|
||||||
|
|
||||||
|
create table t1 (id int primary key);
|
||||||
|
delimiter $$;
|
||||||
|
create procedure p1 () begin
|
||||||
|
insert into t1 values(1);
|
||||||
|
insert into t1 values(2);
|
||||||
|
insert into t1 values(2);
|
||||||
|
insert into t1 values(3);
|
||||||
|
end$$
|
||||||
|
create procedure p2 () begin
|
||||||
|
declare x int;
|
||||||
|
select id into x from t1 where id=5;
|
||||||
|
end$$
|
||||||
|
delimiter ;$$
|
||||||
|
--error ER_DUP_ENTRY
|
||||||
|
call p1();
|
||||||
|
show warnings;
|
||||||
|
select * from t1;
|
||||||
|
call p2();
|
||||||
|
|
||||||
|
drop procedure p1;
|
||||||
|
drop procedure p2;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo # End of 5.5 test
|
||||||
|
@ -1160,8 +1160,9 @@ find_handler_after_execution(THD *thd, sp_rcontext *ctx)
|
|||||||
MYSQL_ERROR *err;
|
MYSQL_ERROR *err;
|
||||||
while ((err= it++))
|
while ((err= it++))
|
||||||
{
|
{
|
||||||
if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_WARN &&
|
if ((err->get_level() != MYSQL_ERROR::WARN_LEVEL_WARN &&
|
||||||
err->get_level() != MYSQL_ERROR::WARN_LEVEL_NOTE)
|
err->get_level() != MYSQL_ERROR::WARN_LEVEL_NOTE) ||
|
||||||
|
err->handled())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ctx->find_handler(thd,
|
if (ctx->find_handler(thd,
|
||||||
@ -1170,6 +1171,7 @@ find_handler_after_execution(THD *thd, sp_rcontext *ctx)
|
|||||||
err->get_level(),
|
err->get_level(),
|
||||||
err->get_message_text()))
|
err->get_message_text()))
|
||||||
{
|
{
|
||||||
|
err->mark_handled();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,7 @@ MYSQL_ERROR::MYSQL_ERROR()
|
|||||||
m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin),
|
m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin),
|
||||||
m_message_text(),
|
m_message_text(),
|
||||||
m_sql_errno(0),
|
m_sql_errno(0),
|
||||||
|
m_handled(0),
|
||||||
m_level(MYSQL_ERROR::WARN_LEVEL_ERROR),
|
m_level(MYSQL_ERROR::WARN_LEVEL_ERROR),
|
||||||
m_mem_root(NULL)
|
m_mem_root(NULL)
|
||||||
{
|
{
|
||||||
@ -212,6 +213,7 @@ void MYSQL_ERROR::clear()
|
|||||||
m_cursor_name.length(0);
|
m_cursor_name.length(0);
|
||||||
m_message_text.length(0);
|
m_message_text.length(0);
|
||||||
m_sql_errno= 0;
|
m_sql_errno= 0;
|
||||||
|
m_handled= 0;
|
||||||
m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
|
m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,6 +231,7 @@ MYSQL_ERROR::MYSQL_ERROR(MEM_ROOT *mem_root)
|
|||||||
m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin),
|
m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin),
|
||||||
m_message_text(),
|
m_message_text(),
|
||||||
m_sql_errno(0),
|
m_sql_errno(0),
|
||||||
|
m_handled(0),
|
||||||
m_level(MYSQL_ERROR::WARN_LEVEL_ERROR),
|
m_level(MYSQL_ERROR::WARN_LEVEL_ERROR),
|
||||||
m_mem_root(mem_root)
|
m_mem_root(mem_root)
|
||||||
{
|
{
|
||||||
@ -267,6 +270,7 @@ MYSQL_ERROR::copy_opt_attributes(const MYSQL_ERROR *cond)
|
|||||||
copy_string(m_mem_root, & m_table_name, & cond->m_table_name);
|
copy_string(m_mem_root, & m_table_name, & cond->m_table_name);
|
||||||
copy_string(m_mem_root, & m_column_name, & cond->m_column_name);
|
copy_string(m_mem_root, & m_column_name, & cond->m_column_name);
|
||||||
copy_string(m_mem_root, & m_cursor_name, & cond->m_cursor_name);
|
copy_string(m_mem_root, & m_cursor_name, & cond->m_cursor_name);
|
||||||
|
m_handled= cond->m_handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -191,6 +191,17 @@ public:
|
|||||||
MYSQL_ERROR::enum_warning_level get_level() const
|
MYSQL_ERROR::enum_warning_level get_level() const
|
||||||
{ return m_level; }
|
{ return m_level; }
|
||||||
|
|
||||||
|
/** check if condition was handled by a condition handler */
|
||||||
|
bool handled() const
|
||||||
|
{
|
||||||
|
return m_handled;
|
||||||
|
}
|
||||||
|
/** mark that condition was handled */
|
||||||
|
void mark_handled()
|
||||||
|
{
|
||||||
|
m_handled= 1;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
The interface of MYSQL_ERROR is mostly private, by design,
|
The interface of MYSQL_ERROR is mostly private, by design,
|
||||||
@ -306,6 +317,9 @@ private:
|
|||||||
/** MySQL extension, MYSQL_ERRNO condition item. */
|
/** MySQL extension, MYSQL_ERRNO condition item. */
|
||||||
uint m_sql_errno;
|
uint m_sql_errno;
|
||||||
|
|
||||||
|
/** Marker if error/warning was handled by a continue handler */
|
||||||
|
bool m_handled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
SQL RETURNED_SQLSTATE condition item.
|
SQL RETURNED_SQLSTATE condition item.
|
||||||
This member is always NUL terminated.
|
This member is always NUL terminated.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user