From 276bd123b7b9cf516c8ddd7a28952f6e1275aa8c Mon Sep 17 00:00:00 2001
From: unknown <konstantin@mysql.com>
Date: Fri, 19 Aug 2005 17:03:21 +0400
Subject: [PATCH] A fix and a test case for "Bug #12168 'DECLARE CONTINUE
 HANDLER FOR NOT FOUND ...' in conditional handled incorrectly".

Whenever we remove an instruction during optimization, we need to
adjust instruction numbers (ip - instruction pointer) stored in all
instructions. In addition to that, sp_instr_hpush_jump, which
corresponds to DECLARE CONTINUE HANDLER needs adjustment for m_handler,
which holds the number of instruction with the continue handler.
In the bug report, a wrong ip stored in m_handler was pointing at
FETCH, which resulted in an error message and abnormal SP termination.
The fix is to just remove m_handler member from sp_instr_hpush_jump,
as it's always points to the instruction next to the DECLARE
statement itself (m_ip+1).


mysql-test/r/sp.result:
  Test results fixed (Bug#12168)
mysql-test/t/sp.test:
  A test case for Bug#12168 "'DECLARE CONTINUE HANDLER FOR NOT
  FOUND ...' in conditional handled incorrectly"
sql/sp_head.cc:
  Remove m_handler (the number of continue handler instruction)
  as it always equal to m_ip+1
sql/sp_head.h:
  Remove m_handler (the number of continue handler instruction)
  as it always equal to m_ip+1
---
 mysql-test/r/sp.result | 66 ++++++++++++++++++++++++++++++++++++++++++
 mysql-test/t/sp.test   | 66 ++++++++++++++++++++++++++++++++++++++++++
 sql/sp_head.cc         |  4 +--
 sql/sp_head.h          |  2 --
 4 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 78bf22d0b2..d1d4103547 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -3100,4 +3100,70 @@ end|
 call p_bug11247(10)|
 drop function f_bug11247|
 drop procedure p_bug11247|
+drop procedure if exists bug12168|
+drop table if exists t1, t2|
+create table t1 (a int)|
+insert into t1 values (1),(2),(3),(4)|
+create table t2 (a int)|
+create procedure bug12168(arg1 char(1))
+begin
+declare b, c integer;
+if arg1 = 'a' then
+begin
+declare c1 cursor for select a from t1 where a % 2;
+declare continue handler for not found set b = 1;
+set b = 0;
+open c1;
+c1_repeat: repeat
+fetch c1 into c;
+if (b = 1) then
+leave c1_repeat;
+end if;
+insert into t2 values (c);
+until b = 1
+end repeat;
+end;
+end if;
+if arg1 = 'b' then
+begin
+declare c2 cursor for select a from t1 where not a % 2;
+declare continue handler for not found set b = 1;
+set b = 0;
+open c2;
+c2_repeat: repeat
+fetch c2 into c;
+if (b = 1) then
+leave c2_repeat;
+end if;
+insert into t2 values (c);
+until b = 1
+end repeat;
+end;
+end if;
+end|
+call bug12168('a')|
+select * from t2|
+a
+1
+3
+truncate t2|
+call bug12168('b')|
+select * from t2|
+a
+2
+4
+truncate t2|
+call bug12168('a')|
+select * from t2|
+a
+1
+3
+truncate t2|
+call bug12168('b')|
+select * from t2|
+a
+2
+4
+truncate t2|
+drop procedure if exists bug12168|
 drop table t1,t2;
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index cde5d3922a..f3e7c3e07a 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -3928,6 +3928,72 @@ end|
 call p_bug11247(10)|
 drop function f_bug11247|
 drop procedure p_bug11247|
+#
+# BUG#12168: "'DECLARE CONTINUE HANDLER FOR NOT FOUND ...' in conditional
+# handled incorrectly"
+#
+--disable_warnings
+drop procedure if exists bug12168|
+drop table if exists t1, t2|
+--enable_warnings
+
+create table t1 (a int)|
+insert into t1 values (1),(2),(3),(4)|
+
+create table t2 (a int)|
+
+create procedure bug12168(arg1 char(1))
+begin
+  declare b, c integer;
+  if arg1 = 'a' then
+    begin
+      declare c1 cursor for select a from t1 where a % 2;
+      declare continue handler for not found set b = 1;
+      set b = 0;
+      open c1;
+      c1_repeat: repeat
+        fetch c1 into c;
+        if (b = 1) then
+          leave c1_repeat;
+        end if;
+
+        insert into t2 values (c);
+        until b = 1
+      end repeat;
+    end;
+  end if;
+  if arg1 = 'b' then
+    begin
+      declare c2 cursor for select a from t1 where not a % 2;
+      declare continue handler for not found set b = 1;
+      set b = 0;
+      open c2;
+      c2_repeat: repeat
+        fetch c2 into c;
+        if (b = 1) then
+          leave c2_repeat;
+        end if;
+
+        insert into t2 values (c);
+        until b = 1
+      end repeat;
+    end;
+  end if;
+end|
+
+call bug12168('a')|
+select * from t2|
+truncate t2|
+call bug12168('b')|
+select * from t2|
+truncate t2|
+call bug12168('a')|
+select * from t2|
+truncate t2|
+call bug12168('b')|
+select * from t2|
+truncate t2|
+drop procedure if exists bug12168|
 
 #
 # BUG#NNNN: New bug synopsis
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 26d76804fc..f119ef1ec2 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1986,7 +1986,7 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
   sp_cond_type_t *p;
 
   while ((p= li++))
-    thd->spcont->push_handler(p, m_handler, m_type, m_frame);
+    thd->spcont->push_handler(p, m_ip+1, m_type, m_frame);
 
   *nextp= m_dest;
   DBUG_RETURN(0);
@@ -2003,7 +2003,7 @@ sp_instr_hpush_jump::print(String *str)
   str->append(" f=");
   str->qs_append(m_frame);
   str->append(" h=");
-  str->qs_append(m_handler);
+  str->qs_append(m_ip+1);
 }
 
 uint
diff --git a/sql/sp_head.h b/sql/sp_head.h
index e15b68be15..8ae7834eb2 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -714,7 +714,6 @@ public:
   sp_instr_hpush_jump(uint ip, sp_pcontext *ctx, int htype, uint fp)
     : sp_instr_jump(ip, ctx), m_type(htype), m_frame(fp)
   {
-    m_handler= ip+1;
     m_cond.empty();
   }
 
@@ -743,7 +742,6 @@ private:
 
   int m_type;			// Handler type
   uint m_frame;
-  uint m_handler;		// Location of handler
   List<struct sp_cond_type> m_cond;
 
 }; // class sp_instr_hpush_jump : public sp_instr_jump
-- 
2.30.9