summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2019-12-11 15:09:17 +0400
committerAlexander Barkov <bar@mariadb.com>2019-12-12 16:25:16 +0400
commite0f9540bcc6ab1618b6fd475f02e019401c4c295 (patch)
treeda554e11e2ad9c9eea4b67efc7e221ce4609564c
parentce47e66516ec1319dacaa3880d21622af6e00ad7 (diff)
downloadmariadb-git-e0f9540bcc6ab1618b6fd475f02e019401c4c295.tar.gz
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
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-goto-debug.result236
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-goto.result79
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-goto-debug.test178
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-goto.test98
-rw-r--r--sql/sp_head.cc6
5 files changed, 594 insertions, 3 deletions
diff --git a/mysql-test/suite/compat/oracle/r/sp-goto-debug.result b/mysql-test/suite/compat/oracle/r/sp-goto-debug.result
new file mode 100644
index 00000000000..3660bfa2d84
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-goto-debug.result
@@ -0,0 +1,236 @@
+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;
diff --git a/mysql-test/suite/compat/oracle/r/sp-goto.result b/mysql-test/suite/compat/oracle/r/sp-goto.result
index 259be7a34e6..badda507ee4 100644
--- a/mysql-test/suite/compat/oracle/r/sp-goto.result
+++ b/mysql-test/suite/compat/oracle/r/sp-goto.result
@@ -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;
diff --git a/mysql-test/suite/compat/oracle/t/sp-goto-debug.test b/mysql-test/suite/compat/oracle/t/sp-goto-debug.test
new file mode 100644
index 00000000000..0ded370b17a
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-goto-debug.test
@@ -0,0 +1,178 @@
+-- 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;
diff --git a/mysql-test/suite/compat/oracle/t/sp-goto.test b/mysql-test/suite/compat/oracle/t/sp-goto.test
index df7f1132666..9c15d10b3de 100644
--- a/mysql-test/suite/compat/oracle/t/sp-goto.test
+++ b/mysql-test/suite/compat/oracle/t/sp-goto.test
@@ -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;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index ab7faf51849..360713fc452 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -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();