Commit e0f9540b authored by Alexander Barkov's avatar Alexander Barkov

MDEV-20667 Server crash on pop_cursor

When backpatching a forward GOTO label, the old code erroneously
used CURSOR/HANDLER difference between context frames "c" and "a" to tune
a cpop/hpop command. So the cpop/hpop command later tried to pop
all cursors/handlers declared between "a" and "c", but those between
"b" and "c" were not cpushed/hpoped yet during the execution of "GOTO x".

Fixing the code to use the difference between frames "b" and "a" only.

BEGIN     -- a
 ...
GOTO x;   -- b
 ...
<<x>>     -- c
 ...
END       -- d
parent ce47e665
SET sql_mode=ORACLE;
#
# MDEV-20667 Server crash on pop_cursor
#
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<< iac_err >>
RETURN;
END//
SHOW PROCEDURE CODE p1;
Pos Instruction
0 jump_if_not 5(5) 1 = 2
1 cpush cur1@0
2 jump 3
3 cpop 1
4 jump 7
5 jump_if_not 7(7) 1 = 1
6 jump 7
7 preturn
DROP PROCEDURE p1;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<< iac_err >>
RETURN ;
END//
SHOW PROCEDURE CODE p1;
Pos Instruction
0 jump_if_not 5(5) 1 = 2
1 cpush cur1@0
2 jump 3
3 cpop 1
4 jump 7
5 jump_if_not 7(7) 1 = 1
6 jump 7
7 preturn
DROP PROCEDURE p1;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
GOTO iac_err;
<< iac_err >>
RETURN ;
END//
SHOW PROCEDURE CODE p1;
Pos Instruction
0 jump_if_not 5(5) 1 = 2
1 cpush cur1@0
2 jump 3
3 cpop 1
4 jump 5
5 preturn
DROP PROCEDURE p1;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=1 THEN
DECLARE
CURSOR cur2 IS SELECT 'cur2' FROM DUAL;
BEGIN
SELECT 'cur2';
IF 1=1 THEN
DECLARE
CURSOR cur3 IS SELECT 'cur3' FROM DUAL;
BEGIN
SELECT 'cur3';
IF 1=1 THEN
DECLARE
CURSOR cur4 IS SELECT 'cur4' FROM DUAL;
BEGIN
SELECT 'cur4';
GOTO ret;
END;
END IF;
GOTO ret;
END;
END IF;
GOTO ret;
END;
END IF;
<<ret>>
RETURN;
END;
//
SHOW PROCEDURE CODE p1;
Pos Instruction
0 jump_if_not 15(15) 1 = 1
1 cpush cur2@0
2 stmt 0 "SELECT 'cur2'"
3 jump_if_not 13(13) 1 = 1
4 cpush cur3@1
5 stmt 0 "SELECT 'cur3'"
6 jump_if_not 11(11) 1 = 1
7 cpush cur4@2
8 stmt 0 "SELECT 'cur4'"
9 cpop 3
10 jump 15
11 cpop 2
12 jump 15
13 cpop 1
14 jump 15
15 preturn
DROP PROCEDURE p1;
CREATE PROCEDURE p1(lab VARCHAR(32)) IS
BEGIN
IF 1=1 THEN
DECLARE
CURSOR cur2 IS SELECT 'cur2' FROM DUAL;
BEGIN
IF 1=1 THEN
DECLARE
CURSOR cur3 IS SELECT 'cur3' FROM DUAL;
BEGIN
IF 1=1 THEN
DECLARE
CURSOR cur4 IS SELECT 'cur4' FROM DUAL;
BEGIN
IF lab = 'cur4' THEN
SELECT 'goto from cur4' AS comment;
GOTO ret;
END IF;
END;
END IF;
IF lab = 'cur3' THEN
SELECT 'goto from cur3' AS comment;
GOTO ret;
END IF;
END;
END IF;
IF lab = 'cur2' THEN
SELECT 'goto from cur2' AS comment;
GOTO ret;
END IF;
END;
END IF;
<<ret>>
RETURN;
END;
//
SHOW PROCEDURE CODE p1;
Pos Instruction
0 jump_if_not 21(21) 1 = 1
1 cpush cur2@0
2 jump_if_not 16(16) 1 = 1
3 cpush cur3@1
4 jump_if_not 11(11) 1 = 1
5 cpush cur4@2
6 jump_if_not 10(10) lab@0 = 'cur4'
7 stmt 0 "SELECT 'goto from cur4' AS comment"
8 cpop 3
9 jump 21
10 cpop 1
11 jump_if_not 15(15) lab@0 = 'cur3'
12 stmt 0 "SELECT 'goto from cur3' AS comment"
13 cpop 2
14 jump 21
15 cpop 1
16 jump_if_not 20(20) lab@0 = 'cur2'
17 stmt 0 "SELECT 'goto from cur2' AS comment"
18 cpop 1
19 jump 21
20 cpop 1
21 preturn
CALL p1('');
CALL p1('cur2');
comment
goto from cur2
CALL p1('cur3');
comment
goto from cur3
CALL p1('cur4');
comment
goto from cur4
DROP PROCEDURE p1;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<<iac_err >>
RETURN;
END//
SHOW PROCEDURE CODE p1;
Pos Instruction
0 jump_if_not 9(9) 1 = 2
1 hpush_jump 4 0 CONTINUE
2 stmt 31 "SET @x2 = 1"
3 hreturn 0
4 hpop 1
5 jump 11
6 jump 11
7 hpop 1
8 jump 9
9 jump_if_not 11(11) 1 = 1
10 jump 11
11 preturn
DROP PROCEDURE p1;
......@@ -832,3 +832,82 @@ a
15
DROP TRIGGER trg1;
DROP TABLE t1;
#
# MDEV-20667 Server crash on pop_cursor
#
CREATE TABLE t1 (a VARCHAR(6));
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<< iac_err >>
RETURN;
END//
CALL p1();
DROP PROCEDURE p1;
DROP TABLE t1;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<< iac_err >>
RETURN ;
END//
CALL p1;
DROP PROCEDURE p1;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
GOTO iac_err;
<< iac_err >>
RETURN ;
END//
CALL p1;
DROP PROCEDURE p1;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<<iac_err >>
RETURN;
END//
CALL p1;
DROP PROCEDURE p1;
-- source include/have_debug.inc
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-20667 Server crash on pop_cursor
--echo #
DELIMITER //;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<< iac_err >>
RETURN;
END//
DELIMITER ;//
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
DELIMITER //;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<< iac_err >>
RETURN ;
END//
DELIMITER ;//
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
DELIMITER //;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
GOTO iac_err;
<< iac_err >>
RETURN ;
END//
DELIMITER ;//
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
DELIMITER //;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=1 THEN
DECLARE
CURSOR cur2 IS SELECT 'cur2' FROM DUAL;
BEGIN
SELECT 'cur2';
IF 1=1 THEN
DECLARE
CURSOR cur3 IS SELECT 'cur3' FROM DUAL;
BEGIN
SELECT 'cur3';
IF 1=1 THEN
DECLARE
CURSOR cur4 IS SELECT 'cur4' FROM DUAL;
BEGIN
SELECT 'cur4';
GOTO ret;
END;
END IF;
GOTO ret;
END;
END IF;
GOTO ret;
END;
END IF;
<<ret>>
RETURN;
END;
//
DELIMITER ;//
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
DELIMITER //;
CREATE PROCEDURE p1(lab VARCHAR(32)) IS
BEGIN
IF 1=1 THEN
DECLARE
CURSOR cur2 IS SELECT 'cur2' FROM DUAL;
BEGIN
IF 1=1 THEN
DECLARE
CURSOR cur3 IS SELECT 'cur3' FROM DUAL;
BEGIN
IF 1=1 THEN
DECLARE
CURSOR cur4 IS SELECT 'cur4' FROM DUAL;
BEGIN
IF lab = 'cur4' THEN
SELECT 'goto from cur4' AS comment;
GOTO ret;
END IF;
END;
END IF;
IF lab = 'cur3' THEN
SELECT 'goto from cur3' AS comment;
GOTO ret;
END IF;
END;
END IF;
IF lab = 'cur2' THEN
SELECT 'goto from cur2' AS comment;
GOTO ret;
END IF;
END;
END IF;
<<ret>>
RETURN;
END;
//
DELIMITER ;//
SHOW PROCEDURE CODE p1;
CALL p1('');
CALL p1('cur2');
CALL p1('cur3');
CALL p1('cur4');
DROP PROCEDURE p1;
DELIMITER //;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<<iac_err >>
RETURN;
END//
DELIMITER ;//
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
......@@ -869,4 +869,100 @@ insert into t1 values (1);
insert into t1 values (null);
SELECT * FROM t1;
DROP TRIGGER trg1;
DROP TABLE t1;
\ No newline at end of file
DROP TABLE t1;
--echo #
--echo # MDEV-20667 Server crash on pop_cursor
--echo #
CREATE TABLE t1 (a VARCHAR(6));
DELIMITER //;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<< iac_err >>
RETURN;
END//
DELIMITER ;//
CALL p1();
DROP PROCEDURE p1;
DROP TABLE t1;
DELIMITER //;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<< iac_err >>
RETURN ;
END//
DELIMITER ;//
CALL p1;
DROP PROCEDURE p1;
DELIMITER //;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CURSOR cur1 IS SELECT a FROM t1 ;
BEGIN
GOTO iac_err;
END;
END;
END IF;
GOTO iac_err;
<< iac_err >>
RETURN ;
END//
DELIMITER ;//
CALL p1;
DROP PROCEDURE p1;
DELIMITER //;
CREATE PROCEDURE p1() IS
BEGIN
IF 1=2 THEN
BEGIN
DECLARE
CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
BEGIN
GOTO iac_err;
END;
END;
END IF;
IF 1=1 THEN
GOTO iac_err;
END IF;
<<iac_err >>
RETURN;
END//
DELIMITER ;//
CALL p1;
DROP PROCEDURE p1;
......@@ -2571,7 +2571,7 @@ sp_head::backpatch_goto(THD *thd, sp_label *lab,sp_label *lab_begin_block)
}
if (bp->instr_type == CPOP)
{
uint n= lab->ctx->diff_cursors(lab_begin_block->ctx, true);
uint n= bp->instr->m_ctx->diff_cursors(lab_begin_block->ctx, true);
if (n == 0)
{
// Remove cpop instr
......@@ -2588,7 +2588,7 @@ sp_head::backpatch_goto(THD *thd, sp_label *lab,sp_label *lab_begin_block)
}
if (bp->instr_type == HPOP)
{
uint n= lab->ctx->diff_handlers(lab_begin_block->ctx, true);
uint n= bp->instr->m_ctx->diff_handlers(lab_begin_block->ctx, true);
if (n == 0)
{
// Remove hpop instr
......@@ -3082,6 +3082,8 @@ void sp_head::optimize()
sp_instr *i;
uint src, dst;
DBUG_EXECUTE_IF("sp_head_optimize_disable", return; );
opt_mark();
bp.empty();
......
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