diff options
author | konstantin@mysql.com <> | 2005-09-22 02:11:21 +0400 |
---|---|---|
committer | konstantin@mysql.com <> | 2005-09-22 02:11:21 +0400 |
commit | 6f8d3c4844e7f7dd760f09a5ab8ad309d1d690d6 (patch) | |
tree | c670884265eea87654bb764c095e254eff48128d /sql/sp_head.cc | |
parent | e89c5220b54fe74d1afc1361f91e18b164e90e33 (diff) | |
download | mariadb-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.cc | 112 |
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); |