Commit b2f80050 authored by Alexander Nozdrin's avatar Alexander Nozdrin

Auto-merge from mysql-trunk-bugfixing.

******
This patch fixes the following bugs:
  - Bug#5889: Exit handler for a warning doesn't hide the warning in
    trigger
  - Bug#9857: Stored procedures: handler for sqlwarning ignored
  - Bug#23032: Handlers declared in a SP do not handle warnings generated
    in sub-SP
  - Bug#36185: Incorrect precedence for warning and exception handlers

The problem was in the way warnings/errors during stored routine execution
were handled. Prior to this patch the logic was as follows:

  - when a warning/an error happens: if we're executing a stored routine,
    and there is a handler for that warning/error, remember the handler,
    ignore the warning/error and continue execution.

  - after a stored routine instruction is executed: check for a remembered
    handler and activate one (if any).

This logic caused several problems:

  - if one instruction generates several warnings (errors) it's impossible
    to choose the right handler -- a handler for the first generated
    condition was chosen and remembered for activation.

  - mess with handling conditions in scopes different from the current one.

  - not putting generated warnings/errors into Warning Info (Diagnostic
    Area) is against The Standard.

The patch changes the logic as follows:

  - Diagnostic Area is cleared on the beginning of each statement that
    either is able to generate warnings, or is able to work with tables.

  - at the end of a stored routine instruction, Diagnostic Area is left
    intact.

  - Diagnostic Area is checked after each stored routine instruction. If
    an instruction generates several condition, it's now possible to take a
    look at all of them and determine an appropriate handler.
