summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/sp.result56
-rw-r--r--mysql-test/t/sp.test54
-rw-r--r--sql/sp_pcontext.cc16
-rw-r--r--sql/sp_pcontext.h10
-rw-r--r--sql/sql_yacc.yy8
5 files changed, 133 insertions, 11 deletions
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index bec2f049bc4..e4168f67125 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -4519,4 +4519,60 @@ Handler
Inner
drop procedure bug15011|
drop table t3|
+drop table if exists t3|
+drop procedure if exists bug16887|
+create table t3 ( c varchar(1) )|
+insert into t3 values
+(' '),('.'),(';'),(','),('-'),('_'),('('),(')'),('/'),('\\')|
+create procedure bug16887()
+begin
+declare i int default 10;
+again:
+while i > 0 do
+begin
+declare breakchar varchar(1);
+declare done int default 0;
+declare t3_cursor cursor for select c from t3;
+declare continue handler for not found set done = 1;
+set i = i - 1;
+select i;
+if i = 3 then
+iterate again;
+end if;
+open t3_cursor;
+loop
+fetch t3_cursor into breakchar;
+if done = 1 then
+begin
+close t3_cursor;
+iterate again;
+end;
+end if;
+end loop;
+end;
+end while;
+end|
+call bug16887()|
+i
+9
+i
+8
+i
+7
+i
+6
+i
+5
+i
+4
+i
+3
+i
+2
+i
+1
+i
+0
+drop table t3|
+drop procedure bug16887|
drop table t1,t2;
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 53c15ffd05b..b86c39e3109 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -5312,6 +5312,60 @@ drop table t3|
#
+# BUG#16887: Cursor causes server segfault
+#
+--disable_warnings
+drop table if exists t3|
+drop procedure if exists bug16887|
+--enable_warnings
+
+create table t3 ( c varchar(1) )|
+
+insert into t3 values
+ (' '),('.'),(';'),(','),('-'),('_'),('('),(')'),('/'),('\\')|
+
+create procedure bug16887()
+begin
+ declare i int default 10;
+
+ again:
+ while i > 0 do
+ begin
+ declare breakchar varchar(1);
+ declare done int default 0;
+ declare t3_cursor cursor for select c from t3;
+ declare continue handler for not found set done = 1;
+
+ set i = i - 1;
+ select i;
+
+ if i = 3 then
+ iterate again;
+ end if;
+
+ open t3_cursor;
+
+ loop
+ fetch t3_cursor into breakchar;
+
+ if done = 1 then
+ begin
+ close t3_cursor;
+ iterate again;
+ end;
+ end if;
+ end loop;
+ end;
+ end while;
+end|
+
+call bug16887()|
+
+drop table t3|
+drop procedure bug16887|
+
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index a8bd8cd2aa0..f69053a7c88 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -122,30 +122,38 @@ sp_pcontext::pop_context()
}
uint
-sp_pcontext::diff_handlers(sp_pcontext *ctx)
+sp_pcontext::diff_handlers(sp_pcontext *ctx, bool exclusive)
{
uint n= 0;
sp_pcontext *pctx= this;
+ sp_pcontext *last_ctx= NULL;
while (pctx && pctx != ctx)
{
n+= pctx->m_handlers;
+ last_ctx= pctx;
pctx= pctx->parent_context();
}
if (pctx)
- return n;
+ return (exclusive && last_ctx ? n - last_ctx->m_handlers : n);
return 0; // Didn't find ctx
}
uint
-sp_pcontext::diff_cursors(sp_pcontext *ctx)
+sp_pcontext::diff_cursors(sp_pcontext *ctx, bool exclusive)
{
+ uint n= 0;
sp_pcontext *pctx= this;
+ sp_pcontext *last_ctx= NULL;
while (pctx && pctx != ctx)
+ {
+ n+= pctx->m_cursor.elements;
+ last_ctx= pctx;
pctx= pctx->parent_context();
+ }
if (pctx)
- return ctx->current_cursors() - pctx->current_cursors();
+ return (exclusive && last_ctx ? n - last_ctx->m_cursor.elements : n);
return 0; // Didn't find ctx
}
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index d1cd7b964c2..872c7c1d505 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -119,11 +119,15 @@ class sp_pcontext : public Sql_alloc
return m_parent;
}
+ /*
+ Number of handlers/cursors to pop between this context and 'ctx'.
+ If 'exclusive' is true, don't count the last block we are leaving;
+ this is used for LEAVE where we will jump to the cpop/hpop instructions.
+ */
uint
- diff_handlers(sp_pcontext *ctx);
-
+ diff_handlers(sp_pcontext *ctx, bool exclusive);
uint
- diff_cursors(sp_pcontext *ctx);
+ diff_cursors(sp_pcontext *ctx, bool exclusive);
//
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 4f4ec5e92de..b68b822b1ac 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2079,10 +2079,10 @@ sp_proc_stmt:
uint ip= sp->instructions();
uint n;
- n= ctx->diff_handlers(lab->ctx);
+ n= ctx->diff_handlers(lab->ctx, TRUE); /* Exclusive the dest. */
if (n)
sp->add_instr(new sp_instr_hpop(ip++, ctx, n));
- n= ctx->diff_cursors(lab->ctx);
+ n= ctx->diff_cursors(lab->ctx, TRUE); /* Exclusive the dest. */
if (n)
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
i= new sp_instr_jump(ip, ctx);
@@ -2108,10 +2108,10 @@ sp_proc_stmt:
uint ip= sp->instructions();
uint n;
- n= ctx->diff_handlers(lab->ctx);
+ n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */
if (n)
sp->add_instr(new sp_instr_hpop(ip++, ctx, n));
- n= ctx->diff_cursors(lab->ctx);
+ n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */
if (n)
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */