summaryrefslogtreecommitdiff
path: root/sql/sp_head.cc
diff options
context:
space:
mode:
authorkonstantin@mysql.com <>2005-09-22 02:11:21 +0400
committerkonstantin@mysql.com <>2005-09-22 02:11:21 +0400
commit6f8d3c4844e7f7dd760f09a5ab8ad309d1d690d6 (patch)
treec670884265eea87654bb764c095e254eff48128d /sql/sp_head.cc
parente89c5220b54fe74d1afc1361f91e18b164e90e33 (diff)
downloadmariadb-git-6f8d3c4844e7f7dd760f09a5ab8ad309d1d690d6.tar.gz
A fix and a test case for Bug#6513 "Test Suite: Values inserted by using
cursor is interpreted latin1 character and Bug#9819 "Cursors: Mysql Server Crash while fetching from table with 5 million records." A fix for a possible memory leak when fetching into an SP cursor in a long loop. The patch uses a common implementation of cursors in the binary protocol and in stored procedures and implements materialized cursors. For implementation details, see comments in sql_cursor.cc
Diffstat (limited to 'sql/sp_head.cc')
-rw-r--r--sql/sp_head.cc112
1 files changed, 50 insertions, 62 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 1a7599d7bbc..1b0d0254da0 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -199,11 +199,18 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
Item *it= sp_prepare_func_item(thd, it_addr);
uint rsize;
Query_arena backup_arena;
+ Item *old_item_next, *old_free_list, **p_free_list;
DBUG_PRINT("info", ("type: %d", type));
if (!it)
- {
DBUG_RETURN(NULL);
+
+ if (reuse)
+ {
+ old_item_next= reuse->next;
+ p_free_list= use_callers_arena ? &thd->spcont->callers_arena->free_list :
+ &thd->free_list;
+ old_free_list= *p_free_list;
}
switch (sp_map_result_type(type)) {
@@ -312,15 +319,23 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
default:
DBUG_ASSERT(0);
}
- it->rsize= rsize;
-
- DBUG_RETURN(it);
+ goto end;
return_null_item:
CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
use_callers_arena, &backup_arena);
+end:
it->rsize= rsize;
+ if (reuse && it == reuse)
+ {
+ /*
+ The Item constructor registered itself in the arena free list,
+ while the item slot is reused, so we have to restore the list.
+ */
+ it->next= old_item_next;
+ *p_free_list= old_free_list;
+ }
DBUG_RETURN(it);
}
@@ -1358,14 +1373,6 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
uint offset= static_cast<Item_splocal *>(it)->get_offset();
Item *val= nctx->get_item(i);
Item *orig= octx->get_item(offset);
- Item *o_item_next;
- /* we'll use callers_arena in sp_eval_func_item */
- Item *o_free_list= thd->spcont->callers_arena->free_list;
-
- LINT_INIT(o_item_next);
-
- if (orig)
- o_item_next= orig->next;
/*
We might need to allocate new item if we weren't able to
@@ -1380,15 +1387,6 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
}
if (copy != orig)
octx->set_item(offset, copy);
- if (orig && copy == orig)
- {
- /*
- A reused item slot, where the constructor put it in the
- free_list, so we have to restore the list.
- */
- thd->spcont->callers_arena->free_list= o_free_list;
- copy->next= o_item_next;
- }
}
else
{
@@ -2476,6 +2474,10 @@ sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx)
int
sp_instr_copen::execute(THD *thd, uint *nextp)
{
+ /*
+ We don't store a pointer to the cursor in the instruction to be
+ able to reuse the same instruction among different threads in future.
+ */
sp_cursor *c= thd->spcont->get_cursor(m_cursor);
int res;
DBUG_ENTER("sp_instr_copen::execute");
@@ -2484,41 +2486,33 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
res= -1;
else
{
- sp_lex_keeper *lex_keeper= c->pre_open(thd);
- if (!lex_keeper) // cursor already open or OOM
- {
- res= -1;
- *nextp= m_ip+1;
- }
- else
- {
- Query_arena *old_arena= thd->stmt_arena;
+ sp_lex_keeper *lex_keeper= c->get_lex_keeper();
+ Query_arena *old_arena= thd->stmt_arena;
- /*
- Get the Query_arena from the cpush instruction, which contains
- the free_list of the query, so new items (if any) are stored in
- the right free_list, and we can cleanup after each open.
- */
- thd->stmt_arena= c->get_instr();
- res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
- /* Cleanup the query's items */
- if (thd->stmt_arena->free_list)
- cleanup_items(thd->stmt_arena->free_list);
- thd->stmt_arena= old_arena;
- /*
- Work around the fact that errors in selects are not returned properly
- (but instead converted into a warning), so if a condition handler
- caught, we have lost the result code.
- */
- if (!res)
- {
- uint dummy1, dummy2;
+ /*
+ Get the Query_arena from the cpush instruction, which contains
+ the free_list of the query, so new items (if any) are stored in
+ the right free_list, and we can cleanup after each open.
+ */
+ thd->stmt_arena= c->get_instr();
+ res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
+ /* Cleanup the query's items */
+ if (thd->stmt_arena->free_list)
+ cleanup_items(thd->stmt_arena->free_list);
+ thd->stmt_arena= old_arena;
+ /*
+ Work around the fact that errors in selects are not returned properly
+ (but instead converted into a warning), so if a condition handler
+ caught, we have lost the result code.
+ */
+ if (!res)
+ {
+ uint dummy1, dummy2;
- if (thd->spcont->found_handler(&dummy1, &dummy2))
- res= -1;
- }
- c->post_open(thd, res ? FALSE : TRUE);
+ if (thd->spcont->found_handler(&dummy1, &dummy2))
+ res= -1;
}
+ /* TODO: Assert here that we either have an error or a cursor */
}
DBUG_RETURN(res);
}
@@ -2527,7 +2521,8 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
int
sp_instr_copen::exec_core(THD *thd, uint *nextp)
{
- int res= mysql_execute_command(thd);
+ sp_cursor *c= thd->spcont->get_cursor(m_cursor);
+ int res= c->open(thd);
*nextp= m_ip+1;
return res;
}
@@ -2582,14 +2577,7 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp)
Query_arena backup_arena;
DBUG_ENTER("sp_instr_cfetch::execute");
- if (! c)
- res= -1;
- else
- {
- thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena);
- res= c->fetch(thd, &m_varlist);
- thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena);
- }
+ res= c ? c->fetch(thd, &m_varlist) : -1;
*nextp= m_ip+1;
DBUG_RETURN(res);