Commit 9c53cbdd authored by Alexander Barkov's avatar Alexander Barkov

MDEV-15941 Explicit cursor FOR loop does not close the cursor

parent b534a7b8
...@@ -1113,23 +1113,26 @@ Pos Instruction ...@@ -1113,23 +1113,26 @@ Pos Instruction
10 stmt 0 "SELECT rec1.a, rec1.b" 10 stmt 0 "SELECT rec1.a, rec1.b"
11 cfetch cur1@1 rec1@0 11 cfetch cur1@1 rec1@0
12 jump 6 12 jump 6
13 cursor_copy_struct cur0 rec0@1 13 cclose cur1@1
14 copen cur0@0 14 cursor_copy_struct cur0 rec0@1
15 cfetch cur0@0 rec0@1 15 copen cur0@0
16 jump_if_not 21(21) `cur0`%FOUND 16 cfetch cur0@0 rec0@1
17 set rec0.a@1["a"] 10 17 jump_if_not 22(22) `cur0`%FOUND
18 set rec0.b@1["b"] 'b0' 18 set rec0.a@1["a"] 10
19 cfetch cur0@0 rec0@1 19 set rec0.b@1["b"] 'b0'
20 jump 16 20 cfetch cur0@0 rec0@1
21 cursor_copy_struct cur2 rec2@2 21 jump 17
22 copen cur2@2 22 cclose cur0@0
23 cfetch cur2@2 rec2@2 23 cursor_copy_struct cur2 rec2@2
24 jump_if_not 29(29) `cur2`%FOUND 24 copen cur2@2
25 set rec2.a@2["a"] 10 25 cfetch cur2@2 rec2@2
26 set rec2.b@2["b"] 'b0' 26 jump_if_not 31(31) `cur2`%FOUND
27 cfetch cur2@2 rec2@2 27 set rec2.a@2["a"] 10
28 jump 24 28 set rec2.b@2["b"] 'b0'
29 cpop 3 29 cfetch cur2@2 rec2@2
30 jump 26
31 cclose cur2@2
32 cpop 3
DROP PROCEDURE p1; DROP PROCEDURE p1;
# Nested explicit cursor FOR loops # Nested explicit cursor FOR loops
CREATE PROCEDURE p1() CREATE PROCEDURE p1()
...@@ -1164,14 +1167,14 @@ Pos Instruction ...@@ -1164,14 +1167,14 @@ Pos Instruction
1 cursor_copy_struct cur0 rec0@0 1 cursor_copy_struct cur0 rec0@0
2 copen cur0@0 2 copen cur0@0
3 cfetch cur0@0 rec0@0 3 cfetch cur0@0 rec0@0
4 jump_if_not 29(29) `cur0`%FOUND 4 jump_if_not 31(31) `cur0`%FOUND
5 cpush cur1@1 5 cpush cur1@1
6 set rec0.a@0["a"] 11 6 set rec0.a@0["a"] 11
7 set rec0.b@0["b"] 'b0' 7 set rec0.b@0["b"] 'b0'
8 cursor_copy_struct cur1 rec1@1 8 cursor_copy_struct cur1 rec1@1
9 copen cur1@1 9 copen cur1@1
10 cfetch cur1@1 rec1@1 10 cfetch cur1@1 rec1@1
11 jump_if_not 26(26) `cur1`%FOUND 11 jump_if_not 27(27) `cur1`%FOUND
12 set rec1.a@1["a"] 11 12 set rec1.a@1["a"] 11
13 set rec1.b@1["b"] 'b1' 13 set rec1.b@1["b"] 'b1'
14 cpush cur2@2 14 cpush cur2@2
...@@ -1183,13 +1186,16 @@ Pos Instruction ...@@ -1183,13 +1186,16 @@ Pos Instruction
20 set rec2.b@2["b"] 'b2' 20 set rec2.b@2["b"] 'b2'
21 cfetch cur2@2 rec2@2 21 cfetch cur2@2 rec2@2
22 jump 18 22 jump 18
23 cpop 1 23 cclose cur2@2
24 cfetch cur1@1 rec1@1 24 cpop 1
25 jump 11 25 cfetch cur1@1 rec1@1
26 cpop 1 26 jump 11
27 cfetch cur0@0 rec0@0 27 cclose cur1@1
28 jump 4 28 cpop 1
29 cpop 1 29 cfetch cur0@0 rec0@0
30 jump 4
31 cclose cur0@0
32 cpop 1
DROP PROCEDURE p1; DROP PROCEDURE p1;
# Implicit cursor FOR loops # Implicit cursor FOR loops
CREATE PROCEDURE p1() CREATE PROCEDURE p1()
......
...@@ -611,3 +611,76 @@ a b ...@@ -611,3 +611,76 @@ a b
a b a b
2 b2 2 b2
DROP TABLE t1; DROP TABLE t1;
#
# MDEV-15941 Explicit cursor FOR loop does not close the cursor
#
BEGIN NOT ATOMIC
DECLARE v INT;
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
FETCH cur INTO v;
END;
$$
rec.a
1
ERROR 24000: Cursor is not open
BEGIN NOT ATOMIC
DECLARE v INT;
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
label:
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
FETCH cur INTO v;
END;
$$
rec.a
1
ERROR 24000: Cursor is not open
BEGIN NOT ATOMIC
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
OPEN cur;
FOR rec IN cur DO
SELECT rec.a;
END FOR;
END;
$$
ERROR 24000: Cursor is already open
BEGIN NOT ATOMIC
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
END;
$$
rec.a
1
rec.a
1
BEGIN NOT ATOMIC
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
label1:
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
label2:
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
END;
$$
rec.a
1
rec.a
1
...@@ -607,3 +607,85 @@ END; ...@@ -607,3 +607,85 @@ END;
$$ $$
DELIMITER ;$$ DELIMITER ;$$
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-15941 Explicit cursor FOR loop does not close the cursor
--echo #
DELIMITER $$;
--error ER_SP_CURSOR_NOT_OPEN
BEGIN NOT ATOMIC
DECLARE v INT;
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
FETCH cur INTO v;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_SP_CURSOR_NOT_OPEN
BEGIN NOT ATOMIC
DECLARE v INT;
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
label:
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
FETCH cur INTO v;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_SP_CURSOR_ALREADY_OPEN
BEGIN NOT ATOMIC
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
OPEN cur;
FOR rec IN cur DO
SELECT rec.a;
END FOR;
END;
$$
DELIMITER ;$$
DELIMITER $$;
BEGIN NOT ATOMIC
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
END;
$$
DELIMITER ;$$
DELIMITER $$;
BEGIN NOT ATOMIC
DECLARE cur CURSOR FOR SELECT 1 AS a FROM DUAL;
label1:
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
label2:
FOR rec IN cur
DO
SELECT rec.a;
END FOR;
END;
$$
DELIMITER ;$$
...@@ -1084,23 +1084,26 @@ Pos Instruction ...@@ -1084,23 +1084,26 @@ Pos Instruction
10 stmt 0 "SELECT rec1.a, rec1.b" 10 stmt 0 "SELECT rec1.a, rec1.b"
11 cfetch cur1@1 rec1@0 11 cfetch cur1@1 rec1@0
12 jump 6 12 jump 6
13 cursor_copy_struct cur0 rec0@1 13 cclose cur1@1
14 copen cur0@0 14 cursor_copy_struct cur0 rec0@1
15 cfetch cur0@0 rec0@1 15 copen cur0@0
16 jump_if_not 21(21) "cur0"%FOUND 16 cfetch cur0@0 rec0@1
17 set rec0.a@1["a"] 10 17 jump_if_not 22(22) "cur0"%FOUND
18 set rec0.b@1["b"] 'b0' 18 set rec0.a@1["a"] 10
19 cfetch cur0@0 rec0@1 19 set rec0.b@1["b"] 'b0'
20 jump 16 20 cfetch cur0@0 rec0@1
21 cursor_copy_struct cur2 rec2@2 21 jump 17
22 copen cur2@2 22 cclose cur0@0
23 cfetch cur2@2 rec2@2 23 cursor_copy_struct cur2 rec2@2
24 jump_if_not 29(29) "cur2"%FOUND 24 copen cur2@2
25 set rec2.a@2["a"] 10 25 cfetch cur2@2 rec2@2
26 set rec2.b@2["b"] 'b0' 26 jump_if_not 31(31) "cur2"%FOUND
27 cfetch cur2@2 rec2@2 27 set rec2.a@2["a"] 10
28 jump 24 28 set rec2.b@2["b"] 'b0'
29 cpop 3 29 cfetch cur2@2 rec2@2
30 jump 26
31 cclose cur2@2
32 cpop 3
DROP PROCEDURE p1; DROP PROCEDURE p1;
CREATE PROCEDURE p1 CREATE PROCEDURE p1
AS AS
...@@ -1137,14 +1140,14 @@ Pos Instruction ...@@ -1137,14 +1140,14 @@ Pos Instruction
1 cursor_copy_struct cur0 rec0@0 1 cursor_copy_struct cur0 rec0@0
2 copen cur0@0 2 copen cur0@0
3 cfetch cur0@0 rec0@0 3 cfetch cur0@0 rec0@0
4 jump_if_not 29(29) "cur0"%FOUND 4 jump_if_not 31(31) "cur0"%FOUND
5 cpush cur1@1 5 cpush cur1@1
6 set rec0.a@0["a"] 11 6 set rec0.a@0["a"] 11
7 set rec0.b@0["b"] 'b0' 7 set rec0.b@0["b"] 'b0'
8 cursor_copy_struct cur1 rec1@1 8 cursor_copy_struct cur1 rec1@1
9 copen cur1@1 9 copen cur1@1
10 cfetch cur1@1 rec1@1 10 cfetch cur1@1 rec1@1
11 jump_if_not 26(26) "cur1"%FOUND 11 jump_if_not 27(27) "cur1"%FOUND
12 set rec1.a@1["a"] 11 12 set rec1.a@1["a"] 11
13 set rec1.b@1["b"] 'b1' 13 set rec1.b@1["b"] 'b1'
14 cpush cur2@2 14 cpush cur2@2
...@@ -1156,13 +1159,16 @@ Pos Instruction ...@@ -1156,13 +1159,16 @@ Pos Instruction
20 set rec2.b@2["b"] 'b2' 20 set rec2.b@2["b"] 'b2'
21 cfetch cur2@2 rec2@2 21 cfetch cur2@2 rec2@2
22 jump 18 22 jump 18
23 cpop 1 23 cclose cur2@2
24 cfetch cur1@1 rec1@1 24 cpop 1
25 jump 11 25 cfetch cur1@1 rec1@1
26 cpop 1 26 jump 11
27 cfetch cur0@0 rec0@0 27 cclose cur1@1
28 jump 4 28 cpop 1
29 cpop 1 29 cfetch cur0@0 rec0@0
30 jump 4
31 cclose cur0@0
32 cpop 1
DROP PROCEDURE p1; DROP PROCEDURE p1;
# #
# MDEV-12098 sql_mode=ORACLE: Implicit cursor FOR loop # MDEV-12098 sql_mode=ORACLE: Implicit cursor FOR loop
......
...@@ -1331,6 +1331,93 @@ rec2.a rec2.b ...@@ -1331,6 +1331,93 @@ rec2.a rec2.b
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-15941 Explicit cursor FOR loop does not close the cursor
#
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
v INT;
BEGIN
FOR rec IN cur
LOOP
NULL;
END LOOP;
FETCH cur INTO v;
END;
$$
ERROR 24000: Cursor is not open
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
v INT;
BEGIN
<<label>>
FOR rec IN cur
LOOP
NULL;
END LOOP label;
FETCH cur INTO v;
END;
$$
ERROR 24000: Cursor is not open
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
BEGIN
OPEN cur;
FOR rec IN cur
LOOP
NULL;
END LOOP;
END;
$$
ERROR 24000: Cursor is already open
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
BEGIN
FOR rec IN cur
LOOP
SELECT rec.a;
END LOOP;
SELECT cur%ISOPEN;
FOR rec IN cur
LOOP
SELECT rec.a;
END LOOP;
SELECT cur%ISOPEN;
END;
$$
rec.a
1
cur%ISOPEN
0
rec.a
1
cur%ISOPEN
0
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
BEGIN
<<label1>>
FOR rec IN cur
LOOP
SELECT rec.a;
END LOOP label1;
SELECT cur%ISOPEN;
<<label2>>
FOR rec IN cur
LOOP
SELECT rec.a;
END LOOP;
SELECT cur%ISOPEN;
END;
$$
rec.a
1
cur%ISOPEN
0
rec.a
1
cur%ISOPEN
0
#
# MDEV-14139 Anchored data types for variables # MDEV-14139 Anchored data types for variables
# #
DECLARE DECLARE
......
...@@ -1424,6 +1424,98 @@ DROP PROCEDURE p1; ...@@ -1424,6 +1424,98 @@ DROP PROCEDURE p1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-15941 Explicit cursor FOR loop does not close the cursor
--echo #
DELIMITER $$;
--error ER_SP_CURSOR_NOT_OPEN
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
v INT;
BEGIN
FOR rec IN cur
LOOP
NULL;
END LOOP;
FETCH cur INTO v;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_SP_CURSOR_NOT_OPEN
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
v INT;
BEGIN
<<label>>
FOR rec IN cur
LOOP
NULL;
END LOOP label;
FETCH cur INTO v;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_SP_CURSOR_ALREADY_OPEN
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
BEGIN
OPEN cur;
FOR rec IN cur
LOOP
NULL;
END LOOP;
END;
$$
DELIMITER ;$$
DELIMITER $$;
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
BEGIN
FOR rec IN cur
LOOP
SELECT rec.a;
END LOOP;
SELECT cur%ISOPEN;
FOR rec IN cur
LOOP
SELECT rec.a;
END LOOP;
SELECT cur%ISOPEN;
END;
$$
DELIMITER ;$$
DELIMITER $$;
DECLARE
CURSOR cur IS SELECT 1 AS a FROM DUAL;
BEGIN
<<label1>>
FOR rec IN cur
LOOP
SELECT rec.a;
END LOOP label1;
SELECT cur%ISOPEN;
<<label2>>
FOR rec IN cur
LOOP
SELECT rec.a;
END LOOP;
SELECT cur%ISOPEN;
END;
$$
DELIMITER ;$$
--echo # --echo #
--echo # MDEV-14139 Anchored data types for variables --echo # MDEV-14139 Anchored data types for variables
--echo # --echo #
......
...@@ -5891,6 +5891,26 @@ bool LEX::sp_for_loop_cursor_finalize(THD *thd, const Lex_for_loop_st &loop) ...@@ -5891,6 +5891,26 @@ bool LEX::sp_for_loop_cursor_finalize(THD *thd, const Lex_for_loop_st &loop)
return sp_while_loop_finalize(thd); return sp_while_loop_finalize(thd);
} }
bool LEX::sp_for_loop_outer_block_finalize(THD *thd,
const Lex_for_loop_st &loop)
{
Lex_spblock tmp;
tmp.curs= MY_TEST(loop.m_implicit_cursor);
if (unlikely(sp_block_finalize(thd, tmp))) // The outer DECLARE..BEGIN..END
return true;
if (!loop.is_for_loop_explicit_cursor())
return false;
/*
Explicit cursor FOR loop must close the cursor automatically.
Note, implicit cursor FOR loop does not need to close the cursor,
it's closed by sp_instr_cpop.
*/
sp_instr_cclose *ic= new (thd->mem_root)
sp_instr_cclose(sphead->instructions(), spcont,
loop.m_cursor_offset);
return ic == NULL || sphead->add_instr(ic);
}
/***************************************************************************/ /***************************************************************************/
bool LEX::sp_declare_cursor(THD *thd, const LEX_CSTRING *name, bool LEX::sp_declare_cursor(THD *thd, const LEX_CSTRING *name,
......
...@@ -3802,6 +3802,7 @@ struct LEX: public Query_tables_list ...@@ -3802,6 +3802,7 @@ struct LEX: public Query_tables_list
sp_for_loop_cursor_finalize(thd, loop) : sp_for_loop_cursor_finalize(thd, loop) :
sp_for_loop_intrange_finalize(thd, loop); sp_for_loop_intrange_finalize(thd, loop);
} }
bool sp_for_loop_outer_block_finalize(THD *thd, const Lex_for_loop_st &loop);
/* End of FOR LOOP methods */ /* End of FOR LOOP methods */
bool add_signal_statement(THD *thd, const class sp_condition_value *value); bool add_signal_statement(THD *thd, const class sp_condition_value *value);
......
...@@ -4729,9 +4729,7 @@ sp_labeled_control: ...@@ -4729,9 +4729,7 @@ sp_labeled_control:
} }
pop_sp_loop_label // The inner WHILE block pop_sp_loop_label // The inner WHILE block
{ {
Lex_spblock tmp; if (unlikely(Lex->sp_for_loop_outer_block_finalize(thd, $4)))
tmp.curs= MY_TEST($4.m_implicit_cursor);
if (unlikely(Lex->sp_block_finalize(thd, tmp))) // The outer DECLARE..BEGIN..END
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| sp_label REPEAT_SYM | sp_label REPEAT_SYM
...@@ -4781,12 +4779,10 @@ sp_unlabeled_control: ...@@ -4781,12 +4779,10 @@ sp_unlabeled_control:
sp_proc_stmts1 sp_proc_stmts1
END FOR_SYM END FOR_SYM
{ {
Lex_spblock tmp;
tmp.curs= MY_TEST($3.m_implicit_cursor);
if (unlikely(Lex->sp_for_loop_finalize(thd, $3))) if (unlikely(Lex->sp_for_loop_finalize(thd, $3)))
MYSQL_YYABORT; MYSQL_YYABORT;
Lex->sp_pop_loop_empty_label(thd); // The inner WHILE block Lex->sp_pop_loop_empty_label(thd); // The inner WHILE block
if (unlikely(Lex->sp_block_finalize(thd, tmp))) // The outer DECLARE..BEGIN..END if (unlikely(Lex->sp_for_loop_outer_block_finalize(thd, $3)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| REPEAT_SYM | REPEAT_SYM
......
...@@ -4676,9 +4676,7 @@ sp_labeled_control: ...@@ -4676,9 +4676,7 @@ sp_labeled_control:
} }
pop_sp_loop_label // The inner WHILE block pop_sp_loop_label // The inner WHILE block
{ {
Lex_spblock tmp; if (unlikely(Lex->sp_for_loop_outer_block_finalize(thd, $4)))
tmp.curs= MY_TEST($4.m_implicit_cursor);
if (unlikely(Lex->sp_block_finalize(thd, tmp))) // The outer DECLARE..BEGIN..END
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| labels_declaration_oracle REPEAT_SYM | labels_declaration_oracle REPEAT_SYM
...@@ -4728,12 +4726,10 @@ sp_unlabeled_control: ...@@ -4728,12 +4726,10 @@ sp_unlabeled_control:
sp_proc_stmts1 sp_proc_stmts1
END LOOP_SYM END LOOP_SYM
{ {
Lex_spblock tmp;
tmp.curs= MY_TEST($3.m_implicit_cursor);
if (unlikely(Lex->sp_for_loop_finalize(thd, $3))) if (unlikely(Lex->sp_for_loop_finalize(thd, $3)))
MYSQL_YYABORT; MYSQL_YYABORT;
Lex->sp_pop_loop_empty_label(thd); // The inner WHILE block Lex->sp_pop_loop_empty_label(thd); // The inner WHILE block
if (unlikely(Lex->sp_block_finalize(thd, tmp))) // The outer DECLARE..BEGIN..END if (unlikely(Lex->sp_for_loop_outer_block_finalize(thd, $3)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| REPEAT_SYM | REPEAT_SYM
......
...@@ -720,6 +720,10 @@ struct Lex_for_loop_st ...@@ -720,6 +720,10 @@ struct Lex_for_loop_st
*this= other; *this= other;
} }
bool is_for_loop_cursor() const { return m_upper_bound == NULL; } bool is_for_loop_cursor() const { return m_upper_bound == NULL; }
bool is_for_loop_explicit_cursor() const
{
return is_for_loop_cursor() && !m_implicit_cursor;
}
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment