summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2016-08-17 10:33:31 +0400
committerAlexander Barkov <bar@mariadb.org>2017-04-05 15:02:44 +0400
commit8feb984211f559ad8bf2f231544cf8852b23632d (patch)
tree7fac25a4c0ff09df8cbca18390efb652c560c9c8
parent765d9d6429588d3aa27ded3e58bb6bac3e7c139b (diff)
downloadmariadb-git-8feb984211f559ad8bf2f231544cf8852b23632d.tar.gz
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.
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-code.result110
-rw-r--r--mysql-test/suite/compat/oracle/r/sp.result92
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-code.test78
-rw-r--r--mysql-test/suite/compat/oracle/t/sp.test107
-rw-r--r--sql/sp_pcontext.cc22
-rw-r--r--sql/sp_pcontext.h10
-rw-r--r--sql/sql_lex.cc40
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_yacc_ora.yy15
9 files changed, 469 insertions, 8 deletions
diff --git a/mysql-test/suite/compat/oracle/r/sp-code.result b/mysql-test/suite/compat/oracle/r/sp-code.result
index 8e6d6d940e4..b3605b19db4 100644
--- a/mysql-test/suite/compat/oracle/r/sp-code.result
+++ b/mysql-test/suite/compat/oracle/r/sp-code.result
@@ -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;
diff --git a/mysql-test/suite/compat/oracle/r/sp.result b/mysql-test/suite/compat/oracle/r/sp.result
index d0fb26b04ae..13c4e246c0b 100644
--- a/mysql-test/suite/compat/oracle/r/sp.result
+++ b/mysql-test/suite/compat/oracle/r/sp.result
@@ -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;
diff --git a/mysql-test/suite/compat/oracle/t/sp-code.test b/mysql-test/suite/compat/oracle/t/sp-code.test
index dffd1a19fd2..23a74c0cae8 100644
--- a/mysql-test/suite/compat/oracle/t/sp-code.test
+++ b/mysql-test/suite/compat/oracle/t/sp-code.test
@@ -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;
diff --git a/mysql-test/suite/compat/oracle/t/sp.test b/mysql-test/suite/compat/oracle/t/sp.test
index 6b47ab4f7d6..8fa242a770e 100644
--- a/mysql-test/suite/compat/oracle/t/sp.test
+++ b/mysql-test/suite/compat/oracle/t/sp.test
@@ -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;
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index e8748ffb852..db2d36978d4 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -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)
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index cbebc157dbb..6cbd98e89a8 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -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();
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 65e89ec7c58..07f411e39a0 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -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;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 14094da8cbf..21c7e8797b6 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -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);
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index 028513c4fe6..94cfaa7107c 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -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
{