mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-10411 Providing compatibility for basic PL/SQL constructs
Part 5: EXIT statement Adding unconditional EXIT statement: EXIT [ label ] Conditional EXIT statements with WHERE clause will be added in a separate patch.
This commit is contained in:
@ -396,3 +396,113 @@ SELECT @v;
|
||||
@v
|
||||
324
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Testing EXIT statement
|
||||
#
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
LOOP
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
SHOW FUNCTION CODE f1;
|
||||
Pos Instruction
|
||||
0 set i@0 0
|
||||
1 set i@0 (i@0 + 1)
|
||||
2 jump_if_not 1(1) (i@0 >= 5)
|
||||
3 jump 4
|
||||
4 freturn 3 i@0
|
||||
SELECT f1() FROM DUAL;
|
||||
f1()
|
||||
5
|
||||
DROP FUNCTION f1;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
LOOP
|
||||
BEGIN
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN i:= 1000;
|
||||
END;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
SHOW FUNCTION CODE f1;
|
||||
Pos Instruction
|
||||
0 set i@0 0
|
||||
1 jump 5
|
||||
2 set i@0 (i@0 + 1)
|
||||
3 jump_if_not 8(8) (i@0 >= 5)
|
||||
4 jump 10
|
||||
5 hpush_jump 2 1 EXIT
|
||||
6 set i@0 1000
|
||||
7 hreturn 0 8
|
||||
8 hpop 1
|
||||
9 jump 5
|
||||
10 freturn 3 i@0
|
||||
SELECT f1() FROM DUAL;
|
||||
f1()
|
||||
5
|
||||
DROP FUNCTION f1;
|
||||
CREATE PROCEDURE p1(a IN OUT INT)
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
LOOP
|
||||
LOOP
|
||||
BEGIN
|
||||
i:= i + 1;
|
||||
IF i >=5 THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN a:=1000;
|
||||
END;
|
||||
END LOOP;
|
||||
i:= i + 100;
|
||||
EXIT;
|
||||
END LOOP;
|
||||
a:= i;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN a:=11;
|
||||
END;
|
||||
/
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set i@1 0
|
||||
1 jump 14
|
||||
2 set i@1 (i@1 + 1)
|
||||
3 jump_if_not 8(8) (i@1 >= 5)
|
||||
4 jump 10
|
||||
5 hpush_jump 2 2 EXIT
|
||||
6 set a@0 1000
|
||||
7 hreturn 0 8
|
||||
8 hpop 1
|
||||
9 jump 5
|
||||
10 set i@1 (i@1 + 100)
|
||||
11 jump 12
|
||||
12 set a@0 i@1
|
||||
13 jump 17
|
||||
14 hpush_jump 5 2 EXIT
|
||||
15 set a@0 11
|
||||
16 hreturn 0 17
|
||||
17 hpop 1
|
||||
set @v= 10;
|
||||
CALL p1(@v);
|
||||
SELECT @v;
|
||||
@v
|
||||
105
|
||||
DROP PROCEDURE p1;
|
||||
|
@ -493,3 +493,95 @@ SELECT @v;
|
||||
@v
|
||||
10
|
||||
DROP PROCEDURE sp1;
|
||||
#
|
||||
# Testing EXIT statement
|
||||
#
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
EXIT;
|
||||
END;
|
||||
/
|
||||
ERROR 42000: EXIT with no matching label:
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
<<lable1>>
|
||||
BEGIN
|
||||
<<label2>>
|
||||
LOOP
|
||||
EXIT label1;
|
||||
END LOOP;
|
||||
END;
|
||||
END;
|
||||
/
|
||||
ERROR 42000: EXIT with no matching label: label1
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
LOOP
|
||||
LOOP
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
i:= i + 100;
|
||||
EXIT;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
SELECT f1() FROM DUAL;
|
||||
f1()
|
||||
105
|
||||
DROP FUNCTION f1;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
<<label1>>
|
||||
LOOP
|
||||
<<label2>>
|
||||
LOOP
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT label2;
|
||||
END IF;
|
||||
END LOOP;
|
||||
i:= i + 100;
|
||||
EXIT;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
SELECT f1() FROM DUAL;
|
||||
f1()
|
||||
105
|
||||
DROP FUNCTION f1;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
<<label1>>
|
||||
LOOP
|
||||
<<label2>>
|
||||
LOOP
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT label1;
|
||||
END IF;
|
||||
END LOOP;
|
||||
i:= i + 100;
|
||||
EXIT;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
SELECT f1() FROM DUAL;
|
||||
f1()
|
||||
5
|
||||
DROP FUNCTION f1;
|
||||
|
@ -319,3 +319,81 @@ SET @v=10;
|
||||
CALL p1(@v);
|
||||
SELECT @v;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo #
|
||||
--echo # Testing EXIT statement
|
||||
--echo #
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
LOOP
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
SHOW FUNCTION CODE f1;
|
||||
SELECT f1() FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
LOOP
|
||||
BEGIN
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN i:= 1000;
|
||||
END;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
SHOW FUNCTION CODE f1;
|
||||
SELECT f1() FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
||||
|
||||
DELIMITER /;
|
||||
CREATE PROCEDURE p1(a IN OUT INT)
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
LOOP
|
||||
LOOP
|
||||
BEGIN
|
||||
i:= i + 1;
|
||||
IF i >=5 THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN a:=1000;
|
||||
END;
|
||||
END LOOP;
|
||||
i:= i + 100;
|
||||
EXIT;
|
||||
END LOOP;
|
||||
a:= i;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN a:=11;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
SHOW PROCEDURE CODE p1;
|
||||
set @v= 10;
|
||||
CALL p1(@v);
|
||||
SELECT @v;
|
||||
DROP PROCEDURE p1;
|
||||
|
@ -525,3 +525,110 @@ SET @v=10;
|
||||
CALL sp1(@v, 30002);
|
||||
SELECT @v;
|
||||
DROP PROCEDURE sp1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Testing EXIT statement
|
||||
--echo #
|
||||
|
||||
DELIMITER /;
|
||||
--error ER_SP_LILABEL_MISMATCH
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
EXIT;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
|
||||
|
||||
DELIMITER /;
|
||||
--error ER_SP_LILABEL_MISMATCH
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
<<lable1>>
|
||||
BEGIN
|
||||
<<label2>>
|
||||
LOOP
|
||||
EXIT label1;
|
||||
END LOOP;
|
||||
END;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
LOOP
|
||||
LOOP
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
i:= i + 100;
|
||||
EXIT;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
SELECT f1() FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
<<label1>>
|
||||
LOOP
|
||||
<<label2>>
|
||||
LOOP
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT label2;
|
||||
END IF;
|
||||
END LOOP;
|
||||
i:= i + 100;
|
||||
EXIT;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
SELECT f1() FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
IS
|
||||
i INT := 0;
|
||||
BEGIN
|
||||
<<label1>>
|
||||
LOOP
|
||||
<<label2>>
|
||||
LOOP
|
||||
i:= i + 1;
|
||||
IF i >= 5 THEN
|
||||
EXIT label1;
|
||||
END IF;
|
||||
END LOOP;
|
||||
i:= i + 100;
|
||||
EXIT;
|
||||
END LOOP;
|
||||
RETURN i;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
SELECT f1() FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
@ -197,10 +197,11 @@ sp_variable *sp_pcontext::add_variable(THD *thd, LEX_STRING name)
|
||||
}
|
||||
|
||||
|
||||
sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip)
|
||||
sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip,
|
||||
sp_label::enum_type type)
|
||||
{
|
||||
sp_label *label=
|
||||
new (thd->mem_root) sp_label(name, ip, sp_label::IMPLICIT, this);
|
||||
new (thd->mem_root) sp_label(name, ip, type, this);
|
||||
|
||||
if (!label)
|
||||
return NULL;
|
||||
@ -236,6 +237,23 @@ sp_label *sp_pcontext::find_label(const LEX_STRING name)
|
||||
}
|
||||
|
||||
|
||||
sp_label *sp_pcontext::find_label_current_loop_start()
|
||||
{
|
||||
List_iterator_fast<sp_label> li(m_labels);
|
||||
sp_label *lab;
|
||||
|
||||
while ((lab= li++))
|
||||
{
|
||||
if (lab->type == sp_label::ITERATION)
|
||||
return lab;
|
||||
}
|
||||
// See a comment in sp_pcontext::find_label()
|
||||
return (m_parent && (m_scope == REGULAR_SCOPE)) ?
|
||||
m_parent->find_label_current_loop_start() :
|
||||
NULL;
|
||||
}
|
||||
|
||||
|
||||
bool sp_pcontext::add_condition(THD *thd,
|
||||
LEX_STRING name,
|
||||
sp_condition_value *value)
|
||||
|
@ -402,10 +402,18 @@ public:
|
||||
// Labels.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sp_label *push_label(THD *thd, const LEX_STRING name, uint ip);
|
||||
sp_label *push_label(THD *thd, const LEX_STRING name, uint ip,
|
||||
sp_label::enum_type type);
|
||||
|
||||
sp_label *push_label(THD *thd, const LEX_STRING name, uint ip)
|
||||
{
|
||||
return push_label(thd, name, ip, sp_label::IMPLICIT);
|
||||
}
|
||||
|
||||
sp_label *find_label(const LEX_STRING name);
|
||||
|
||||
sp_label *find_label_current_loop_start();
|
||||
|
||||
sp_label *last_label()
|
||||
{
|
||||
sp_label *label= m_labels.head();
|
||||
|
@ -5312,8 +5312,7 @@ bool LEX::sp_handler_declaration_finalize(THD *thd, int type)
|
||||
|
||||
void LEX::sp_block_init(THD *thd, const LEX_STRING label)
|
||||
{
|
||||
sp_label *lab= spcont->push_label(thd, label, sphead->instructions());
|
||||
lab->type= sp_label::BEGIN;
|
||||
spcont->push_label(thd, label, sphead->instructions(), sp_label::BEGIN);
|
||||
spcont= spcont->push_context(thd, sp_pcontext::REGULAR_SCOPE);
|
||||
}
|
||||
|
||||
@ -5478,7 +5477,12 @@ bool LEX::sp_leave_statement(THD *thd, const LEX_STRING label_name)
|
||||
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", label_name.str);
|
||||
return true;
|
||||
}
|
||||
return sp_exit_block(thd, lab);
|
||||
}
|
||||
|
||||
|
||||
bool LEX::sp_exit_block(THD *thd, sp_label *lab)
|
||||
{
|
||||
/*
|
||||
When jumping to a BEGIN-END block end, the target jump
|
||||
points to the block hpop/cpop cleanup instructions,
|
||||
@ -5493,6 +5497,31 @@ bool LEX::sp_leave_statement(THD *thd, const LEX_STRING label_name)
|
||||
}
|
||||
|
||||
|
||||
bool LEX::sp_exit_statement(THD *thd)
|
||||
{
|
||||
sp_label *lab= spcont->find_label_current_loop_start();
|
||||
if (!lab)
|
||||
{
|
||||
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "EXIT", "");
|
||||
return true;
|
||||
}
|
||||
DBUG_ASSERT(lab->type == sp_label::ITERATION);
|
||||
return sp_exit_block(thd, lab);
|
||||
}
|
||||
|
||||
|
||||
bool LEX::sp_exit_statement(THD *thd, const LEX_STRING label_name)
|
||||
{
|
||||
sp_label *lab= spcont->find_label(label_name);
|
||||
if (!lab || lab->type != sp_label::ITERATION)
|
||||
{
|
||||
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "EXIT", label_name);
|
||||
return true;
|
||||
}
|
||||
return sp_exit_block(thd, lab);
|
||||
}
|
||||
|
||||
|
||||
bool LEX::sp_iterate_statement(THD *thd, const LEX_STRING label_name)
|
||||
{
|
||||
sp_label *lab= spcont->find_label(label_name);
|
||||
@ -5527,8 +5556,8 @@ bool LEX::sp_push_loop_label(THD *thd, const LEX_STRING label_name)
|
||||
my_error(ER_SP_LABEL_REDEFINE, MYF(0), label_name.str);
|
||||
return true;
|
||||
}
|
||||
lab= spcont->push_label(thd, label_name, sphead->instructions());
|
||||
lab->type= sp_label::ITERATION;
|
||||
spcont->push_label(thd, label_name, sphead->instructions(),
|
||||
sp_label::ITERATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5538,7 +5567,8 @@ bool LEX::sp_push_loop_empty_label(THD *thd)
|
||||
if (maybe_start_compound_statement(thd))
|
||||
return true;
|
||||
/* Unlabeled controls get an empty label. */
|
||||
spcont->push_label(thd, empty_lex_str, sphead->instructions());
|
||||
spcont->push_label(thd, empty_lex_str, sphead->instructions(),
|
||||
sp_label::ITERATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3152,6 +3152,9 @@ public:
|
||||
uint executable_section_ip,
|
||||
uint exception_count);
|
||||
bool sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive);
|
||||
bool sp_exit_block(THD *thd, sp_label *lab);
|
||||
bool sp_exit_statement(THD *thd);
|
||||
bool sp_exit_statement(THD *thd, const LEX_STRING label_name);
|
||||
bool sp_leave_statement(THD *thd, const LEX_STRING label_name);
|
||||
bool sp_iterate_statement(THD *thd, const LEX_STRING label_name);
|
||||
|
||||
|
@ -1260,6 +1260,7 @@ END_OF_INPUT
|
||||
%type <NONE> sp_proc_stmt_if
|
||||
%type <NONE> sp_labeled_control sp_unlabeled_control
|
||||
%type <NONE> sp_labeled_block sp_unlabeled_block sp_unlabeled_block_not_atomic
|
||||
%type <NONE> sp_proc_stmt_exit
|
||||
%type <NONE> sp_proc_stmt_leave
|
||||
%type <NONE> sp_proc_stmt_iterate
|
||||
%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
|
||||
@ -2858,6 +2859,7 @@ sp_proc_stmt_in_returns_clause:
|
||||
sp_proc_stmt:
|
||||
sp_proc_stmt_in_returns_clause
|
||||
| sp_proc_stmt_statement
|
||||
| sp_proc_stmt_exit
|
||||
| sp_proc_stmt_leave
|
||||
| sp_proc_stmt_iterate
|
||||
| sp_proc_stmt_open
|
||||
@ -2961,6 +2963,19 @@ sp_proc_stmt_return:
|
||||
}
|
||||
;
|
||||
|
||||
sp_proc_stmt_exit:
|
||||
EXIT_SYM
|
||||
{
|
||||
if (Lex->sp_exit_statement(thd))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| EXIT_SYM label_ident
|
||||
{
|
||||
if (Lex->sp_exit_statement(thd, $2))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
sp_proc_stmt_leave:
|
||||
LEAVE_SYM label_ident
|
||||
{
|
||||
|
Reference in New Issue
Block a user