mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-32275 getting error 'Illegal parameter data types row and bigint for operation '+' ' when using ITERATE in a FOR..DO
An "ITERATE innerLoop" did not work properly inside a WHILE loop, which itself is inside an outer FOR loop: outerLoop: FOR ... innerLoop: WHILE ... ITERATE innerLoop; ... END WHILE; ... END FOR; It erroneously generated an integer increment code for the outer FOR loop. There were two problems: 1. "ITERATE innerLoop" worked like "ITERATE outerLoop" 2. It was always integer increment, even in case of FOR cursor loops. Background: - A FOR loop automatically creates a dedicated sp_pcontext stack entry, to put the iteration and bound variables on it. - Other loop types (LOOP, WHILE, REPEAT), do not generate a dedicated slack entry. The old code erroneously assumed that sp_pcontext::m_for_loop either describes the most inner loop (in case the inner loop is FOR), or is empty (in case the inner loop is not FOR). But in fact, sp_pcontext::m_for_loop is never empty inside a FOR loop: it describes the closest FOR loop, even if this FOR loop has nested non-FOR loops inside. So when we're near the ITERATE statement in the above script, sp_pcontext::m_for_loop is not empty - it stores information about the FOR loop labeled as "outrLoop:". Fix: - Adding a new member sp_pcontext::Lex_for_loop::m_start_label, to remember the explicit or the auto-generated label correspoding to the start of the FOR body. It's used during generation of "ITERATE loop_label" code to check if "loop_label" belongs to the current FOR loop pointed by sp_pcontext::m_for_loop, or belongs to a non-FOR nested loop. - Adding LEX methods sp_for_loop_intrange_iterate() and sp_for_loop_cursor_iterate() to reuse the code between methods handling: * ITERATE * END FOR - Adding a test for Lex_for_loop::is_for_loop_cursor() and generate a code either a cursor fetch, or for an integer increment. Before this change, it always erroneously generated an integer increment version. - Cleanup: Initialize Lex_for_loop_st::m_cursor_offset inside Lex_for_loop_st::init(), to avoid not initialized members. - Cleanup: Removing a redundant method: Lex_for_loop_st::init(const Lex_for_loop_st &other) Using Lex_for_loop_st::operator(const Lex_for_loop_st &other) instead.
This commit is contained in:
@ -1356,3 +1356,330 @@ drop function f1;
|
||||
#
|
||||
# End of 10.3 tests
|
||||
#
|
||||
#
|
||||
# Start of 10.4 tests
|
||||
#
|
||||
#
|
||||
# MDEV-32275 getting error 'Illegal parameter data types row and bigint for operation '+' ' when using ITERATE in a FOR..DO
|
||||
#
|
||||
#
|
||||
# Unlabeled FOR/cursor with a nested labeled LOOP inside
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
FOR _row IN (SELECT '' AS a) DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop: LOOP
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _row.a = 'v1'
|
||||
THEN
|
||||
SELECT 'start of THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END LOOP;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set loopDone@0 0
|
||||
1 cpush [implicit_cursor]@0
|
||||
2 cursor_copy_struct [implicit_cursor] _row@1
|
||||
3 copen [implicit_cursor]@0
|
||||
4 cfetch [implicit_cursor]@0 _row@1
|
||||
5 jump_if_not 19(19) `[implicit_cursor]`%FOUND
|
||||
6 stmt 0 "SELECT 'start of outerLoop'"
|
||||
7 stmt 0 "SELECT 'start of innerLoop'"
|
||||
8 jump_if_not 10(10) loopDone@0
|
||||
9 jump 16
|
||||
10 set loopDone@0 1
|
||||
11 jump_if_not 14(14) _row.a@1["a"] = 'v1'
|
||||
12 stmt 0 "SELECT 'start of THEN block'"
|
||||
13 jump 7
|
||||
14 stmt 0 "SELECT 'end of innerLoop'"
|
||||
15 jump 7
|
||||
16 stmt 0 "SELECT 'end of outerLoop'"
|
||||
17 cfetch [implicit_cursor]@0 _row@1
|
||||
18 jump 5
|
||||
19 cpop 1
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Labeled FOR/cursor with a nested labeled LOOP
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
outerLoop:
|
||||
FOR _row IN (SELECT '' AS a) DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop: LOOP
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _row.a = 'v1'
|
||||
THEN
|
||||
SELECT 'start of IF/v1/THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
IF _row.a = 'v2'
|
||||
THEN
|
||||
SELECT 'start of IF/v2/THEN block';
|
||||
ITERATE outerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END LOOP;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set loopDone@0 0
|
||||
1 cpush [implicit_cursor]@0
|
||||
2 cursor_copy_struct [implicit_cursor] _row@1
|
||||
3 copen [implicit_cursor]@0
|
||||
4 cfetch [implicit_cursor]@0 _row@1
|
||||
5 jump_if_not 23(23) `[implicit_cursor]`%FOUND
|
||||
6 stmt 0 "SELECT 'start of outerLoop'"
|
||||
7 stmt 0 "SELECT 'start of innerLoop'"
|
||||
8 jump_if_not 10(10) loopDone@0
|
||||
9 jump 20
|
||||
10 set loopDone@0 1
|
||||
11 jump_if_not 14(14) _row.a@1["a"] = 'v1'
|
||||
12 stmt 0 "SELECT 'start of IF/v1/THEN block'"
|
||||
13 jump 7
|
||||
14 jump_if_not 18(18) _row.a@1["a"] = 'v2'
|
||||
15 stmt 0 "SELECT 'start of IF/v2/THEN block'"
|
||||
16 cfetch [implicit_cursor]@0 _row@1
|
||||
17 jump 5
|
||||
18 stmt 0 "SELECT 'end of innerLoop'"
|
||||
19 jump 7
|
||||
20 stmt 0 "SELECT 'end of outerLoop'"
|
||||
21 cfetch [implicit_cursor]@0 _row@1
|
||||
22 jump 5
|
||||
23 cpop 1
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Unlabeled FOR/integer with a labeled LOOP inside
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
FOR _index IN 1..10 DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop: LOOP
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _index = 1
|
||||
THEN
|
||||
SELECT 'start of THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END LOOP;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set loopDone@0 0
|
||||
1 set _index@1 1
|
||||
2 set [target_bound]@2 10
|
||||
3 jump_if_not 19(19) _index@1 <= [target_bound]@2
|
||||
4 stmt 0 "SELECT 'start of outerLoop'"
|
||||
5 stmt 0 "SELECT 'start of innerLoop'"
|
||||
6 jump_if_not 8(8) loopDone@0
|
||||
7 jump 14
|
||||
8 set loopDone@0 1
|
||||
9 jump_if_not 12(12) _index@1 = 1
|
||||
10 stmt 0 "SELECT 'start of THEN block'"
|
||||
11 jump 5
|
||||
12 stmt 0 "SELECT 'end of innerLoop'"
|
||||
13 jump 5
|
||||
14 stmt 0 "SELECT 'end of outerLoop'"
|
||||
15 set _index@1 _index@1 + 1
|
||||
16 jump 3
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Labeled FOR/integer with a labeled LOOP inside
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
outerLoop:
|
||||
FOR _index IN 1..10 DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop: LOOP
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _index = 1
|
||||
THEN
|
||||
SELECT 'start of IF/1/THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
IF _index = 2
|
||||
THEN
|
||||
SELECT 'start of IF/2/THEN block';
|
||||
ITERATE outerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END LOOP;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set loopDone@0 0
|
||||
1 set _index@1 1
|
||||
2 set [target_bound]@2 10
|
||||
3 jump_if_not 24(24) _index@1 <= [target_bound]@2
|
||||
4 stmt 0 "SELECT 'start of outerLoop'"
|
||||
5 stmt 0 "SELECT 'start of innerLoop'"
|
||||
6 jump_if_not 8(8) loopDone@0
|
||||
7 jump 18
|
||||
8 set loopDone@0 1
|
||||
9 jump_if_not 12(12) _index@1 = 1
|
||||
10 stmt 0 "SELECT 'start of IF/1/THEN block'"
|
||||
11 jump 5
|
||||
12 jump_if_not 16(16) _index@1 = 2
|
||||
13 stmt 0 "SELECT 'start of IF/2/THEN block'"
|
||||
14 set _index@1 _index@1 + 1
|
||||
15 jump 3
|
||||
16 stmt 0 "SELECT 'end of innerLoop'"
|
||||
17 jump 5
|
||||
18 stmt 0 "SELECT 'end of outerLoop'"
|
||||
19 set _index@1 _index@1 + 1
|
||||
20 jump 3
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Unlabeled FOR/integer with a labeled FOR inside
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
FOR _index_outer IN 1..10 DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop:
|
||||
FOR _index_inner IN 1..10 DO
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _index_inner = 1
|
||||
THEN
|
||||
SELECT 'start of IF/1/THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END FOR;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set loopDone@0 0
|
||||
1 set _index_outer@1 1
|
||||
2 set [target_bound]@2 10
|
||||
3 jump_if_not 24(24) _index_outer@1 <= [target_bound]@2
|
||||
4 stmt 0 "SELECT 'start of outerLoop'"
|
||||
5 set _index_inner@3 1
|
||||
6 set [target_bound]@4 10
|
||||
7 jump_if_not 19(19) _index_inner@3 <= [target_bound]@4
|
||||
8 stmt 0 "SELECT 'start of innerLoop'"
|
||||
9 jump_if_not 11(11) loopDone@0
|
||||
10 jump 19
|
||||
11 set loopDone@0 1
|
||||
12 jump_if_not 16(16) _index_inner@3 = 1
|
||||
13 stmt 0 "SELECT 'start of IF/1/THEN block'"
|
||||
14 set _index_inner@3 _index_inner@3 + 1
|
||||
15 jump 7
|
||||
16 stmt 0 "SELECT 'end of innerLoop'"
|
||||
17 set _index_inner@3 _index_inner@3 + 1
|
||||
18 jump 7
|
||||
19 stmt 0 "SELECT 'end of outerLoop'"
|
||||
20 set _index_outer@1 _index_outer@1 + 1
|
||||
21 jump 3
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Labeled FOR/integer with a labeled FOR inside
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
outerLoop:
|
||||
FOR _index_outer IN 1..10 DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop:
|
||||
FOR _index_inner IN 1..10 DO
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _index_inner = 1
|
||||
THEN
|
||||
SELECT 'start of IF/1/THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
IF _index_inner = 2
|
||||
THEN
|
||||
SELECT 'start of IF/2/THEN block';
|
||||
ITERATE outerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END FOR;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set loopDone@0 0
|
||||
1 set _index_outer@1 1
|
||||
2 set [target_bound]@2 10
|
||||
3 jump_if_not 29(29) _index_outer@1 <= [target_bound]@2
|
||||
4 stmt 0 "SELECT 'start of outerLoop'"
|
||||
5 set _index_inner@3 1
|
||||
6 set [target_bound]@4 10
|
||||
7 jump_if_not 23(23) _index_inner@3 <= [target_bound]@4
|
||||
8 stmt 0 "SELECT 'start of innerLoop'"
|
||||
9 jump_if_not 11(11) loopDone@0
|
||||
10 jump 23
|
||||
11 set loopDone@0 1
|
||||
12 jump_if_not 16(16) _index_inner@3 = 1
|
||||
13 stmt 0 "SELECT 'start of IF/1/THEN block'"
|
||||
14 set _index_inner@3 _index_inner@3 + 1
|
||||
15 jump 7
|
||||
16 jump_if_not 20(20) _index_inner@3 = 2
|
||||
17 stmt 0 "SELECT 'start of IF/2/THEN block'"
|
||||
18 set _index_outer@1 _index_outer@1 + 1
|
||||
19 jump 3
|
||||
20 stmt 0 "SELECT 'end of innerLoop'"
|
||||
21 set _index_inner@3 _index_inner@3 + 1
|
||||
22 jump 7
|
||||
23 stmt 0 "SELECT 'end of outerLoop'"
|
||||
24 set _index_outer@1 _index_outer@1 + 1
|
||||
25 jump 3
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# End of 10.4 tests
|
||||
#
|
||||
|
@ -975,3 +975,227 @@ drop function f1;
|
||||
--echo #
|
||||
--echo # End of 10.3 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Start of 10.4 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-32275 getting error 'Illegal parameter data types row and bigint for operation '+' ' when using ITERATE in a FOR..DO
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Unlabeled FOR/cursor with a nested labeled LOOP inside
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
FOR _row IN (SELECT '' AS a) DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop: LOOP
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _row.a = 'v1'
|
||||
THEN
|
||||
SELECT 'start of THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END LOOP;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Labeled FOR/cursor with a nested labeled LOOP
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
outerLoop:
|
||||
FOR _row IN (SELECT '' AS a) DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop: LOOP
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _row.a = 'v1'
|
||||
THEN
|
||||
SELECT 'start of IF/v1/THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
IF _row.a = 'v2'
|
||||
THEN
|
||||
SELECT 'start of IF/v2/THEN block';
|
||||
ITERATE outerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END LOOP;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Unlabeled FOR/integer with a labeled LOOP inside
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
FOR _index IN 1..10 DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop: LOOP
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _index = 1
|
||||
THEN
|
||||
SELECT 'start of THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END LOOP;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Labeled FOR/integer with a labeled LOOP inside
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
outerLoop:
|
||||
FOR _index IN 1..10 DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop: LOOP
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _index = 1
|
||||
THEN
|
||||
SELECT 'start of IF/1/THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
IF _index = 2
|
||||
THEN
|
||||
SELECT 'start of IF/2/THEN block';
|
||||
ITERATE outerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END LOOP;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Unlabeled FOR/integer with a labeled FOR inside
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
FOR _index_outer IN 1..10 DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop:
|
||||
FOR _index_inner IN 1..10 DO
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _index_inner = 1
|
||||
THEN
|
||||
SELECT 'start of IF/1/THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END FOR;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Labeled FOR/integer with a labeled FOR inside
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE OR REPLACE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
outerLoop:
|
||||
FOR _index_outer IN 1..10 DO
|
||||
SELECT 'start of outerLoop';
|
||||
innerLoop:
|
||||
FOR _index_inner IN 1..10 DO
|
||||
SELECT 'start of innerLoop';
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
IF _index_inner = 1
|
||||
THEN
|
||||
SELECT 'start of IF/1/THEN block';
|
||||
ITERATE innerLoop;
|
||||
END IF;
|
||||
IF _index_inner = 2
|
||||
THEN
|
||||
SELECT 'start of IF/2/THEN block';
|
||||
ITERATE outerLoop;
|
||||
END IF;
|
||||
SELECT 'end of innerLoop';
|
||||
END FOR;
|
||||
SELECT 'end of outerLoop';
|
||||
END FOR;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.4 tests
|
||||
--echo #
|
||||
|
@ -206,3 +206,33 @@ SELECT f1(3), f1(4), f1(5) FROM DUAL;
|
||||
f1(3) f1(4) f1(5)
|
||||
6 8 8
|
||||
DROP FUNCTION f1;
|
||||
#
|
||||
# End of 10.3 tests
|
||||
#
|
||||
#
|
||||
# Start of 10.4 tests
|
||||
#
|
||||
#
|
||||
# MDEV-32275 getting error 'Illegal parameter data types row and bigint for operation '+' ' when using ITERATE in a FOR..DO
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE forIterateBug()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
FOR _unused IN (SELECT '') DO
|
||||
innerLoop: LOOP
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
BEGIN
|
||||
ITERATE innerLoop;
|
||||
END;
|
||||
END LOOP;
|
||||
END FOR;
|
||||
END;
|
||||
$$
|
||||
CALL forIterateBug;
|
||||
DROP PROCEDURE forIterateBug;
|
||||
#
|
||||
# End of 10.4 tests
|
||||
#
|
||||
|
@ -210,3 +210,41 @@ END;
|
||||
DELIMITER ;/
|
||||
SELECT f1(3), f1(4), f1(5) FROM DUAL;
|
||||
DROP FUNCTION f1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.3 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Start of 10.4 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-32275 getting error 'Illegal parameter data types row and bigint for operation '+' ' when using ITERATE in a FOR..DO
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE OR REPLACE PROCEDURE forIterateBug()
|
||||
BEGIN
|
||||
DECLARE loopDone TINYINT DEFAULT FALSE;
|
||||
FOR _unused IN (SELECT '') DO
|
||||
innerLoop: LOOP
|
||||
IF loopDone THEN
|
||||
LEAVE innerLoop;
|
||||
END IF;
|
||||
SET loopDone = TRUE;
|
||||
BEGIN
|
||||
ITERATE innerLoop;
|
||||
END;
|
||||
END LOOP;
|
||||
END FOR;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL forIterateBug;
|
||||
DROP PROCEDURE forIterateBug;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.4 tests
|
||||
--echo #
|
||||
|
@ -371,7 +371,28 @@ public:
|
||||
class Lex_for_loop: public Lex_for_loop_st
|
||||
{
|
||||
public:
|
||||
Lex_for_loop() { init(); }
|
||||
/*
|
||||
The label poiting to the body start,
|
||||
either explicit or automatically generated.
|
||||
Used during generation of "ITERATE loop_label"
|
||||
to check if "loop_label" is a FOR loop label.
|
||||
- In case of a FOR loop, some additional code
|
||||
(cursor fetch or iteger increment) is generated before
|
||||
the backward jump to the beginning of the loop body.
|
||||
- In case of other loop types (WHILE, REPEAT)
|
||||
only the jump is generated.
|
||||
*/
|
||||
const sp_label *m_start_label;
|
||||
|
||||
Lex_for_loop()
|
||||
:m_start_label(NULL)
|
||||
{ Lex_for_loop_st::init(); }
|
||||
|
||||
Lex_for_loop(const Lex_for_loop_st &for_loop, const sp_label *start)
|
||||
:m_start_label(start)
|
||||
{
|
||||
Lex_for_loop_st::operator=(for_loop);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
@ -679,9 +700,9 @@ public:
|
||||
|
||||
void set_for_loop(const Lex_for_loop_st &for_loop)
|
||||
{
|
||||
m_for_loop.init(for_loop);
|
||||
m_for_loop= Lex_for_loop(for_loop, last_label());
|
||||
}
|
||||
const Lex_for_loop_st &for_loop()
|
||||
const Lex_for_loop &for_loop()
|
||||
{
|
||||
return m_for_loop;
|
||||
}
|
||||
|
@ -6362,7 +6362,7 @@ bool LEX::sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop)
|
||||
}
|
||||
|
||||
|
||||
bool LEX::sp_for_loop_intrange_finalize(THD *thd, const Lex_for_loop_st &loop)
|
||||
bool LEX::sp_for_loop_intrange_iterate(THD *thd, const Lex_for_loop_st &loop)
|
||||
{
|
||||
sphead->reset_lex(thd);
|
||||
|
||||
@ -6372,13 +6372,12 @@ bool LEX::sp_for_loop_intrange_finalize(THD *thd, const Lex_for_loop_st &loop)
|
||||
thd->lex->sphead->restore_lex(thd)))
|
||||
return true;
|
||||
|
||||
// Generate a jump to the beginning of the loop
|
||||
DBUG_ASSERT(this == thd->lex);
|
||||
return sp_while_loop_finalize(thd);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LEX::sp_for_loop_cursor_finalize(THD *thd, const Lex_for_loop_st &loop)
|
||||
bool LEX::sp_for_loop_cursor_iterate(THD *thd, const Lex_for_loop_st &loop)
|
||||
{
|
||||
sp_instr_cfetch *instr=
|
||||
new (thd->mem_root) sp_instr_cfetch(sphead->instructions(),
|
||||
@ -6386,10 +6385,10 @@ bool LEX::sp_for_loop_cursor_finalize(THD *thd, const Lex_for_loop_st &loop)
|
||||
if (unlikely(instr == NULL) || unlikely(sphead->add_instr(instr)))
|
||||
return true;
|
||||
instr->add_to_varlist(loop.m_index);
|
||||
// Generate a jump to the beginning of the loop
|
||||
return sp_while_loop_finalize(thd);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LEX::sp_for_loop_outer_block_finalize(THD *thd,
|
||||
const Lex_for_loop_st &loop)
|
||||
{
|
||||
@ -6970,13 +6969,22 @@ bool LEX::sp_iterate_statement(THD *thd, const LEX_CSTRING *label_name)
|
||||
|
||||
bool LEX::sp_continue_loop(THD *thd, sp_label *lab)
|
||||
{
|
||||
if (lab->ctx->for_loop().m_index)
|
||||
const sp_pcontext::Lex_for_loop &for_loop= lab->ctx->for_loop();
|
||||
/*
|
||||
FOR loops need some additional instructions (e.g. an integer increment or
|
||||
a cursor fetch) before the "jump to the start of the body" instruction.
|
||||
We need to check two things here:
|
||||
- If we're in a FOR loop at all.
|
||||
- If the label pointed by "lab" belongs exactly to the nearest FOR loop,
|
||||
rather than to a nested LOOP/WHILE/REPEAT inside the FOR.
|
||||
*/
|
||||
if (for_loop.m_index /* we're in some FOR loop */ &&
|
||||
for_loop.m_start_label == lab /* lab belongs to the FOR loop */)
|
||||
{
|
||||
// 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))
|
||||
// We're in a FOR loop, and "ITERATE loop_label" belongs to this FOR loop.
|
||||
if (for_loop.is_for_loop_cursor() ?
|
||||
sp_for_loop_cursor_iterate(thd, for_loop) :
|
||||
sp_for_loop_intrange_iterate(thd, for_loop))
|
||||
return true;
|
||||
}
|
||||
return sp_change_context(thd, lab->ctx, false) ||
|
||||
|
@ -4158,7 +4158,7 @@ public:
|
||||
const LEX_CSTRING *index,
|
||||
const Lex_for_loop_bounds_st &bounds);
|
||||
bool sp_for_loop_intrange_condition_test(THD *thd, const Lex_for_loop_st &loop);
|
||||
bool sp_for_loop_intrange_finalize(THD *thd, const Lex_for_loop_st &loop);
|
||||
bool sp_for_loop_intrange_iterate(THD *thd, const Lex_for_loop_st &loop);
|
||||
|
||||
/* Cursor FOR LOOP methods */
|
||||
bool sp_for_loop_cursor_declarations(THD *thd, Lex_for_loop_st *loop,
|
||||
@ -4174,7 +4174,7 @@ public:
|
||||
Lex_for_loop_bounds_st *bounds,
|
||||
sp_lex_cursor *cur);
|
||||
bool sp_for_loop_cursor_condition_test(THD *thd, const Lex_for_loop_st &loop);
|
||||
bool sp_for_loop_cursor_finalize(THD *thd, const Lex_for_loop_st &);
|
||||
bool sp_for_loop_cursor_iterate(THD *thd, const Lex_for_loop_st &);
|
||||
|
||||
/* Generic FOR LOOP methods*/
|
||||
|
||||
@ -4232,9 +4232,12 @@ public:
|
||||
*/
|
||||
bool sp_for_loop_finalize(THD *thd, const Lex_for_loop_st &loop)
|
||||
{
|
||||
return loop.is_for_loop_cursor() ?
|
||||
sp_for_loop_cursor_finalize(thd, loop) :
|
||||
sp_for_loop_intrange_finalize(thd, loop);
|
||||
if (loop.is_for_loop_cursor() ?
|
||||
sp_for_loop_cursor_iterate(thd, loop) :
|
||||
sp_for_loop_intrange_iterate(thd, loop))
|
||||
return true;
|
||||
// Generate a jump to the beginning of the loop
|
||||
return sp_while_loop_finalize(thd);
|
||||
}
|
||||
bool sp_for_loop_outer_block_finalize(THD *thd, const Lex_for_loop_st &loop);
|
||||
|
||||
|
@ -744,13 +744,10 @@ public:
|
||||
{
|
||||
m_index= 0;
|
||||
m_target_bound= 0;
|
||||
m_cursor_offset= 0;
|
||||
m_direction= 0;
|
||||
m_implicit_cursor= false;
|
||||
}
|
||||
void init(const Lex_for_loop_st &other)
|
||||
{
|
||||
*this= other;
|
||||
}
|
||||
bool is_for_loop_cursor() const { return m_target_bound == NULL; }
|
||||
bool is_for_loop_explicit_cursor() const
|
||||
{
|
||||
|
Reference in New Issue
Block a user