mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Fixed BUG#11529: crash server after use stored procedure
Make sure to cleanup the items for a cursor query after each open, otherwise it's done too late, after the run-time mem_root is freed. mysql-test/r/sp.result: New test case for BUG#11529. mysql-test/t/sp.test: New test case for BUG#11529. sql/sp_head.cc: Add a back pointer from a sp_cursor to its cpush instruction, and use it to set the arena and cleanup the items for the cursor's query when opening it. sql/sp_rcontext.cc: Store pointer in sp_cursor to its cpush instruction. sql/sp_rcontext.h: Store pointer in sp_cursor to its cpush instruction.
This commit is contained in:
@ -3224,4 +3224,29 @@ bbbbb 2
|
|||||||
ccccc 3
|
ccccc 3
|
||||||
drop procedure bug10136|
|
drop procedure bug10136|
|
||||||
drop table t3|
|
drop table t3|
|
||||||
|
drop procedure if exists bug11529|
|
||||||
|
create procedure bug11529()
|
||||||
|
begin
|
||||||
|
declare c cursor for select id, data from t1 where data in (10,13);
|
||||||
|
open c;
|
||||||
|
begin
|
||||||
|
declare vid char(16);
|
||||||
|
declare vdata int;
|
||||||
|
declare exit handler for not found begin end;
|
||||||
|
while true do
|
||||||
|
fetch c into vid, vdata;
|
||||||
|
end while;
|
||||||
|
end;
|
||||||
|
close c;
|
||||||
|
end|
|
||||||
|
insert into t1 values
|
||||||
|
('Name1', 10),
|
||||||
|
('Name2', 11),
|
||||||
|
('Name3', 12),
|
||||||
|
('Name4', 13),
|
||||||
|
('Name5', 14)|
|
||||||
|
call bug11529()|
|
||||||
|
call bug11529()|
|
||||||
|
delete from t1|
|
||||||
|
drop procedure bug11529|
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
@ -3911,6 +3911,42 @@ call bug10136()|
|
|||||||
drop procedure bug10136|
|
drop procedure bug10136|
|
||||||
drop table t3|
|
drop table t3|
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUG#11529: crash server after use stored procedure
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop procedure if exists bug11529|
|
||||||
|
--enable_warnings
|
||||||
|
create procedure bug11529()
|
||||||
|
begin
|
||||||
|
declare c cursor for select id, data from t1 where data in (10,13);
|
||||||
|
|
||||||
|
open c;
|
||||||
|
begin
|
||||||
|
declare vid char(16);
|
||||||
|
declare vdata int;
|
||||||
|
declare exit handler for not found begin end;
|
||||||
|
|
||||||
|
while true do
|
||||||
|
fetch c into vid, vdata;
|
||||||
|
end while;
|
||||||
|
end;
|
||||||
|
close c;
|
||||||
|
end|
|
||||||
|
|
||||||
|
insert into t1 values
|
||||||
|
('Name1', 10),
|
||||||
|
('Name2', 11),
|
||||||
|
('Name3', 12),
|
||||||
|
('Name4', 13),
|
||||||
|
('Name5', 14)|
|
||||||
|
|
||||||
|
call bug11529()|
|
||||||
|
call bug11529()|
|
||||||
|
delete from t1|
|
||||||
|
drop procedure bug11529|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# BUG#NNNN: New bug synopsis
|
# BUG#NNNN: New bug synopsis
|
||||||
#
|
#
|
||||||
@ -3921,7 +3957,7 @@ drop table t3|
|
|||||||
|
|
||||||
|
|
||||||
# Add bugs above this line. Use existing tables t1 and t2 when
|
# Add bugs above this line. Use existing tables t1 and t2 when
|
||||||
# practical, or create table t3, t3 etc temporarily (and drop them).
|
# practical, or create table t3, t4 etc temporarily (and drop them).
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
|
||||||
|
@ -1935,7 +1935,7 @@ int
|
|||||||
sp_instr_cpush::execute(THD *thd, uint *nextp)
|
sp_instr_cpush::execute(THD *thd, uint *nextp)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("sp_instr_cpush::execute");
|
DBUG_ENTER("sp_instr_cpush::execute");
|
||||||
thd->spcont->push_cursor(&m_lex_keeper);
|
thd->spcont->push_cursor(&m_lex_keeper, this);
|
||||||
*nextp= m_ip+1;
|
*nextp= m_ip+1;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
@ -1994,7 +1994,19 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Query_arena *old_arena= thd->current_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->current_arena= c->get_instr();
|
||||||
res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
|
res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
|
||||||
|
/* Cleanup the query's items */
|
||||||
|
if (thd->current_arena->free_list)
|
||||||
|
cleanup_items(thd->current_arena->free_list);
|
||||||
|
thd->current_arena= old_arena;
|
||||||
/*
|
/*
|
||||||
Work around the fact that errors in selects are not returned properly
|
Work around the fact that errors in selects are not returned properly
|
||||||
(but instead converted into a warning), so if a condition handler
|
(but instead converted into a warning), so if a condition handler
|
||||||
|
@ -148,9 +148,9 @@ sp_rcontext::restore_variables(uint fp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper)
|
sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
|
||||||
{
|
{
|
||||||
m_cstack[m_ccount++]= new sp_cursor(lex_keeper);
|
m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -169,8 +169,9 @@ sp_rcontext::pop_cursors(uint count)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper)
|
sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
|
||||||
:m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL)
|
:m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL),
|
||||||
|
m_i(i)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
currsor can't be stored in QC, so we should prevent opening QC for
|
currsor can't be stored in QC, so we should prevent opening QC for
|
||||||
|
@ -26,6 +26,7 @@ struct sp_cond_type;
|
|||||||
class sp_cursor;
|
class sp_cursor;
|
||||||
struct sp_pvar;
|
struct sp_pvar;
|
||||||
class sp_lex_keeper;
|
class sp_lex_keeper;
|
||||||
|
class sp_instr_cpush;
|
||||||
|
|
||||||
#define SP_HANDLER_NONE 0
|
#define SP_HANDLER_NONE 0
|
||||||
#define SP_HANDLER_EXIT 1
|
#define SP_HANDLER_EXIT 1
|
||||||
@ -161,7 +162,7 @@ class sp_rcontext : public Sql_alloc
|
|||||||
restore_variables(uint fp);
|
restore_variables(uint fp);
|
||||||
|
|
||||||
void
|
void
|
||||||
push_cursor(sp_lex_keeper *lex_keeper);
|
push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
|
||||||
|
|
||||||
void
|
void
|
||||||
pop_cursors(uint count);
|
pop_cursors(uint count);
|
||||||
@ -203,7 +204,7 @@ class sp_cursor : public Sql_alloc
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
sp_cursor(sp_lex_keeper *lex_keeper);
|
sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
|
||||||
|
|
||||||
virtual ~sp_cursor()
|
virtual ~sp_cursor()
|
||||||
{
|
{
|
||||||
@ -229,6 +230,12 @@ public:
|
|||||||
int
|
int
|
||||||
fetch(THD *, List<struct sp_pvar> *vars);
|
fetch(THD *, List<struct sp_pvar> *vars);
|
||||||
|
|
||||||
|
inline sp_instr_cpush *
|
||||||
|
get_instr()
|
||||||
|
{
|
||||||
|
return m_i;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MEM_ROOT m_mem_root; // My own mem_root
|
MEM_ROOT m_mem_root; // My own mem_root
|
||||||
@ -238,6 +245,7 @@ private:
|
|||||||
my_bool m_nseof; // Original no_send_eof
|
my_bool m_nseof; // Original no_send_eof
|
||||||
Protocol *m_oprot; // Original protcol
|
Protocol *m_oprot; // Original protcol
|
||||||
MYSQL_ROWS *m_current_row;
|
MYSQL_ROWS *m_current_row;
|
||||||
|
sp_instr_cpush *m_i; // My push instruction
|
||||||
|
|
||||||
void
|
void
|
||||||
destroy();
|
destroy();
|
||||||
|
Reference in New Issue
Block a user