Commit 4b614955 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-10411 Providing compatibility for basic PL/SQL constructs

Part 9: EXCEPTION handlers

EXCEPTION is now supported in inner blocks.
parent d2b007d6
SET sql_mode=ORACLE;
#
# Testing exceptions in the top-level blocks
#
# No HANDLER declarations, no exceptions
CREATE FUNCTION f1 RETURN INT
AS
......@@ -175,3 +178,221 @@ Pos Instruction
11 jump 6
12 hpop 3
DROP PROCEDURE p1;
#
# Testing EXCEPTIONS in internal blocks
#
# No HANDLER declarations, no code, no exceptions
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
BEGIN
END;
END;
/
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set v@0 123
1 jump 5
SET @v=10;
CALL p1(@v);
SELECT @v;
@v
123
DROP PROCEDURE p1;
# No HANDLER declarations, no code, some exceptions
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
BEGIN
EXCEPTION
WHEN 20002 THEN v:=335;
END;
END;
/
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set v@0 123
1 jump 2
2 hpush_jump 5 1 EXIT
3 set v@0 335
4 hreturn 0 5
5 hpop 1
SET @v=10;
CALL p1(@v);
SELECT @v;
@v
123
DROP PROCEDURE p1;
# No HANDLER declarations, some code, no exceptions
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
BEGIN
v:=223;
END;
END;
/
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set v@0 123
1 set v@0 223
2 jump 6
SET @v=10;
CALL p1(@v);
SELECT @v;
@v
223
DROP PROCEDURE p1;
# No HANDLER declarations, some code, some exceptions
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
BEGIN
v:=223;
EXCEPTION
WHEN 20002 THEN v:=335;
END;
END;
/
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set v@0 123
1 jump 4
2 set v@0 223
3 jump 7
4 hpush_jump 2 1 EXIT
5 set v@0 335
6 hreturn 0 7
7 hpop 1
SET @v=10;
CALL p1(@v);
SELECT @v;
@v
223
DROP PROCEDURE p1;
# Some HANDLER declarations, no code, no exceptions
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
DECLARE
EXIT HANDLER FOR 1000
BEGIN
v:=323;
END;
BEGIN
END;
END;
/
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set v@0 123
1 hpush_jump 4 1 EXIT
2 set v@0 323
3 hreturn 0 4
4 hpop 1
SET @v=10;
CALL p1(@v);
SELECT @v;
@v
123
DROP PROCEDURE p1;
# Some HANDLER declarations, no code, some exceptions
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
DECLARE
EXIT HANDLER FOR 1000
BEGIN
v:=323;
END;
BEGIN
EXCEPTION
WHEN 20002 THEN v:=335;
END;
END;
/
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set v@0 123
1 hpush_jump 4 1 EXIT
2 set v@0 323
3 hreturn 0 7
4 hpush_jump 7 1 EXIT
5 set v@0 335
6 hreturn 0 7
7 hpop 2
SET @v=10;
CALL p1(@v);
SELECT @v;
@v
123
DROP PROCEDURE p1;
# Some HANDLER declarations, some code, no exceptions
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
DECLARE
EXIT HANDLER FOR 1000
BEGIN
v:=323;
END;
BEGIN
v:= 324;
END;
END;
/
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set v@0 123
1 hpush_jump 4 1 EXIT
2 set v@0 323
3 hreturn 0 5
4 set v@0 324
5 hpop 1
SET @v=10;
CALL p1(@v);
SELECT @v;
@v
324
DROP PROCEDURE p1;
# Some HANDLER declarations, some code, some exceptions
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
DECLARE
EXIT HANDLER FOR 1000
BEGIN
v:=323;
END;
BEGIN
v:= 324;
EXCEPTION WHEN 2002 THEN v:= 325;
END;
END;
/
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set v@0 123
1 hpush_jump 6 1 EXIT
2 set v@0 323
3 hreturn 0 9
4 set v@0 324
5 jump 9
6 hpush_jump 4 1 EXIT
7 set v@0 325
8 hreturn 0 9
9 hpop 2
SET @v=10;
CALL p1(@v);
SELECT @v;
@v
324
DROP PROCEDURE p1;
......@@ -465,3 +465,31 @@ SELECT @v;
@v
113
DROP PROCEDURE sp1;
CREATE PROCEDURE sp1 (v IN OUT INT, error IN INT)
IS
BEGIN
BEGIN
BEGIN
SIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=error, MESSAGE_TEXT='User defined error!';
v:= 223;
EXCEPTION
WHEN 30001 THEN
BEGIN
v:= 113;
END;
END;
END;
END;
/
SET @v=10;
CALL sp1(@v, 30001);
SELECT @v;
@v
113
SET @v=10;
CALL sp1(@v, 30002);
ERROR 45000: User defined error!
SELECT @v;
@v
10
DROP PROCEDURE sp1;
......@@ -2,6 +2,10 @@
SET sql_mode=ORACLE;
--echo #
--echo # Testing exceptions in the top-level blocks
--echo #
--echo # No HANDLER declarations, no exceptions
DELIMITER /;
CREATE FUNCTION f1 RETURN INT
......@@ -143,3 +147,175 @@ END;
DELIMITER ;/
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
--echo #
--echo # Testing EXCEPTIONS in internal blocks
--echo #
--echo # No HANDLER declarations, no code, no exceptions
DELIMITER /;
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
BEGIN
END;
END;
/
DELIMITER ;/
SHOW PROCEDURE CODE p1;
SET @v=10;
CALL p1(@v);
SELECT @v;
DROP PROCEDURE p1;
--echo # No HANDLER declarations, no code, some exceptions
DELIMITER /;
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
BEGIN
EXCEPTION
WHEN 20002 THEN v:=335;
END;
END;
/
DELIMITER ;/
SHOW PROCEDURE CODE p1;
SET @v=10;
CALL p1(@v);
SELECT @v;
DROP PROCEDURE p1;
--echo # No HANDLER declarations, some code, no exceptions
DELIMITER /;
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
BEGIN
v:=223;
END;
END;
/
DELIMITER ;/
SHOW PROCEDURE CODE p1;
SET @v=10;
CALL p1(@v);
SELECT @v;
DROP PROCEDURE p1;
--echo # No HANDLER declarations, some code, some exceptions
DELIMITER /;
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
BEGIN
v:=223;
EXCEPTION
WHEN 20002 THEN v:=335;
END;
END;
/
DELIMITER ;/
SHOW PROCEDURE CODE p1;
SET @v=10;
CALL p1(@v);
SELECT @v;
DROP PROCEDURE p1;
--echo # Some HANDLER declarations, no code, no exceptions
DELIMITER /;
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
DECLARE
EXIT HANDLER FOR 1000
BEGIN
v:=323;
END;
BEGIN
END;
END;
/
DELIMITER ;/
SHOW PROCEDURE CODE p1;
SET @v=10;
CALL p1(@v);
SELECT @v;
DROP PROCEDURE p1;
--echo # Some HANDLER declarations, no code, some exceptions
DELIMITER /;
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
DECLARE
EXIT HANDLER FOR 1000
BEGIN
v:=323;
END;
BEGIN
EXCEPTION
WHEN 20002 THEN v:=335;
END;
END;
/
DELIMITER ;/
SHOW PROCEDURE CODE p1;
SET @v=10;
CALL p1(@v);
SELECT @v;
DROP PROCEDURE p1;
--echo # Some HANDLER declarations, some code, no exceptions
DELIMITER /;
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
DECLARE
EXIT HANDLER FOR 1000
BEGIN
v:=323;
END;
BEGIN
v:= 324;
END;
END;
/
DELIMITER ;/
SHOW PROCEDURE CODE p1;
SET @v=10;
CALL p1(@v);
SELECT @v;
DROP PROCEDURE p1;
--echo # Some HANDLER declarations, some code, some exceptions
DELIMITER /;
CREATE PROCEDURE p1 (v IN OUT INT)
IS
BEGIN
v:=123;
DECLARE
EXIT HANDLER FOR 1000
BEGIN
v:=323;
END;
BEGIN
v:= 324;
EXCEPTION WHEN 2002 THEN v:= 325;
END;
END;
/
DELIMITER ;/
SHOW PROCEDURE CODE p1;
SET @v=10;
CALL p1(@v);
SELECT @v;
DROP PROCEDURE p1;
......@@ -497,3 +497,31 @@ CALL sp1(@v, 30001);
CALL sp1(@v, 30002);
SELECT @v;
DROP PROCEDURE sp1;
DELIMITER /;
CREATE PROCEDURE sp1 (v IN OUT INT, error IN INT)
IS
BEGIN
BEGIN
BEGIN
SIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=error, MESSAGE_TEXT='User defined error!';
v:= 223;
EXCEPTION
WHEN 30001 THEN
BEGIN
v:= 113;
END;
END;
END;
END;
/
DELIMITER ;/
SET @v=10;
CALL sp1(@v, 30001);
SELECT @v;
SET @v=10;
--error 30002
CALL sp1(@v, 30002);
SELECT @v;
DROP PROCEDURE sp1;
......@@ -832,6 +832,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
ulong ulong_num;
ulonglong ulonglong_number;
longlong longlong_number;
uint sp_instr_addr;
/* structs */
LEX_STRING lex_str;
......@@ -839,6 +840,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
Lex_string_with_metadata_st lex_string_with_metadata;
struct sys_var_with_base variable;
Lex_spblock_st spblock;
Lex_spblock_handlers_st spblock_handlers;
Lex_length_and_dec_st Lex_length_and_dec;
Lex_cast_type_st Lex_cast_type;
Lex_field_type_st Lex_field_type;
......
......@@ -215,6 +215,7 @@ static bool push_sp_empty_label(THD *thd)
Lex_string_with_metadata_st lex_string_with_metadata;
struct sys_var_with_base variable;
Lex_spblock_st spblock;
Lex_spblock_handlers_st spblock_handlers;
Lex_length_and_dec_st Lex_length_and_dec;
Lex_cast_type_st Lex_cast_type;
Lex_field_type_st Lex_field_type;
......@@ -1311,9 +1312,9 @@ END_OF_INPUT
%type <num> sp_decl_idents sp_handler_type sp_hcond_list
%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
%type <spblock> sp_decl_body sp_decl_body_list opt_sp_decl_body_list
%type <spblock_handlers> sp_block_statements_and_exceptions
%type <sp_instr_addr> sp_instr_addr
%type <num> opt_exception_clause exception_handlers
%type <num> sp_block_statements_and_exceptions
%type <lex> sp_cursor_stmt
%type <spname> sp_name
%type <spvar> sp_param_name sp_param_name_and_type
......@@ -3407,12 +3408,14 @@ sp_labeled_block:
BEGIN_SYM
{
Lex->sp_block_init(thd, $1);
if (Lex->sp_block_with_exceptions_finalize_declarations(thd))
MYSQL_YYABORT;
}
sp_proc_stmts
sp_block_statements_and_exceptions
END
sp_opt_label
{
if (Lex->sp_block_finalize(thd, $6))
if (Lex->sp_block_finalize(thd, Lex_spblock($4), $6))
MYSQL_YYABORT;
}
| sp_block_label
......@@ -3421,12 +3424,17 @@ sp_labeled_block:
Lex->sp_block_init(thd, $1);
}
sp_decl_body_list
{
if (Lex->sp_block_with_exceptions_finalize_declarations(thd))
MYSQL_YYABORT;
}
BEGIN_SYM
sp_proc_stmts
sp_block_statements_and_exceptions
END
sp_opt_label
{
if (Lex->sp_block_finalize(thd, $4, $8))
$4.hndlrs+= $7.hndlrs;
if (Lex->sp_block_finalize(thd, $4, $9))
MYSQL_YYABORT;
}
;
......@@ -3435,11 +3443,13 @@ sp_unlabeled_block:
BEGIN_SYM
{
Lex->sp_block_init(thd);
if (Lex->sp_block_with_exceptions_finalize_declarations(thd))
MYSQL_YYABORT;
}
sp_proc_stmts
sp_block_statements_and_exceptions
END
{
if (Lex->sp_block_finalize(thd))
if (Lex->sp_block_finalize(thd, Lex_spblock($3)))
MYSQL_YYABORT;
}
| DECLARE_SYM
......@@ -3447,10 +3457,15 @@ sp_unlabeled_block:
Lex->sp_block_init(thd);
}
sp_decl_body_list
{
if (Lex->sp_block_with_exceptions_finalize_declarations(thd))
MYSQL_YYABORT;
}
BEGIN_SYM
sp_proc_stmts
sp_block_statements_and_exceptions
END
{
$3.hndlrs+= $6.hndlrs;
if (Lex->sp_block_finalize(thd, $3))
MYSQL_YYABORT;
}
......@@ -3472,7 +3487,7 @@ sp_body:
BEGIN_SYM
sp_block_statements_and_exceptions
{
$2.hndlrs+= $5;
$2.hndlrs+= $5.hndlrs;
if (Lex->sp_block_finalize(thd, $2))
MYSQL_YYABORT;
}
......@@ -3491,7 +3506,7 @@ sp_block_statements_and_exceptions:
{
if (Lex->sp_block_with_exceptions_finalize_exceptions(thd, $1, $4))
MYSQL_YYABORT;
$$= $4;
$$.init($4);
}
;
......
......@@ -628,12 +628,20 @@ struct Lex_dyncol_type_st: public Lex_length_and_dec_st
int dyncol_type() const { return m_type; }
};
struct Lex_spblock_st
struct Lex_spblock_handlers_st
{
public:
int hndlrs;
void init(int count) { hndlrs= count; }
};
struct Lex_spblock_st: public Lex_spblock_handlers_st
{
public:
int vars;
int conds;
int hndlrs;
int curs;
void init()
{
......@@ -653,6 +661,11 @@ class Lex_spblock: public Lex_spblock_st
{
public:
Lex_spblock() { init(); }
Lex_spblock(const Lex_spblock_handlers_st &other)
{
vars= conds= curs= 0;
hndlrs= other.hndlrs;
}
};
#endif /* STRUCTS_INCLUDED */
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