summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-code.result120
-rw-r--r--mysql-test/suite/compat/oracle/r/sp.result47
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-code.test79
-rw-r--r--mysql-test/suite/compat/oracle/t/sp.test33
-rw-r--r--sql/sp_pcontext.h18
-rw-r--r--sql/sql_lex.cc10
-rw-r--r--sql/structs.h10
7 files changed, 317 insertions, 0 deletions
diff --git a/mysql-test/suite/compat/oracle/r/sp-code.result b/mysql-test/suite/compat/oracle/r/sp-code.result
index b6d42bfc05b..6f8de418888 100644
--- a/mysql-test/suite/compat/oracle/r/sp-code.result
+++ b/mysql-test/suite/compat/oracle/r/sp-code.result
@@ -677,3 +677,123 @@ SELECT f1(2, 3, 2, 3) FROM DUAL;
f1(2, 3, 2, 3)
2004
DROP FUNCTION f1;
+# Testing labeled ITERATE in a labeled FOR LOOP
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+<<li>>
+FOR i IN 1 .. a
+LOOP
+total:= total + 1000;
+IF i = 5 THEN
+ITERATE li;
+END IF;
+total:= total + 1;
+END LOOP;
+RETURN total;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@1 0
+1 set i@2 1
+2 set [upper_bound]@3 a@0
+3 jump_if_not 11(11) (i@2 <= [upper_bound]@3)
+4 set total@1 (total@1 + 1000)
+5 jump_if_not 8(8) (i@2 = 5)
+6 set i@2 (i@2 + 1)
+7 jump 3
+8 set total@1 (total@1 + 1)
+9 set i@2 (i@2 + 1)
+10 jump 3
+11 freturn 3 total@1
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+f1(3) f1(4) f1(5) f1(6)
+3003 4004 5004 6005
+DROP FUNCTION f1;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+<<li>>
+FOR i IN 1 .. a
+LOOP
+FOR j IN 1 .. 2
+LOOP
+total:= total + 1000;
+IF i = 5 THEN
+ITERATE li;
+END IF;
+total:= total + 1;
+END LOOP;
+END LOOP;
+RETURN total;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@1 0
+1 set i@2 1
+2 set [upper_bound]@3 a@0
+3 jump_if_not 16(16) (i@2 <= [upper_bound]@3)
+4 set j@4 1
+5 set [upper_bound]@5 2
+6 jump_if_not 14(14) (j@4 <= [upper_bound]@5)
+7 set total@1 (total@1 + 1000)
+8 jump_if_not 11(11) (i@2 = 5)
+9 set i@2 (i@2 + 1)
+10 jump 3
+11 set total@1 (total@1 + 1)
+12 set j@4 (j@4 + 1)
+13 jump 6
+14 set i@2 (i@2 + 1)
+15 jump 3
+16 freturn 3 total@1
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+f1(3) f1(4) f1(5) f1(6)
+6006 8008 9008 11010
+DROP FUNCTION f1;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+<<lj>>
+FOR j IN 1 .. 2
+LOOP
+<<li>>
+FOR i IN 1 .. a
+LOOP
+total:= total + 1000;
+IF i = 5 THEN
+ITERATE li;
+END IF;
+total:= total + 1;
+END LOOP;
+END LOOP;
+RETURN total;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@1 0
+1 set j@2 1
+2 set [upper_bound]@3 2
+3 jump_if_not 16(16) (j@2 <= [upper_bound]@3)
+4 set i@4 1
+5 set [upper_bound]@5 a@0
+6 jump_if_not 14(14) (i@4 <= [upper_bound]@5)
+7 set total@1 (total@1 + 1000)
+8 jump_if_not 11(11) (i@4 = 5)
+9 set i@4 (i@4 + 1)
+10 jump 6
+11 set total@1 (total@1 + 1)
+12 set i@4 (i@4 + 1)
+13 jump 6
+14 set j@2 (j@2 + 1)
+15 jump 3
+16 freturn 3 total@1
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+f1(3) f1(4) f1(5) f1(6)
+6006 8008 10008 12010
+DROP FUNCTION f1;
diff --git a/mysql-test/suite/compat/oracle/r/sp.result b/mysql-test/suite/compat/oracle/r/sp.result
index ef23f302a35..97b1e1d649a 100644
--- a/mysql-test/suite/compat/oracle/r/sp.result
+++ b/mysql-test/suite/compat/oracle/r/sp.result
@@ -899,3 +899,50 @@ SELECT f1(2, 3, 2, 3) FROM DUAL;
f1(2, 3, 2, 3)
2004
DROP FUNCTION f1;
+# Testing labeled ITERATE in a labeled FOR LOOP statement
+CREATE FUNCTION f1 (a INT, b INT, blim INT) RETURN INT
+AS
+total INT := 0;
+BEGIN
+<<la>>
+FOR ia IN 1 .. a
+LOOP
+total:= total + 1000;
+DECLARE
+ib INT:= 1;
+BEGIN
+WHILE ib <= b
+LOOP
+IF ib > blim THEN
+ITERATE la;
+END IF;
+ib:= ib + 1;
+total:= total + 1;
+END LOOP;
+END;
+END LOOP la;
+RETURN total;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@3 0
+1 set ia@4 1
+2 set [upper_bound]@5 a@0
+3 jump_if_not 15(15) (ia@4 <= [upper_bound]@5)
+4 set total@3 (total@3 + 1000)
+5 set ib@6 1
+6 jump_if_not 13(13) (ib@6 <= b@1)
+7 jump_if_not 10(10) (ib@6 > blim@2)
+8 set ia@4 (ia@4 + 1)
+9 jump 3
+10 set ib@6 (ib@6 + 1)
+11 set total@3 (total@3 + 1)
+12 jump 6
+13 set ia@4 (ia@4 + 1)
+14 jump 3
+15 freturn 3 total@3
+SELECT f1(3,3,0), f1(3,3,1), f1(3,3,2), f1(3,3,3), f1(3,3,4) FROM DUAL;
+f1(3,3,0) f1(3,3,1) f1(3,3,2) f1(3,3,3) f1(3,3,4)
+3000 3003 3006 3009 3009
+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 a0ab0e5ab92..73fb5fb91d6 100644
--- a/mysql-test/suite/compat/oracle/t/sp-code.test
+++ b/mysql-test/suite/compat/oracle/t/sp-code.test
@@ -486,6 +486,7 @@ SELECT f1(3, 100) FROM DUAL;
SELECT f1(3, 2) FROM DUAL;
DROP FUNCTION f1;
+
--echo # Testing labeled FOR LOOP statement
DELIMITER /;
@@ -514,3 +515,81 @@ SELECT f1(2, 1, 2, 2) FROM DUAL;
SELECT f1(2, 2, 2, 2) FROM DUAL;
SELECT f1(2, 3, 2, 3) FROM DUAL;
DROP FUNCTION f1;
+
+
+--echo # Testing labeled ITERATE in a labeled FOR LOOP
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ <<li>>
+ FOR i IN 1 .. a
+ LOOP
+ total:= total + 1000;
+ IF i = 5 THEN
+ ITERATE li;
+ END IF;
+ total:= total + 1;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ <<li>>
+ FOR i IN 1 .. a
+ LOOP
+ FOR j IN 1 .. 2
+ LOOP
+ total:= total + 1000;
+ IF i = 5 THEN
+ ITERATE li;
+ END IF;
+ total:= total + 1;
+ END LOOP;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ <<lj>>
+ FOR j IN 1 .. 2
+ LOOP
+ <<li>>
+ FOR i IN 1 .. a
+ LOOP
+ total:= total + 1000;
+ IF i = 5 THEN
+ ITERATE li;
+ END IF;
+ total:= total + 1;
+ END LOOP;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+DROP FUNCTION f1;
diff --git a/mysql-test/suite/compat/oracle/t/sp.test b/mysql-test/suite/compat/oracle/t/sp.test
index 3b301f21cea..a45e4961184 100644
--- a/mysql-test/suite/compat/oracle/t/sp.test
+++ b/mysql-test/suite/compat/oracle/t/sp.test
@@ -963,3 +963,36 @@ SELECT f1(2, 1, 2, 2) FROM DUAL;
SELECT f1(2, 2, 2, 2) FROM DUAL;
SELECT f1(2, 3, 2, 3) FROM DUAL;
DROP FUNCTION f1;
+
+
+--echo # Testing labeled ITERATE in a labeled FOR LOOP statement
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT, b INT, blim INT) RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ <<la>>
+ FOR ia IN 1 .. a
+ LOOP
+ total:= total + 1000;
+ DECLARE
+ ib INT:= 1;
+ BEGIN
+ WHILE ib <= b
+ LOOP
+ IF ib > blim THEN
+ ITERATE la;
+ END IF;
+ ib:= ib + 1;
+ total:= total + 1;
+ END LOOP;
+ END;
+ END LOOP la;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3,3,0), f1(3,3,1), f1(3,3,2), f1(3,3,3), f1(3,3,4) FROM DUAL;
+DROP FUNCTION f1;
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 6cbd98e89a8..877e43e96c0 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -268,6 +268,12 @@ public:
HANDLER_SCOPE
};
+ class Lex_for_loop: public Lex_for_loop_st
+ {
+ public:
+ Lex_for_loop() { init(); }
+ };
+
public:
sp_pcontext();
~sp_pcontext();
@@ -513,6 +519,15 @@ public:
uint current_cursor_count() const
{ return m_cursor_offset + m_cursors.elements(); }
+ void set_for_loop(const Lex_for_loop_st &for_loop)
+ {
+ m_for_loop.init(for_loop);
+ }
+ const Lex_for_loop_st &for_loop()
+ {
+ return m_for_loop;
+ }
+
private:
/// Constructor for a tree node.
/// @param prev the parent parsing context
@@ -583,6 +598,9 @@ private:
/// Scope of this parsing context.
enum_scope m_scope;
+
+ /// FOR LOOP characteristics
+ Lex_for_loop m_for_loop;
}; // class sp_pcontext : public Sql_alloc
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index a47a0fe0a46..22e6e7e5245 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -5317,6 +5317,7 @@ bool LEX::sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop)
*/
bool LEX::sp_for_loop_index_and_bounds(THD *thd, const Lex_for_loop_st &loop)
{
+ spcont->set_for_loop(loop);
sphead->reset_lex(thd);
if (thd->lex->sp_for_loop_condition(thd, loop))
return true;
@@ -5674,6 +5675,15 @@ bool LEX::sp_iterate_statement(THD *thd, const LEX_STRING label_name)
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", label_name.str);
return true;
}
+ if (lab->ctx->for_loop().m_index)
+ {
+ // We're in a FOR loop, increment the index variable before backward jump
+ sphead->reset_lex(thd);
+ DBUG_ASSERT(this != thd->lex);
+ if (thd->lex->sp_for_loop_increment(thd, lab->ctx->for_loop()) ||
+ thd->lex->sphead->restore_lex(thd))
+ return true;
+ }
return sp_change_context(thd, lab->ctx, false) ||
sphead->add_instr_jump(thd, spcont, lab->ip); /* Jump back */
}
diff --git a/sql/structs.h b/sql/structs.h
index cf1b2ff4e94..10dc1f40fa9 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -675,6 +675,16 @@ public:
class sp_variable *m_index;
class sp_variable *m_upper_bound;
int m_direction;
+ void init()
+ {
+ m_index= 0;
+ m_upper_bound= 0;
+ m_direction= 0;
+ }
+ void init(const Lex_for_loop_st &other)
+ {
+ *this= other;
+ }
};