diff options
-rw-r--r-- | mysql-test/suite/compat/oracle/r/sp-code.result | 120 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/r/sp.result | 47 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/t/sp-code.test | 79 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/t/sp.test | 33 | ||||
-rw-r--r-- | sql/sp_pcontext.h | 18 | ||||
-rw-r--r-- | sql/sql_lex.cc | 10 | ||||
-rw-r--r-- | sql/structs.h | 10 |
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; + } }; |