Bug#8153 (Stored procedure with subquery and continue handler, wrong result)

Implemented code review comments
Test cleanup
parent 154bb53b
...@@ -5218,12 +5218,18 @@ CHARSET(p2) COLLATION(p2) ...@@ -5218,12 +5218,18 @@ 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| use test|
DROP DATABASE mysqltest1|
drop table if exists t3|
drop table if exists t4|
drop procedure if exists bug8153_subselect| drop procedure if exists bug8153_subselect|
drop procedure if exists bug8153_function| drop procedure if exists bug8153_subselect_a|
drop procedure if exists bug8153_subselect_b|
drop procedure if exists bug8153_proc_a|
drop procedure if exists bug8153_proc_b|
create table t3 (a int)| create table t3 (a int)|
create table t4 (a int)| create table t4 (a int)|
insert into t3 values (1)| insert into t3 values (1), (1), (2), (3)|
insert into t4 values (1), (1)| insert into t4 values (1), (1)|
create procedure bug8153_subselect() create procedure bug8153_subselect()
begin begin
...@@ -5242,6 +5248,9 @@ statement after update ...@@ -5242,6 +5248,9 @@ statement after update
select * from t3| select * from t3|
a a
1 1
1
2
3
call bug8153_subselect()| call bug8153_subselect()|
statement failed statement failed
statement failed statement failed
...@@ -5250,24 +5259,75 @@ statement after update ...@@ -5250,24 +5259,75 @@ statement after update
select * from t3| select * from t3|
a a
1 1
1
2
3
drop procedure bug8153_subselect| drop procedure bug8153_subselect|
create procedure bug8153_function_a() create procedure bug8153_subselect_a()
begin
declare continue handler for sqlexception
begin
select 'in continue handler';
end;
select 'reachable code a1';
call bug8153_subselect_b();
select 'reachable code a2';
end|
create procedure bug8153_subselect_b()
begin
select 'reachable code b1';
update t3 set a=a+1 where (select a from t4 where a=1) is null;
select 'unreachable code b2';
end|
call bug8153_subselect_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
select * from t3|
a
1
1
2
3
call bug8153_subselect_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
select * from t3|
a
1
1
2
3
drop procedure bug8153_subselect_a|
drop procedure bug8153_subselect_b|
create procedure bug8153_proc_a()
begin begin
declare continue handler for sqlexception declare continue handler for sqlexception
begin begin
select 'in continue handler'; select 'in continue handler';
end; end;
select 'reachable code a1'; select 'reachable code a1';
call bug8153_function_b(); call bug8153_proc_b();
select 'reachable code a2'; select 'reachable code a2';
end| end|
create procedure bug8153_function_b() create procedure bug8153_proc_b()
begin begin
select 'reachable code b1'; select 'reachable code b1';
select no_such_function(); select no_such_function();
select 'unreachable code b2'; select 'unreachable code b2';
end| end|
call bug8153_function_a()| call bug8153_proc_a()|
reachable code a1 reachable code a1
reachable code a1 reachable code a1
reachable code b1 reachable code b1
...@@ -5276,10 +5336,10 @@ in continue handler ...@@ -5276,10 +5336,10 @@ in continue handler
in continue handler in continue handler
reachable code a2 reachable code a2
reachable code a2 reachable code a2
drop procedure bug8153_function_a| drop procedure bug8153_proc_a|
drop procedure bug8153_function_b| drop procedure bug8153_proc_b|
use test| drop table t3|
DROP DATABASE mysqltest1| drop table t4|
drop procedure if exists bug19862| drop procedure if exists bug19862|
CREATE TABLE t11 (a INT)| CREATE TABLE t11 (a INT)|
CREATE TABLE t12 (a INT)| CREATE TABLE t12 (a INT)|
......
...@@ -6141,19 +6141,28 @@ SET @v3 = 'c'| ...@@ -6141,19 +6141,28 @@ 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)|
# Cleanup.
use test|
DROP DATABASE mysqltest1|
# #
# BUG#8153: Stored procedure with subquery and continue handler, wrong result # BUG#8153: Stored procedure with subquery and continue handler, wrong result
# #
--disable_warnings --disable_warnings
drop table if exists t3, t4, t5| drop table if exists t3|
drop table if exists t4|
drop procedure if exists bug8153_subselect| drop procedure if exists bug8153_subselect|
drop procedure if exists bug8153_function| drop procedure if exists bug8153_subselect_a|
drop procedure if exists bug8153_subselect_b|
drop procedure if exists bug8153_proc_a|
drop procedure if exists bug8153_proc_b|
--enable_warnings --enable_warnings
create table t3 (a int)| create table t3 (a int)|
create table t4 (a int)| create table t4 (a int)|
insert into t3 values (1)| insert into t3 values (1), (1), (2), (3)|
insert into t4 values (1), (1)| insert into t4 values (1), (1)|
## Testing the use case reported in Bug#8153 ## Testing the use case reported in Bug#8153
...@@ -6176,10 +6185,40 @@ select * from t3| ...@@ -6176,10 +6185,40 @@ select * from t3|
drop procedure bug8153_subselect| drop procedure bug8153_subselect|
## Testing a subselect with a non local handler
create procedure bug8153_subselect_a()
begin
declare continue handler for sqlexception
begin
select 'in continue handler';
end;
select 'reachable code a1';
call bug8153_subselect_b();
select 'reachable code a2';
end|
create procedure bug8153_subselect_b()
begin
select 'reachable code b1';
update t3 set a=a+1 where (select a from t4 where a=1) is null;
select 'unreachable code b2';
end|
call bug8153_subselect_a()|
select * from t3|
call bug8153_subselect_a()|
select * from t3|
drop procedure bug8153_subselect_a|
drop procedure bug8153_subselect_b|
## Testing extra use cases, found while investigating ## Testing extra use cases, found while investigating
## This is related to BUG#18787, with a non local handler ## This is related to BUG#18787, with a non local handler
create procedure bug8153_function_a() create procedure bug8153_proc_a()
begin begin
declare continue handler for sqlexception declare continue handler for sqlexception
begin begin
...@@ -6187,27 +6226,24 @@ begin ...@@ -6187,27 +6226,24 @@ begin
end; end;
select 'reachable code a1'; select 'reachable code a1';
call bug8153_function_b(); call bug8153_proc_b();
select 'reachable code a2'; select 'reachable code a2';
end| end|
create procedure bug8153_function_b() create procedure bug8153_proc_b()
begin begin
select 'reachable code b1'; select 'reachable code b1';
select no_such_function(); select no_such_function();
select 'unreachable code b2'; select 'unreachable code b2';
end| end|
call bug8153_function_a()| call bug8153_proc_a()|
drop procedure bug8153_function_a|
drop procedure bug8153_function_b|
# Cleanup.
use test| drop procedure bug8153_proc_a|
drop procedure bug8153_proc_b|
drop table t3|
drop table t4|
DROP DATABASE mysqltest1|
# #
# BUG#19862: Sort with filesort by function evaluates function twice # BUG#19862: Sort with filesort by function evaluates function twice
# #
......
...@@ -53,8 +53,18 @@ bool Protocol_prep::net_store_data(const char *from, uint length) ...@@ -53,8 +53,18 @@ bool Protocol_prep::net_store_data(const char *from, uint length)
} }
/* Send a error string to client */ /*
Send a error string to client
Design note:
net_printf_error and net_send_error are low-level functions
that shall be used only when a new connection is being
established or at server startup.
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
critical that every error that can be intercepted is issued in one
place only, my_message_sql.
*/
void net_send_error(THD *thd, uint sql_errno, const char *err) void net_send_error(THD *thd, uint sql_errno, const char *err)
{ {
NET *net= &thd->net; NET *net= &thd->net;
...@@ -64,6 +74,8 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) ...@@ -64,6 +74,8 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
err ? err : net->last_error[0] ? err ? err : net->last_error[0] ?
net->last_error : "NULL")); net->last_error : "NULL"));
DBUG_ASSERT(!thd->spcont);
if (net && net->no_send_error) if (net && net->no_send_error)
{ {
thd->clear_error(); thd->clear_error();
...@@ -71,12 +83,6 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) ...@@ -71,12 +83,6 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
if (thd->spcont &&
thd->spcont->handle_error(sql_errno, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
{
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)
{ {
...@@ -117,6 +123,15 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) ...@@ -117,6 +123,15 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
Write error package and flush to client Write error package and flush to client
It's a little too low level, but I don't want to use another buffer for It's a little too low level, but I don't want to use another buffer for
this this
Design note:
net_printf_error and net_send_error are low-level functions
that shall be used only when a new connection is being
established or at server startup.
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
critical that every error that can be intercepted is issued in one
place only, my_message_sql.
*/ */
void void
...@@ -136,6 +151,8 @@ net_printf_error(THD *thd, uint errcode, ...) ...@@ -136,6 +151,8 @@ net_printf_error(THD *thd, uint errcode, ...)
DBUG_ENTER("net_printf_error"); DBUG_ENTER("net_printf_error");
DBUG_PRINT("enter",("message: %u",errcode)); DBUG_PRINT("enter",("message: %u",errcode));
DBUG_ASSERT(!thd->spcont);
if (net && net->no_send_error) if (net && net->no_send_error)
{ {
thd->clear_error(); thd->clear_error();
...@@ -143,12 +160,6 @@ net_printf_error(THD *thd, uint errcode, ...) ...@@ -143,12 +160,6 @@ net_printf_error(THD *thd, uint errcode, ...)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
if (thd->spcont &&
thd->spcont->handle_error(errcode, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
{
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
......
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