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)
|
f1(2, 3, 2, 3)
|
||||||
2004
|
2004
|
||||||
DROP FUNCTION f1;
|
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)
|
f1(2, 3, 2, 3)
|
||||||
2004
|
2004
|
||||||
DROP FUNCTION f1;
|
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;
|
SELECT f1(3, 2) FROM DUAL;
|
||||||
DROP FUNCTION f1;
|
DROP FUNCTION f1;
|
||||||
|
|
||||||
|
|
||||||
--echo # Testing labeled FOR LOOP statement
|
--echo # Testing labeled FOR LOOP statement
|
||||||
|
|
||||||
DELIMITER /;
|
DELIMITER /;
|
||||||
@ -514,3 +515,81 @@ SELECT f1(2, 1, 2, 2) FROM DUAL;
|
|||||||
SELECT f1(2, 2, 2, 2) FROM DUAL;
|
SELECT f1(2, 2, 2, 2) FROM DUAL;
|
||||||
SELECT f1(2, 3, 2, 3) FROM DUAL;
|
SELECT f1(2, 3, 2, 3) FROM DUAL;
|
||||||
DROP FUNCTION f1;
|
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, 2, 2, 2) FROM DUAL;
|
||||||
SELECT f1(2, 3, 2, 3) FROM DUAL;
|
SELECT f1(2, 3, 2, 3) FROM DUAL;
|
||||||
DROP FUNCTION f1;
|
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
|
HANDLER_SCOPE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Lex_for_loop: public Lex_for_loop_st
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Lex_for_loop() { init(); }
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
sp_pcontext();
|
sp_pcontext();
|
||||||
~sp_pcontext();
|
~sp_pcontext();
|
||||||
@ -513,6 +519,15 @@ public:
|
|||||||
uint current_cursor_count() const
|
uint current_cursor_count() const
|
||||||
{ return m_cursor_offset + m_cursors.elements(); }
|
{ 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:
|
private:
|
||||||
/// Constructor for a tree node.
|
/// Constructor for a tree node.
|
||||||
/// @param prev the parent parsing context
|
/// @param prev the parent parsing context
|
||||||
@ -583,6 +598,9 @@ private:
|
|||||||
|
|
||||||
/// Scope of this parsing context.
|
/// Scope of this parsing context.
|
||||||
enum_scope m_scope;
|
enum_scope m_scope;
|
||||||
|
|
||||||
|
/// FOR LOOP characteristics
|
||||||
|
Lex_for_loop m_for_loop;
|
||||||
}; // class sp_pcontext : public Sql_alloc
|
}; // 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)
|
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);
|
sphead->reset_lex(thd);
|
||||||
if (thd->lex->sp_for_loop_condition(thd, loop))
|
if (thd->lex->sp_for_loop_condition(thd, loop))
|
||||||
return true;
|
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);
|
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", label_name.str);
|
||||||
return true;
|
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) ||
|
return sp_change_context(thd, lab->ctx, false) ||
|
||||||
sphead->add_instr_jump(thd, spcont, lab->ip); /* Jump back */
|
sphead->add_instr_jump(thd, spcont, lab->ip); /* Jump back */
|
||||||
}
|
}
|
||||||
|
@ -675,6 +675,16 @@ public:
|
|||||||
class sp_variable *m_index;
|
class sp_variable *m_index;
|
||||||
class sp_variable *m_upper_bound;
|
class sp_variable *m_upper_bound;
|
||||||
int m_direction;
|
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