parent 02a0787d
......@@ -1189,6 +1189,8 @@ end $$
call test_signal() $$
Caught by SQLSTATE
Caught by SQLSTATE
Warnings:
Warning 1012 Raising a warning
drop procedure test_signal $$
create procedure test_signal()
begin
......@@ -1204,6 +1206,8 @@ end $$
call test_signal() $$
Caught by number
Caught by number
Warnings:
Warning 1012 Raising a warning
drop procedure test_signal $$
create procedure test_signal()
begin
......@@ -1219,6 +1223,8 @@ end $$
call test_signal() $$
Caught by SQLWARNING
Caught by SQLWARNING
Warnings:
Warning 1012 Raising a warning
drop procedure test_signal $$
create procedure test_signal()
begin
......@@ -1234,6 +1240,8 @@ end $$
call test_signal() $$
Caught by SQLSTATE
Caught by SQLSTATE
Warnings:
Error 1012 Raising a not found
drop procedure test_signal $$
create procedure test_signal()
begin
......@@ -1249,6 +1257,8 @@ end $$
call test_signal() $$
Caught by number
Caught by number
Warnings:
Error 1012 Raising a not found
drop procedure test_signal $$
create procedure test_signal()
begin
......@@ -1264,6 +1274,8 @@ end $$
call test_signal() $$
Caught by NOT FOUND
Caught by NOT FOUND
Warnings:
Error 1012 Raising a not found
drop procedure test_signal $$
create procedure test_signal()
begin
......@@ -1279,6 +1291,8 @@ end $$
call test_signal() $$
Caught by SQLSTATE
Caught by SQLSTATE
Warnings:
Error 1012 Raising an error
drop procedure test_signal $$
create procedure test_signal()
begin
......@@ -1294,6 +1308,8 @@ end $$
call test_signal() $$
Caught by number
Caught by number
Warnings:
Error 1012 Raising an error
drop procedure test_signal $$
create procedure test_signal()
begin
......@@ -1309,6 +1325,8 @@ end $$
call test_signal() $$
Caught by SQLEXCEPTION
Caught by SQLEXCEPTION
Warnings:
Error 1012 Raising an error
drop procedure test_signal $$
#
# Test where SIGNAL can be used
......@@ -1455,6 +1473,7 @@ after RESIGNAL
after RESIGNAL
Warnings:
Warning 1012 Raising a warning
Warning 1012 Raising a warning
drop procedure test_resignal $$
create procedure test_resignal()
begin
......@@ -1509,6 +1528,7 @@ after RESIGNAL
after RESIGNAL
Warnings:
Warning 1264 Out of range value for column 'a' at row 1
Warning 1264 Out of range value for column 'a' at row 1
drop procedure test_resignal $$
create procedure test_resignal()
begin
......@@ -1565,6 +1585,7 @@ before RESIGNAL
after RESIGNAL
after RESIGNAL
Warnings:
Warning 1012 Raising a warning
Warning 5555 RESIGNAL of a warning
drop procedure test_resignal $$
create procedure test_resignal()
......@@ -1625,6 +1646,7 @@ before RESIGNAL
after RESIGNAL
after RESIGNAL
Warnings:
Warning 1264 Out of range value for column 'a' at row 1
Warning 5555 RESIGNAL of a warning
drop procedure test_resignal $$
create procedure test_resignal()
......@@ -2126,6 +2148,9 @@ CALL peter_p2() $$
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 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 $$
drop procedure peter_p2 $$
......@@ -2135,15 +2160,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 +2183,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 +2194,24 @@ $$
CALL peter_p2() $$
1
1
Level Code Message
Error 1231 Variable 'sql_mode' can't be set to the value of 'NULL'
2
2
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'
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 9999 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 $$
......
......@@ -95,11 +95,11 @@ call proc_1();
ERROR 45000: Oops in proc_1
show warnings;
Level Code Message
Error 1644 Oops in proc_5
Error 1644 Oops in proc_4
Error 1644 Oops in proc_3
Error 1644 Oops in proc_2
Error 1644 Oops in proc_1
Error 1051 Unknown table 'oops_it_is_not_here'
Error 1644 Oops in proc_9
Error 1644 Oops in proc_8
Error 1644 Oops in proc_7
Error 1644 Oops in proc_6
SET @@session.max_error_count = 7;
SELECT @@session.max_error_count;
@@session.max_error_count
......@@ -108,13 +108,13 @@ call proc_1();
ERROR 45000: Oops in proc_1
show warnings;
Level Code Message
Error 1051 Unknown table 'oops_it_is_not_here'
Error 1644 Oops in proc_9
Error 1644 Oops in proc_8
Error 1644 Oops in proc_7
Error 1644 Oops in proc_6
Error 1644 Oops in proc_5
Error 1644 Oops in proc_4
Error 1644 Oops in proc_3
Error 1644 Oops in proc_2
Error 1644 Oops in proc_1
SET @@session.max_error_count = 9;
SELECT @@session.max_error_count;
@@session.max_error_count
......@@ -123,6 +123,7 @@ call proc_1();
ERROR 45000: Oops in proc_1
show warnings;
Level Code Message
Error 1051 Unknown table 'oops_it_is_not_here'
Error 1644 Oops in proc_9
Error 1644 Oops in proc_8
Error 1644 Oops in proc_7
......@@ -131,7 +132,6 @@ Error 1644 Oops in proc_5
Error 1644 Oops in proc_4
Error 1644 Oops in proc_3
Error 1644 Oops in proc_2
Error 1644 Oops in proc_1
drop database demo;
SET @@global.max_error_count = @start_global_value;
SELECT @@global.max_error_count;
......
......@@ -46,6 +46,8 @@ end while;
close cur1;
end|
call p1();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
select count(*) from t1;
count(*)
256
......
......@@ -43,6 +43,8 @@ END|
SELECT f2 ();
f2 ()
NULL
Warnings:
Error 1305 FUNCTION testdb.f_not_exists does not exist
DROP SCHEMA testdb;
USE test;
#
......
......@@ -711,6 +711,8 @@ looping i
looping 1
looping i
looping 0
Warnings:
Error 1062 Duplicate entry '1' for key 'a'
call proc_26977_works(2);
do something
do something
......@@ -730,6 +732,8 @@ looping i
looping 0
optimizer: keep hreturn
optimizer: keep hreturn
Warnings:
Error 1062 Duplicate entry '2' for key 'a'
drop table t1;
drop procedure proc_26977_broken;
drop procedure proc_26977_works;
......@@ -888,3 +892,56 @@ Pos Instruction
4 jump 6
5 error 1339
DROP PROCEDURE p1;
#
# Bug#23032: Handlers declared in a SP do not handle warnings generated in sub-SP
#
# - Case 4: check that "No Data trumps Warning".
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
CREATE PROCEDURE p1()
BEGIN
DECLARE c CURSOR FOR SELECT a FROM t1;
OPEN c;
BEGIN
DECLARE v INT;
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
SELECT "Warning found!";
SHOW WARNINGS;
END;
DECLARE EXIT HANDLER FOR NOT FOUND
BEGIN
SELECT "End of Result Set found!";
SHOW WARNINGS;
END;
WHILE TRUE DO
FETCH c INTO v;
END WHILE;
END;
CLOSE c;
SELECT a INTO @foo FROM t1 LIMIT 1; # Clear warning stack
END|
SET SESSION debug="+d,bug23032_emit_warning";
CALL p1();
Warning found!
Warning found!
Level Code Message
Warning 1105 Unknown error
Warning found!
Warning found!
Level Code Message
Warning 1105 Unknown error
Warning found!
Warning found!
Level Code Message
Warning 1105 Unknown error
End of Result Set found!
End of Result Set found!
Level Code Message
Warning 1105 Unknown error
Error 1329 No data - zero rows fetched, selected, or processed
SET SESSION debug="-d,bug23032_emit_warning";
DROP PROCEDURE p1;
DROP TABLE t1;
......@@ -1344,6 +1344,8 @@ set @in_func := 0;
select func_20713_a();
func_20713_a()
NULL
Warnings:
Error 1146 Table 'test.bogus_table_20713' doesn't exist
select @in_func;
@in_func
2
......@@ -1351,6 +1353,8 @@ set @in_func := 0;
select func_20713_b();
func_20713_b()
NULL
Warnings:
Error 1146 Table 'test.bogus_table_20713' doesn't exist
select @in_func;
@in_func
2
......@@ -1714,3 +1718,246 @@ DROP PROCEDURE p1;
DROP VIEW v1;
DROP TABLE t1;
End of 5.1 tests
#
# Bug#23032: Handlers declared in a SP do not handle warnings generated in sub-SP
#
# - Case 1
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
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;
# - Case 2
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
1
Level Code Message
Warning 1292 Truncated incorrect INTEGER value: '10 '
Warnings:
Warning 1292 Truncated incorrect INTEGER value: '10 '
CALL p6();
CAST('10 ' as unsigned integer)
10
Level Code Message
Warning 1292 Truncated incorrect INTEGER value: '10 '
c
1
Warnings:
Warning 1292 Truncated incorrect INTEGER value: '10 '
DROP PROCEDURE p1;
DROP PROCEDURE p2;
DROP PROCEDURE p3;
DROP PROCEDURE p4;
DROP PROCEDURE p5;
DROP PROCEDURE p6;
# - Case 3: check that "Exception trumps No Data".
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
CREATE PROCEDURE p1()
BEGIN
DECLARE c CURSOR FOR SELECT a FROM t1;
OPEN c;
BEGIN
DECLARE v1 INT;
DECLARE v2 INT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
SELECT "Error caught (expected)";
DECLARE EXIT HANDLER FOR NOT FOUND
SELECT "End of Result Set found!";
WHILE TRUE DO
FETCH c INTO v1, v2;
END WHILE;
END;
CLOSE c;
SELECT a INTO @foo FROM t1 LIMIT 1; # Clear warning stack
END|
CALL p1();
Error caught (expected)
Error caught (expected)
DROP PROCEDURE p1;
DROP TABLE t1;
#
# Bug#36185: Incorrect precedence for warning and exception handlers
#
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 '
Error 1048 Column 'b' cannot be null
DROP TABLE t1;
DROP PROCEDURE p1;
#
# Bug#5889: Exit handler for a warning doesn't hide the warning in trigger
#
# - Case 1
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES (1, 2);
CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW
BEGIN
DECLARE EXIT HANDLER FOR SQLWARNING
SET NEW.a = 10;
SET NEW.a = 99999999999;
END|
UPDATE t1 SET b = 20;
Warnings:
Warning 1264 Out of range value for column 'a' at row 1
SHOW WARNINGS;
Level Code Message
Warning 1264 Out of range value for column 'a' at row 1
SELECT * FROM t1;
a b
10 20
DROP TRIGGER t1_bu;
DROP TABLE t1;
# - Case 2
CREATE TABLE t1(a INT);
CREATE TABLE t2(b CHAR(1));
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
INSERT INTO t2 VALUES('ab'); # Produces a warning.
INSERT INTO t2 VALUES('b'); # Does not produce a warning,
# previous warning should be cleared.
END|
INSERT INTO t1 VALUES(0);
SHOW WARNINGS;
Level Code Message
SELECT * FROM t1;
a
0
SELECT * FROM t2;
b
a
b
DROP TRIGGER t1_bi;
DROP TABLE t1;
DROP TABLE t2;
#
# Bug#9857: Stored procedures: handler for sqlwarning ignored
#
SET @sql_mode_saved = @@sql_mode;
SET sql_mode = traditional;
CREATE PROCEDURE p1()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING
SELECT 'warning caught (expected)';
SELECT 5 / 0;
END|
CREATE PROCEDURE p2()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SELECT 'error caught (unexpected)';
SELECT 5 / 0;
END|
CALL p1();
5 / 0
NULL
warning caught (expected)
warning caught (expected)
Warnings:
Warning 1365 Division by 0
SHOW WARNINGS;
Level Code Message
Warning 1365 Division by 0
CALL p2();
5 / 0
NULL
Warnings:
Warning 1365 Division by 0
SHOW WARNINGS;
Level Code Message
Warning 1365 Division by 0
DROP PROCEDURE p1;
DROP PROCEDURE p2;
SET sql_mode = @sql_mode_saved;
This diff is collapsed.
......@@ -99,6 +99,8 @@ return i;
end|
set @error_in_func:= 0|
insert into t1 values (bug10015_6(5)), (bug10015_6(6))|
Warnings:
Error 1062 Duplicate entry '1' for key 'PRIMARY'
select @error_in_func|
@error_in_func
1
......@@ -524,6 +526,8 @@ until done end repeat;
close c;
end|
call bug14210()|
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
select count(*) from t4|
count(*)
256
......
......@@ -1190,6 +1190,8 @@ select'a'; insert into t1 values (200); end;|
call t1();
a
a
Warnings:
Error 1264 Out of range value for column 'col1' at row 1
select * from t1;
col1
drop procedure t1;
......
......@@ -3946,6 +3946,8 @@ create view a as select 1;
end|
call p();
call p();
Warnings:
Error 1050 Table 'a' already exists
drop view a;
drop procedure p;
#
......
......@@ -347,6 +347,8 @@ CALL h1();
-7- 1 1 1 1 1 1
END x1 x2 x3 x4 x5 x6
END 1 1 1 1 1 1
Warnings:
Error 1062 Duplicate entry 'a' for key 'w'
DROP TABLE IF EXISTS tnull;
DROP PROCEDURE IF EXISTS sp1;
CREATE TABLE tnull(f1 int);
......@@ -445,6 +447,8 @@ END//
CALL h2();
x1 x2 x3 x4 x5 x6
1 1 1 1 1 1
Warnings:
Error 1062 Duplicate entry 'a' for key 'w'
SELECT * FROM res_t1;
w x
a b
......@@ -550,6 +554,8 @@ exit handler 2
exit handler 2
exit handler 1
exit handler 1
Warnings:
Error 1146 Table 'db_storedproc.tqq' doesn't exist
create table res_t1(w char unique, x char);
insert into res_t1 values ('a', 'b');
CREATE PROCEDURE h1 ()
......@@ -580,6 +586,8 @@ END//
CALL h1();
x1 x2 x3 x4 x5 x6
1 1 1 1 1 1
Warnings:
Error 1062 Duplicate entry 'a' for key 'w'
This will fail, SQLSTATE 00000 is not allowed
CREATE PROCEDURE sp1()
begin1_label:BEGIN
......@@ -623,6 +631,8 @@ CALL sp2();
NULL
@x2 @x
1 2
Warnings:
Error 1318 Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expected 2, got 1
DROP PROCEDURE sp1;
DROP PROCEDURE sp2;
......@@ -654,6 +664,8 @@ ERROR 42000: Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expe
CALL sp2();
-1- @x2 @x
-1- 0 1
Warnings:
Error 1318 Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expected 2, got 1
SELECT '-3-', @x2, @x;
-3- @x2 @x
-3- 1 1
......@@ -696,6 +708,8 @@ CALL sp2();
-2- 1 20
-4- @x2 @x
-4- 11 22
Warnings:
Error 1318 Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expected 2, got 1
DROP PROCEDURE sp1;
DROP PROCEDURE sp2;
......@@ -762,21 +776,33 @@ SELECT @done, @x;
0 1
INSERT INTO temp VALUES('1', NULL);
CALL sp1();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 1
INSERT INTO temp VALUES('2', NULL);
CALL sp2();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 1
INSERT INTO temp VALUES('3', NULL);
CALL sp3();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 0
INSERT INTO temp VALUES('4', NULL);
CALL sp4();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 0
......@@ -885,18 +911,26 @@ SELECT @done, @x;
@done @x
0 1
CALL sp1();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 2
CALL sp2();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 2
CALL sp3();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 1
CALL sp4();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 1
......@@ -1031,6 +1065,8 @@ SQLSTATE
21000
SQLSTATE
24000
Warnings:
Error 1326 Cursor is not open
SELECT '-1-', @x;
-1- @x
-1- 6
......@@ -1041,18 +1077,24 @@ SQLSTATE
SQLEXCEPTION
SQLSTATE
24000
Warnings:
Error 1326 Cursor is not open
SELECT '-2-', @x;
-2- @x
-2- 6
CALL sp3();
SQLSTATE
20000
Warnings:
Error 1339 Case not found for CASE statement
SELECT '-3-', @x;
-3- @x
-3- 1
CALL sp4();
SQLSTATE
SQLEXCEPTION
Warnings:
Error 1339 Case not found for CASE statement
SELECT '-4-', @x;
-4- @x
-4- 1
......@@ -1335,6 +1377,8 @@ CLOSE cur1;
CLOSE cur2;
END//
CALL sp_outer();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT * FROM temp1;
f0 cnt f1 f2 f3 f4
_sp_out_ 1 a` a` 1000-01-01 -5000
......
......@@ -348,6 +348,8 @@ CALL h1();
-7- 1 1 1 1 1 1
END x1 x2 x3 x4 x5 x6
END 1 1 1 1 1 1
Warnings:
Error 1062 Duplicate entry 'a' for key 'w'
DROP TABLE IF EXISTS tnull;
DROP PROCEDURE IF EXISTS sp1;
CREATE TABLE tnull(f1 int);
......@@ -446,6 +448,8 @@ END//
CALL h2();
x1 x2 x3 x4 x5 x6
1 1 1 1 1 1
Warnings:
Error 1062 Duplicate entry 'a' for key 'w'
SELECT * FROM res_t1;
w x
a b
......@@ -551,6 +555,8 @@ exit handler 2
exit handler 2
exit handler 1
exit handler 1
Warnings:
Error 1146 Table 'db_storedproc.tqq' doesn't exist
create table res_t1(w char unique, x char);
insert into res_t1 values ('a', 'b');
CREATE PROCEDURE h1 ()
......@@ -581,6 +587,8 @@ END//
CALL h1();
x1 x2 x3 x4 x5 x6
1 1 1 1 1 1
Warnings:
Error 1062 Duplicate entry 'a' for key 'w'
This will fail, SQLSTATE 00000 is not allowed
CREATE PROCEDURE sp1()
begin1_label:BEGIN
......@@ -624,6 +632,8 @@ CALL sp2();
NULL
@x2 @x
1 2
Warnings:
Error 1318 Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expected 2, got 1
DROP PROCEDURE sp1;
DROP PROCEDURE sp2;
......@@ -655,6 +665,8 @@ ERROR 42000: Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expe
CALL sp2();
-1- @x2 @x
-1- 0 1
Warnings:
Error 1318 Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expected 2, got 1
SELECT '-3-', @x2, @x;
-3- @x2 @x
-3- 1 1
......@@ -697,6 +709,8 @@ CALL sp2();
-2- 1 20
-4- @x2 @x
-4- 11 22
Warnings:
Error 1318 Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expected 2, got 1
DROP PROCEDURE sp1;
DROP PROCEDURE sp2;
......@@ -763,21 +777,33 @@ SELECT @done, @x;
0 1
INSERT INTO temp VALUES('1', NULL);
CALL sp1();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 1
INSERT INTO temp VALUES('2', NULL);
CALL sp2();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 1
INSERT INTO temp VALUES('3', NULL);
CALL sp3();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 0
INSERT INTO temp VALUES('4', NULL);
CALL sp4();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 0
......@@ -886,18 +912,26 @@ SELECT @done, @x;
@done @x
0 1
CALL sp1();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 2
CALL sp2();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 2
CALL sp3();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 1
CALL sp4();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 1
......@@ -1032,6 +1066,8 @@ SQLSTATE
21000
SQLSTATE
24000
Warnings:
Error 1326 Cursor is not open
SELECT '-1-', @x;
-1- @x
-1- 6
......@@ -1042,18 +1078,24 @@ SQLSTATE
SQLEXCEPTION
SQLSTATE
24000
Warnings:
Error 1326 Cursor is not open
SELECT '-2-', @x;
-2- @x
-2- 6
CALL sp3();
SQLSTATE
20000
Warnings:
Error 1339 Case not found for CASE statement
SELECT '-3-', @x;
-3- @x
-3- 1
CALL sp4();
SQLSTATE
SQLEXCEPTION
Warnings:
Error 1339 Case not found for CASE statement
SELECT '-4-', @x;
-4- @x
-4- 1
......@@ -1336,6 +1378,8 @@ CLOSE cur1;
CLOSE cur2;
END//
CALL sp_outer();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT * FROM temp1;
f0 cnt f1 f2 f3 f4
_sp_out_ 1 a` a` 1000-01-01 -5000
......
......@@ -348,6 +348,8 @@ CALL h1();
-7- 1 1 1 1 1 1
END x1 x2 x3 x4 x5 x6
END 1 1 1 1 1 1
Warnings:
Error 1062 Duplicate entry 'a' for key 'w'
DROP TABLE IF EXISTS tnull;
DROP PROCEDURE IF EXISTS sp1;
CREATE TABLE tnull(f1 int);
......@@ -446,6 +448,8 @@ END//
CALL h2();
x1 x2 x3 x4 x5 x6
1 1 1 1 1 1
Warnings:
Error 1062 Duplicate entry 'a' for key 'w'
SELECT * FROM res_t1;
w x
a b
......@@ -551,6 +555,8 @@ exit handler 2
exit handler 2
exit handler 1
exit handler 1
Warnings:
Error 1146 Table 'db_storedproc.tqq' doesn't exist
create table res_t1(w char unique, x char);
insert into res_t1 values ('a', 'b');
CREATE PROCEDURE h1 ()
......@@ -581,6 +587,8 @@ END//
CALL h1();
x1 x2 x3 x4 x5 x6
1 1 1 1 1 1
Warnings:
Error 1062 Duplicate entry 'a' for key 'w'
This will fail, SQLSTATE 00000 is not allowed
CREATE PROCEDURE sp1()
begin1_label:BEGIN
......@@ -624,6 +632,8 @@ CALL sp2();
NULL
@x2 @x
1 2
Warnings:
Error 1318 Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expected 2, got 1
DROP PROCEDURE sp1;
DROP PROCEDURE sp2;
......@@ -655,6 +665,8 @@ ERROR 42000: Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expe
CALL sp2();
-1- @x2 @x
-1- 0 1
Warnings:
Error 1318 Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expected 2, got 1
SELECT '-3-', @x2, @x;
-3- @x2 @x
-3- 1 1
......@@ -697,6 +709,8 @@ CALL sp2();
-2- 1 20
-4- @x2 @x
-4- 11 22
Warnings:
Error 1318 Incorrect number of arguments for PROCEDURE db_storedproc.sp1; expected 2, got 1
DROP PROCEDURE sp1;
DROP PROCEDURE sp2;
......@@ -763,21 +777,33 @@ SELECT @done, @x;
0 1
INSERT INTO temp VALUES('1', NULL);
CALL sp1();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 1
INSERT INTO temp VALUES('2', NULL);
CALL sp2();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 1
INSERT INTO temp VALUES('3', NULL);
CALL sp3();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 0
INSERT INTO temp VALUES('4', NULL);
CALL sp4();
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
Warning 1265 Data truncated for column 'f2' at row 1
SELECT @done, @x;
@done @x
1 0
......@@ -886,18 +912,26 @@ SELECT @done, @x;
@done @x
0 1
CALL sp1();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 2
CALL sp2();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 2
CALL sp3();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 1
CALL sp4();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT @done, @x;
@done @x
1 1
......@@ -1032,6 +1066,8 @@ SQLSTATE
21000
SQLSTATE
24000
Warnings:
Error 1326 Cursor is not open
SELECT '-1-', @x;
-1- @x
-1- 6
......@@ -1042,18 +1078,24 @@ SQLSTATE
SQLEXCEPTION
SQLSTATE
24000
Warnings:
Error 1326 Cursor is not open
SELECT '-2-', @x;
-2- @x
-2- 6
CALL sp3();
SQLSTATE
20000
Warnings:
Error 1339 Case not found for CASE statement
SELECT '-3-', @x;
-3- @x
-3- 1
CALL sp4();
SQLSTATE
SQLEXCEPTION
Warnings:
Error 1339 Case not found for CASE statement
SELECT '-4-', @x;
-4- @x
-4- 1
......@@ -1336,6 +1378,8 @@ CLOSE cur1;
CLOSE cur2;
END//
CALL sp_outer();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT * FROM temp1;
f0 cnt f1 f2 f3 f4
_sp_out_ 1 a` a` 1000-01-01 -5000
......
......@@ -77,6 +77,8 @@ id2
< ---- Master selects-- >
-------------------------
CALL test.p1();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
SELECT * FROM test.t3 ORDER BY id3;
id3 c
1 MySQL
......
......@@ -38,6 +38,8 @@ INSERT INTO t1 VALUES ('MySQL','1993-02-04'),('ROCKS', '1990-08-27'),('Texas', '
END|
CALL p2();
CALL p1();
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
DROP TABLE t1;
DROP TABLE t2;
DROP PROCEDURE p1;
......
......@@ -69,9 +69,15 @@ INSERT INTO test.t2 VALUES(NULL,0,'Testing MySQL databases is a cool ', 'MySQL C
UPDATE test.t1 SET b1 = 0 WHERE b1 = 1;
INSERT INTO test.t2 VALUES(NULL,1,'This is an after update test.', 'If this works, total will not be zero on the master or slave',1.4321,5.221,0,YEAR(NOW()),NOW());
UPDATE test.t2 SET b1 = 0 WHERE b1 = 1;
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
INSERT INTO test.t1 VALUES(NULL,1,'add some more test data test.', 'and hope for the best', 3.321,5.221,0,YEAR(NOW()),NOW());
DELETE FROM test.t1 WHERE id = 1;
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
DELETE FROM test.t2 WHERE id = 1;
Warnings:
Error 1329 No data - zero rows fetched, selected, or processed
DROP TRIGGER test.t1_bi;
DROP TRIGGER test.t2_ai;
DROP TRIGGER test.t1_bu;
......
......@@ -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;
......
......@@ -649,3 +649,56 @@ END//
DELIMITER ;//
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
--echo #
--echo # Bug#23032: Handlers declared in a SP do not handle warnings generated in sub-SP
--echo #
--echo
--echo # - Case 4: check that "No Data trumps Warning".
--echo
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
delimiter |;
CREATE PROCEDURE p1()
BEGIN
DECLARE c CURSOR FOR SELECT a FROM t1;
OPEN c;
BEGIN
DECLARE v INT;
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
SELECT "Warning found!";
SHOW WARNINGS;
END;
DECLARE EXIT HANDLER FOR NOT FOUND
BEGIN
SELECT "End of Result Set found!";
SHOW WARNINGS;
END;
WHILE TRUE DO
FETCH c INTO v;
END WHILE;
END;
CLOSE c;
SELECT a INTO @foo FROM t1 LIMIT 1; # Clear warning stack
END|
delimiter ;|
SET SESSION debug="+d,bug23032_emit_warning";
CALL p1();
SET SESSION debug="-d,bug23032_emit_warning";
DROP PROCEDURE p1;
DROP TABLE t1;
......@@ -2543,3 +2543,273 @@ DROP TABLE t1;
--echo End of 5.1 tests
--echo #
--echo # Bug#23032: Handlers declared in a SP do not handle warnings generated in sub-SP
--echo #
--echo
--echo # - Case 1
--echo
--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
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;
--echo
--echo # - Case 2
--echo
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;
--echo
--echo # - Case 3: check that "Exception trumps No Data".
--echo
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
delimiter |;
CREATE PROCEDURE p1()
BEGIN
DECLARE c CURSOR FOR SELECT a FROM t1;
OPEN c;
BEGIN
DECLARE v1 INT;
DECLARE v2 INT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
SELECT "Error caught (expected)";
DECLARE EXIT HANDLER FOR NOT FOUND
SELECT "End of Result Set found!";
WHILE TRUE DO
FETCH c INTO v1, v2;
END WHILE;
END;
CLOSE c;
SELECT a INTO @foo FROM t1 LIMIT 1; # Clear warning stack
END|
delimiter ;|
CALL p1();
DROP PROCEDURE p1;
DROP TABLE t1;
--echo #
--echo # Bug#36185: Incorrect precedence for warning and exception handlers
--echo #
--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;
--echo #
--echo # Bug#5889: Exit handler for a warning doesn't hide the warning in trigger
--echo #
--echo
--echo # - Case 1
--echo
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES (1, 2);
delimiter |;
CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW
BEGIN
DECLARE EXIT HANDLER FOR SQLWARNING
SET NEW.a = 10;
SET NEW.a = 99999999999;
END|
delimiter ;|
UPDATE t1 SET b = 20;
SHOW WARNINGS;
SELECT * FROM t1;
DROP TRIGGER t1_bu;
DROP TABLE t1;
--echo
--echo # - Case 2
--echo
CREATE TABLE t1(a INT);
CREATE TABLE t2(b CHAR(1));
delimiter |;
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
INSERT INTO t2 VALUES('ab'); # Produces a warning.
INSERT INTO t2 VALUES('b'); # Does not produce a warning,
# previous warning should be cleared.
END|
delimiter ;|
INSERT INTO t1 VALUES(0);
SHOW WARNINGS;
SELECT * FROM t1;
SELECT * FROM t2;
DROP TRIGGER t1_bi;
DROP TABLE t1;
DROP TABLE t2;
--echo #
--echo # Bug#9857: Stored procedures: handler for sqlwarning ignored
--echo #
SET @sql_mode_saved = @@sql_mode;
SET sql_mode = traditional;
delimiter |;
CREATE PROCEDURE p1()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING
SELECT 'warning caught (expected)';
SELECT 5 / 0;
END|
CREATE PROCEDURE p2()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SELECT 'error caught (unexpected)';
SELECT 5 / 0;
END|
delimiter ;|
CALL p1();
SHOW WARNINGS;
CALL p2();
SHOW WARNINGS;
DROP PROCEDURE p1;
DROP PROCEDURE p2;
SET sql_mode = @sql_mode_saved;
......@@ -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|
#
......
......@@ -1075,6 +1075,104 @@ void sp_head::recursion_level_error(THD *thd)
}
/**
Find an SQL handler for any condition (warning or error) after execution
of a stored routine instruction. Basically, this function looks for an
appropriate SQL handler in RT-contexts. If an SQL handler is found, it is
remembered in the RT-context for future activation (the context can be
inactive at the moment).
If there is no pending condition, the function just returns.
If there was an error during the execution, an SQL handler for it will be
searched within the current and outer scopes.
There might be several errors in the Warning Info (that's possible by using
SIGNAL/RESIGNAL in nested scopes) -- the function is looking for an SQL
handler for the latest (current) error only.
If there was a warning during the execution, an SQL handler for it will be
searched within the current scope only.
If several warnings were thrown during the execution and there are different
SQL handlers for them, it is not determined which SQL handler will be chosen.
Only one SQL handler will be executed.
If warnings and errors were thrown during the execution, the error takes
precedence. I.e. error handler will be executed. If there is no handler
for that error, condition will remain unhandled.
Once a warning or an error has been handled it is not removed from
Warning Info.
According to The Standard (quoting PeterG):
An SQL procedure statement works like this ...
SQL/Foundation 13.5 <SQL procedure statement>
(General Rules) (greatly summarized) says:
(1) Empty diagnostics area, thus clearing the condition.
(2) Execute statement.
During execution, if Exception Condition occurs,
set Condition Area = Exception Condition and stop
statement.
During execution, if No Data occurs,
set Condition Area = No Data Condition and continue
statement.
During execution, if Warning occurs,
and Condition Area is not already full due to
an earlier No Data condition, set Condition Area
= Warning and continue statement.
(3) Finish statement.
At end of execution, if Condition Area is not
already full due to an earlier No Data or Warning,
set Condition Area = Successful Completion.
In effect, this system means there is a precedence:
Exception trumps No Data, No Data trumps Warning,
Warning trumps Successful Completion.
NB: "Procedure statements" include any DDL or DML or
control statements. So CREATE and DELETE and WHILE
and CALL and RETURN are procedure statements. But
DECLARE and END are not procedure statements.
@param thd thread handle
@param ctx runtime context of the stored routine
*/
static void
find_handler_after_execution(THD *thd, sp_rcontext *ctx)
{
if (thd->is_error())
{
ctx->find_handler(thd,
thd->stmt_da->sql_errno(),
thd->stmt_da->get_sqlstate(),
MYSQL_ERROR::WARN_LEVEL_ERROR,
thd->stmt_da->message());
}
else 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 &&
err->get_level() != MYSQL_ERROR::WARN_LEVEL_NOTE)
continue;
if (ctx->find_handler(thd,
err->get_sql_errno(),
err->get_sqlstate(),
err->get_level(),
err->get_message_text()))
{
break;
}
}
}
}
/**
Execute the routine. The main instruction jump loop is there.
Assume the parameters already set.
......@@ -1096,7 +1194,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;
......@@ -1157,8 +1255,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;
......@@ -1243,7 +1339,6 @@ sp_head::execute(THD *thd)
do
{
sp_instr *i;
uint hip;
#if defined(ENABLED_PROFILING)
/*
......@@ -1265,6 +1360,9 @@ sp_head::execute(THD *thd)
break;
}
/* Reset number of warnings for this query. */
thd->warning_info->reset_for_next_command();
DBUG_PRINT("execute", ("Instruction %u", ip));
/*
......@@ -1309,40 +1407,28 @@ sp_head::execute(THD *thd)
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").
Find and process SQL handlers unless it is a fatal error (fatal
errors are not catchable by SQL handlers) or the connection has been
killed during execution.
*/
if (ctx)
if (!thd->is_fatal_error && !thd->killed_errno())
{
uint handler_index;
/*
Find SQL handler in the appropriate RT-contexts:
- warnings can be handled by SQL handlers within
the current scope only;
- errors can be handled by any SQL handler from outer scope.
*/
find_handler_after_execution(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;
/* If found, activate handler for the current scope. */
if (ctx->activate_handler(thd, &ip, i, &execute_arena, &backup_arena))
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;
}
/* Reset sp_rcontext::end_partial_result_set flag. */
ctx->end_partial_result_set= FALSE;
}
} while (!err_status && !thd->killed && !thd->is_fatal_error);
#if defined(ENABLED_PROFILING)
......@@ -3037,23 +3123,14 @@ sp_instr_set::exec_core(THD *thd, uint *nextp)
{
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));
}
}
......@@ -3586,18 +3663,6 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
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);
......@@ -3773,13 +3838,11 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
{
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();
......@@ -3788,13 +3851,7 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
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
......
......@@ -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);
......
This diff is collapsed.
......@@ -131,67 +131,40 @@ class sp_rcontext : public Sql_alloc
return m_return_value_set;
}
/*
SQL handlers support.
*/
void push_handler(struct sp_cond_type *cond, uint h, int type);
void pop_handlers(uint count);
// Returns 1 if a handler was found, 0 otherwise.
bool
find_handler(THD *thd,
uint sql_errno,
const char* sqlstate,
MYSQL_ERROR::enum_warning_level level,
const char* msg,
MYSQL_ERROR ** cond_hdl);
// 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,
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;
}
MYSQL_ERROR* raised_condition() const;
const char *msg);
// Returns true if we found a handler in this context
inline bool
found_handler_here()
{
return (m_hfound >= 0);
}
MYSQL_ERROR *
raised_condition() const;
// Clears the handler find state
inline void
clear_handler()
{
m_hfound= -1;
}
void
push_hstack(uint h);
void push_hstack(uint h);
uint
pop_hstack();
uint pop_hstack();
bool
activate_handler(THD *thd,
uint *ip,
sp_instr *instr,
Query_arena *execute_arena,
Query_arena *backup_arena);
/**
Enter a SQL exception handler.
@param hip the handler instruction pointer
@param index the handler index
*/
void enter_handler(uint hip, uint index);
void exit_handler();
void
exit_handler();
void
push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
......@@ -199,7 +172,7 @@ class sp_rcontext : public Sql_alloc
void
pop_cursors(uint count);
void
inline void
pop_all_cursors()
{
pop_cursors(m_ccount);
......
......@@ -845,35 +845,6 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno,
}
}
/*
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);
DBUG_RETURN(cond);
}
MYSQL_ERROR*
THD::raise_condition_no_handler(uint sql_errno,
const char* sqlstate,
MYSQL_ERROR::enum_warning_level level,
const char* msg)
{
MYSQL_ERROR *cond= NULL;
DBUG_ENTER("THD::raise_condition_no_handler");
query_cache_abort(&query_cache_tls);
/* FIXME: broken special case */
......@@ -886,6 +857,7 @@ THD::raise_condition_no_handler(uint sql_errno,
cond= warning_info->push_warning(this, sql_errno, sqlstate, level, msg);
DBUG_RETURN(cond);
}
extern "C"
void *thd_alloc(MYSQL_THD thd, unsigned int size)
{
......
......@@ -2800,23 +2800,6 @@ private:
MYSQL_ERROR::enum_warning_level level,
const char* msg);
/**
Raise a generic SQL condition, without activation any SQL condition
handlers.
This method is necessary to support the RESIGNAL statement,
which is allowed to bypass SQL exception handlers.
@param sql_errno the condition error number
@param sqlstate the condition SQLSTATE
@param level the condition level
@param msg the condition message text
@return The condition raised, or NULL
*/
MYSQL_ERROR*
raise_condition_no_handler(uint sql_errno,
const char* sqlstate,
MYSQL_ERROR::enum_warning_level level,
const char* msg);
public:
/** Overloaded to guard query/query_length fields */
virtual void set_statement(Statement *stmt);
......
......@@ -494,14 +494,6 @@ void Warning_info::clear_warning_info(ulonglong warn_id_arg)
m_current_row_for_warning= 1; /* Start counting from the first row */
}
void Warning_info::reserve_space(THD *thd, uint count)
{
/* Make room for count conditions */
while ((m_warn_list.elements > 0) &&
((m_warn_list.elements + count) > thd->variables.max_error_count))
m_warn_list.pop();
}
/**
Append warnings only if the original contents of the routine
warning info was replaced.
......
......@@ -153,8 +153,8 @@ private:
Representation of a SQL condition.
A SQL condition can be a completion condition (note, warning),
or an exception condition (error, not found).
@note This class is named MYSQL_ERROR instead of SQL_condition for historical reasons,
to facilitate merging code with previous releases.
@note This class is named MYSQL_ERROR instead of SQL_condition for
historical reasons, to facilitate merging code with previous releases.
*/
class MYSQL_ERROR : public Sql_alloc
{
......@@ -471,18 +471,6 @@ public:
ulong statement_warn_count() const { return m_statement_warn_count; }
/**
Reserve some space in the condition area.
This is a privileged operation, reserved for the RESIGNAL implementation,
as only the RESIGNAL statement is allowed to remove conditions from
the condition area.
For other statements, new conditions are not added to the condition
area once the condition area is full.
@param thd The current thread
@param count The number of slots to reserve
*/
void reserve_space(THD *thd, uint count);
/** Add a new condition to the current list. */
MYSQL_ERROR *push_warning(THD *thd,
uint sql_errno, const char* sqlstate,
......
......@@ -499,18 +499,6 @@ bool Resignal_statement::execute(THD *thd)
}
/* RESIGNAL with signal_value */
/* Make room for 2 conditions */
thd->warning_info->reserve_space(thd, 2);
MYSQL_ERROR *raised= NULL;
raised= thd->raise_condition_no_handler(signaled->get_sql_errno(),
signaled->get_sqlstate(),
signaled->get_level(),
signaled->get_message_text());
if (raised)
raised->copy_opt_attributes(signaled);
result= raise_condition(thd, signaled);
DBUG_RETURN(result);
......
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