Commit 81ecb75e authored by unknown's avatar unknown

Fixed BUG#6048: Stored procedure causes operating system reboot.

  Memory leak in locally evalutated expressions during SP execution fixed by
  reusing allocated item slots when possible.
  Note: No test case added, since the test is a stress test that tries to make
  the machine to run out of memory.


sql/item.cc:
  Make it possible to reuse allocated item slots (for use in SP execution).
sql/item.h:
  Make it possible to reuse allocated item slots (for use in SP execution).
sql/sp_head.cc:
  Reuse allocated item slots for expression evalutation during SP execution.
sql/sp_rcontext.cc:
  Updated sp_eval_func_item() call, and prevent item reuse in reused frames (for handlers).
parent b167a4ac
...@@ -307,8 +307,14 @@ Item::Item(): ...@@ -307,8 +307,14 @@ Item::Item():
/* Put item in free list so that we can free all items at end */ /* Put item in free list so that we can free all items at end */
THD *thd= current_thd; THD *thd= current_thd;
next= thd->free_list;
thd->free_list= this; if (reused)
next= reuse_next;
else
{
next= thd->free_list;
thd->free_list= this;
}
/* /*
Item constructor can be called during execution other then SQL_COM Item constructor can be called during execution other then SQL_COM
command => we should check thd->lex->current_select on zero (thd->lex command => we should check thd->lex->current_select on zero (thd->lex
...@@ -343,8 +349,13 @@ Item::Item(THD *thd, Item *item): ...@@ -343,8 +349,13 @@ Item::Item(THD *thd, Item *item):
fixed(item->fixed), fixed(item->fixed),
collation(item->collation) collation(item->collation)
{ {
next= thd->free_list; // Put in free list if (reused)
thd->free_list= this; next= reuse_next;
else
{
next= thd->free_list; // Put in free list
thd->free_list= this;
}
} }
......
...@@ -229,9 +229,59 @@ class Item { ...@@ -229,9 +229,59 @@ class Item {
Item(const Item &); /* Prevent use of these */ Item(const Item &); /* Prevent use of these */
void operator=(Item &); void operator=(Item &);
public: public:
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } /* For SP reuse mechanism */
bool reused;
size_t reuse_slot_size;
Item *reuse_next;
static void *operator new(size_t size)
{
Item *me= (Item *)sql_alloc((uint) size);
if (me)
{
me->reuse_slot_size= size;
me->reused= FALSE;
}
return (void*)me;
}
static void *operator new(size_t size, MEM_ROOT *mem_root) static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); } {
Item *me= (Item *)alloc_root(mem_root, (uint) size);
if (me)
{
me->reuse_slot_size= size;
me->reused= FALSE;
}
return (void*)me;
}
static void *operator new(size_t size, MEM_ROOT *mem_root, Item *reuse)
{
Item *me;
if (!reuse || size > reuse->reuse_slot_size)
{
me= (Item *)alloc_root(mem_root, (uint) size);
if (me)
{
me->reuse_slot_size= size;
me->reused= FALSE;
}
}
else
{ /* Reuse old item */
size_t slot_size= reuse->reuse_slot_size;
reuse->delete_self();
me= reuse;
me->reuse_slot_size= slot_size;
/* For the constructor */
me->reuse_next= reuse->next;
me->reused= TRUE;
}
return (void *)me;
}
static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); } static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {} static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
......
...@@ -131,7 +131,9 @@ sp_prepare_func_item(THD* thd, Item **it_addr) ...@@ -131,7 +131,9 @@ sp_prepare_func_item(THD* thd, Item **it_addr)
** if nothing else. ** if nothing else.
*/ */
Item * Item *
sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
MEM_ROOT *mem_root,
Item *reuse)
{ {
DBUG_ENTER("sp_eval_func_item"); DBUG_ENTER("sp_eval_func_item");
Item *it= sp_prepare_func_item(thd, it_addr); Item *it= sp_prepare_func_item(thd, it_addr);
...@@ -144,7 +146,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) ...@@ -144,7 +146,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type)
/* QQ How do we do this? Is there some better way? */ /* QQ How do we do this? Is there some better way? */
if (type == MYSQL_TYPE_NULL) if (type == MYSQL_TYPE_NULL)
it= new Item_null(); it= new(mem_root, reuse) Item_null();
else else
{ {
switch (sp_map_result_type(type)) { switch (sp_map_result_type(type)) {
...@@ -155,12 +157,12 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) ...@@ -155,12 +157,12 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type)
if (it->null_value) if (it->null_value)
{ {
DBUG_PRINT("info", ("INT_RESULT: null")); DBUG_PRINT("info", ("INT_RESULT: null"));
it= new Item_null(); it= new(mem_root, reuse) Item_null();
} }
else else
{ {
DBUG_PRINT("info", ("INT_RESULT: %d", i)); DBUG_PRINT("info", ("INT_RESULT: %d", i));
it= new Item_int(i); it= new(mem_root, reuse) Item_int(i);
} }
break; break;
} }
...@@ -171,7 +173,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) ...@@ -171,7 +173,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type)
if (it->null_value) if (it->null_value)
{ {
DBUG_PRINT("info", ("REAL_RESULT: null")); DBUG_PRINT("info", ("REAL_RESULT: null"));
it= new Item_null(); it= new(mem_root, reuse) Item_null();
} }
else else
{ {
...@@ -180,7 +182,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) ...@@ -180,7 +182,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type)
uint8 decimals= it->decimals; uint8 decimals= it->decimals;
uint32 max_length= it->max_length; uint32 max_length= it->max_length;
DBUG_PRINT("info", ("REAL_RESULT: %g", d)); DBUG_PRINT("info", ("REAL_RESULT: %g", d));
it= new Item_float(d); it= new(mem_root, reuse) Item_float(d);
it->decimals= decimals; it->decimals= decimals;
it->max_length= max_length; it->max_length= max_length;
} }
...@@ -190,9 +192,9 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) ...@@ -190,9 +192,9 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type)
{ {
my_decimal value, *val= it->val_decimal(&value); my_decimal value, *val= it->val_decimal(&value);
if (it->null_value) if (it->null_value)
it= new Item_null(); it= new(mem_root, reuse) Item_null();
else else
it= new Item_decimal(val); it= new(mem_root, reuse) Item_decimal(val);
#ifndef DBUG_OFF #ifndef DBUG_OFF
char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val))); DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val)));
...@@ -208,14 +210,16 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) ...@@ -208,14 +210,16 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type)
if (it->null_value) if (it->null_value)
{ {
DBUG_PRINT("info", ("default result: null")); DBUG_PRINT("info", ("default result: null"));
it= new Item_null(); it= new(mem_root, reuse) Item_null();
} }
else else
{ {
DBUG_PRINT("info",("default result: %*s", DBUG_PRINT("info",("default result: %*s",
s->length(), s->c_ptr_quick())); s->length(), s->c_ptr_quick()));
it= new Item_string(thd->strmake(s->ptr(), s->length()), it= new(mem_root, reuse) Item_string(thd->strmake(s->ptr(),
s->length(), it->collation.collation); s->length()),
s->length(),
it->collation.collation);
} }
break; break;
} }
...@@ -708,7 +712,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) ...@@ -708,7 +712,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
for (i= 0 ; i < params && i < argcount ; i++) for (i= 0 ; i < params && i < argcount ; i++)
{ {
sp_pvar_t *pvar = m_pcont->find_pvar(i); sp_pvar_t *pvar = m_pcont->find_pvar(i);
Item *it= sp_eval_func_item(thd, argp++, pvar->type); Item *it= sp_eval_func_item(thd, argp++, pvar->type, thd->mem_root, NULL);
if (it) if (it)
nctx->push_item(it); nctx->push_item(it);
...@@ -823,7 +827,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) ...@@ -823,7 +827,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
} }
else else
{ {
Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type); Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type,
thd->mem_root, NULL);
if (it2) if (it2)
nctx->push_item(it2); // IN or INOUT nctx->push_item(it2); // IN or INOUT
...@@ -1468,7 +1473,9 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) ...@@ -1468,7 +1473,9 @@ sp_instr_set::exec_core(THD *thd, uint *nextp)
Item *it; Item *it;
int res; int res;
it= sp_eval_func_item(thd, &m_value, m_type); it= sp_eval_func_item(thd, &m_value, m_type,
thd->mem_root,
thd->spcont->get_item(m_offset));
if (! it) if (! it)
res= -1; res= -1;
else else
...@@ -1714,7 +1721,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) ...@@ -1714,7 +1721,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp)
Item *it; Item *it;
int res; int res;
it= sp_eval_func_item(thd, &m_value, m_type); it= sp_eval_func_item(thd, &m_value, m_type, thd->mem_root, NULL);
if (! it) if (! it)
res= -1; res= -1;
else else
......
...@@ -43,8 +43,11 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax) ...@@ -43,8 +43,11 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
int int
sp_rcontext::set_item_eval(uint idx, Item **item_addr, enum_field_types type) sp_rcontext::set_item_eval(uint idx, Item **item_addr, enum_field_types type)
{ {
extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type); extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
Item *it= sp_eval_func_item(current_thd, item_addr, type); MEM_ROOT *mem_root,
Item *reuse);
THD *thd= current_thd;
Item *it= sp_eval_func_item(thd, item_addr, type, thd->mem_root, NULL);
if (! it) if (! it)
return -1; return -1;
...@@ -111,7 +114,12 @@ void ...@@ -111,7 +114,12 @@ void
sp_rcontext::save_variables(uint fp) sp_rcontext::save_variables(uint fp)
{ {
while (fp < m_count) while (fp < m_count)
m_saved.push_front(m_frame[fp++]); {
Item *it= m_frame[fp];
m_frame[fp++]= NULL; // Prevent reuse
m_saved.push_front(it);
}
} }
void void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment