summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <pem@mysql.com>2006-02-15 12:11:29 +0100
committerunknown <pem@mysql.com>2006-02-15 12:11:29 +0100
commit7f02b0a01b64070562d5d768b5709127714732a4 (patch)
tree97f622b83534adc7d26cca57df1a1978fb650e11 /sql
parent3f4c176caeb5e1f9b2d56ab7536d0931bcafe76c (diff)
downloadmariadb-git-7f02b0a01b64070562d5d768b5709127714732a4.tar.gz
Fixed BUG#16887: Cursor causes server segfault
The problem was a code generation bug: cpop instructions were not generated when using ITERATE back to an outer block from a context with a declared cursor; this would make it push a new cursor without popping in-between, eventually overrunning the cursor stack with a crash as the result. Fixed the calculation of how many cursors to pop (in sp_pcontext.cc: diff_cursors()), and also corrected diff_cursors() and diff_handlers() to when doing a "leave"; don't include the last context we're leaving (we are then jumping to the appropriate pop instructions). mysql-test/r/sp.result: Updated result for new test case (BUG#16887) mysql-test/t/sp.test: New test case for BUG#16887 sql/sp_pcontext.cc: Added new parameter to sp_pcontext::diff_handlers() and diff_cursors(): They can either include (for iterate jumps) or exclude (for leave jumps) the outer context. Fixed bug in diff_cursors(); it was just plain wrong and would return zero in some situations when it shouldn't. sql/sp_pcontext.h: Added new parameter to sp_pcontext::diff_handlers() and diff_cursors(): They can either include (for iterate jumps) or exclude (for leave jumps) the outer context. sql/sql_yacc.yy: Added parameter to diff_handlers/diff_cursors depending on if it's an iterate or leave jump. For "leave", we don't have to include the last context we're leaving since we will jump to the appropriate pop instructions.
Diffstat (limited to 'sql')
-rw-r--r--sql/sp_pcontext.cc16
-rw-r--r--sql/sp_pcontext.h10
-rw-r--r--sql/sql_yacc.yy8
3 files changed, 23 insertions, 11 deletions
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 */