mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-10411 Providing compatibility for basic PL/SQL constructs
Fixed that the ITERATE statement inside a FOR LOOP statement did not increment the index variable before jumping to the beginning of the loop, which caused the loop to repeat endlessly.
This commit is contained in:
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user