MySQL Lists are EOL. Please join:

List:Internals« Previous MessageNext Message »
From:Petr Chardin Date:August 16 2005 7:11pm
Subject:bk commit into 5.0 tree (petr:1.1976) BUG#11247
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of cps. When cps does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1976 05/08/16 23:11:18 petr@stripped +6 -0
  Fix for Bug#12297  	SP crashes the server if data inserted inside a lon loop
      and Bug#11247  	Stored procedures: Function calls in long loops leak memory

  sql/sp_rcontext.h
    1.22 05/08/16 23:11:10 petr@stripped +7 -1
    Add new member to sp_rcontext class, in order to handle instructions with assignment
    and/or with nested SP processing properly.

  sql/sp_rcontext.cc
    1.32 05/08/16 23:11:10 petr@stripped +5 -5
    Now we should deal with callers_arena->free_list when we employ reuse mechanism with callers_arena
    switched during sp_eval_func_item

  sql/sp_head.cc
    1.164 05/08/16 23:11:10 petr@stripped +199 -126
    Per-instruction arena is implemented

  mysql-test/t/sp.test
    1.137 05/08/16 23:11:10 petr@stripped +53 -0
    added tests for bugs

  mysql-test/r/sp.result
    1.143 05/08/16 23:11:10 petr@stripped +28 -0
    fixed result file to reflect new tests

  mysql-test/r/rpl_sp.result
    1.6 05/08/16 23:11:10 petr@stripped +2 -0
    New commands appeared in result file, as now we always create spcont in a stored routine.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	petr
# Host:	owlet.
# Root:	/home/cps/mysql/devel/mysql-5.0-sp11247

--- 1.5/mysql-test/r/rpl_sp.result	2005-07-19 20:06:42 +04:00
+++ 1.6/mysql-test/r/rpl_sp.result	2005-08-16 23:11:10 +04:00
@@ -109,6 +109,7 @@
 Got one of the listed errors
 show warnings;
 Level	Code	Message
+Error	1142	INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1'
 Warning	1417	A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
 call foo3();
 show warnings;
@@ -117,6 +118,7 @@
 Got one of the listed errors
 show warnings;
 Level	Code	Message
+Error	1142	INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1'
 Warning	1417	A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
 alter procedure foo4 sql security invoker;
 call foo4();

--- 1.142/mysql-test/r/sp.result	2005-08-09 11:43:42 +04:00
+++ 1.143/mysql-test/r/sp.result	2005-08-16 23:11:10 +04:00
@@ -3085,4 +3085,32 @@
 id	id
 data	data
 drop function bug10055|
+drop procedure if exists bug12297|
+create procedure bug12297(lim int)
+begin
+set @x = 0;
+repeat
+insert into t1(id,data)
+values('aa', @x);
+set @x = @x + 1;
+until @x >= lim
+end repeat;
+end|
+call bug12297(10)|
+drop procedure bug12297|
+drop function if exists f_bug11247|
+drop procedure if exists p_bug11247|
+create function f_bug11247(param int)
+returns int
+return param + 1|
+create procedure p_bug11247(lim int)
+begin
+declare v int default 0;
+while v < lim do
+set v= f_bug11247(v);
+end while;
+end|
+call p_bug11247(10)|
+drop function f_bug11247|
+drop procedure p_bug11247|
 drop table t1,t2;

--- 1.136/mysql-test/t/sp.test	2005-08-09 11:43:42 +04:00
+++ 1.137/mysql-test/t/sp.test	2005-08-16 23:11:10 +04:00
@@ -3868,6 +3868,59 @@
 drop function bug10055|
 
 #
+# Bug #12297 "SP crashes the server if data inserted inside a lon loop"
+# The test for memleak bug, so actually there is no way to test it
+# from the suite. The test below could be used to check SP memory
+# consumption by passing large input parameter.
+#
+
+--disable_warnings
+drop procedure if exists bug12297|
+--enable_warnings
+
+create procedure bug12297(lim int)
+begin
+  set @x = 0;
+  repeat
+   insert into t1(id,data)
+   values('aa', @x);
+   set @x = @x + 1;
+  until @x >= lim
+  end repeat;
+end|
+
+call bug12297(10)|
+drop procedure bug12297|
+
+#
+# Bug #11247 "Stored procedures: Function calls in long loops leak memory"
+# One more memleak bug test. One could use this test to check that the memory
+# isn't leaking by increasing the input value for p_bug11247.
+#
+
+--disable_warnings
+drop function if exists f_bug11247|
+drop procedure if exists p_bug11247|
+--enable_warnings
+
+create function f_bug11247(param int)
+  returns int
+return param + 1|
+
+create procedure p_bug11247(lim int)
+begin
+  declare v int default 0;
+
+  while v < lim do
+    set v= f_bug11247(v);
+  end while;
+end|
+
+call p_bug11247(10)|
+drop function f_bug11247|
+drop procedure p_bug11247|
+
+#
 # BUG#NNNN: New bug synopsis
 #
 #--disable_warnings

--- 1.163/sql/sp_head.cc	2005-08-09 12:56:48 +04:00
+++ 1.164/sql/sp_head.cc	2005-08-16 23:11:10 +04:00
@@ -126,16 +126,50 @@
 }
 
 
+/* Macro to switch arena in sp_eval_func_item */
+#define CREATE_ON_CALLERS_ARENA(new_command, condition, backup_arena) do\
+        {\
+          if (condition) \
+            thd->set_n_backup_item_arena(thd->spcont->callers_arena,\
+                                         backup_arena);\
+          new_command;\
+          if (condition)\
+            thd->restore_backup_item_arena(thd->spcont->callers_arena,\
+                                           &backup_current_arena);\
+        } while(0)
+
+/*
+  Evaluate an item and store it in the returned item
+
+  SYNOPSIS
+    sp_eval_func_item()
+      name                  - current thread object
+      it_addr               - pointer to the item to evaluate
+      type                  - type of the item we evaluating
+      reuse                 - used if we would like to reuse existing item
+                              instead of allocation of the new one
+      use_callers_arena     - TRUE if we want to use caller's arena
+                              rather then current one.
+  DESCRIPTION
+   We use this function to evaluate result for stored functions
+   and stored procedure parameters. It is also used to evaluate and
+   (re) allocate variables.
+
+  RETURN VALUES
+    Evaluated item is returned
+*/
+
 /* Evaluate a (presumed) func item. Always returns an item, the parameter
 ** if nothing else.
 */
 Item *
 sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
-		  Item *reuse)
+		  Item *reuse, bool use_callers_arena)
 {
   DBUG_ENTER("sp_eval_func_item");
   Item *it= sp_prepare_func_item(thd, it_addr);
   uint rsize;
+  Query_arena backup_current_arena;
   DBUG_PRINT("info", ("type: %d", type));
 
   if (!it)
@@ -145,91 +179,100 @@
 
   /* QQ How do we do this? Is there some better way? */
   if (type == MYSQL_TYPE_NULL)
-    it= new(reuse, &rsize) Item_null();
-  else
-  {
-    switch (sp_map_result_type(type)) {
-    case INT_RESULT:
-      {
-	longlong i= it->val_int();
+    goto return_null_item;
 
-	if (it->null_value)
-	{
-	  DBUG_PRINT("info", ("INT_RESULT: null"));
-	  it= new(reuse, &rsize) Item_null();
-	}
-	else
-	{
-	  DBUG_PRINT("info", ("INT_RESULT: %d", i));
-          it= new(reuse, &rsize) Item_int(i);
-	}
-	break;
+  switch (sp_map_result_type(type)) {
+  case INT_RESULT:
+    {
+      longlong i= it->val_int();
+
+      if (it->null_value)
+      {
+        DBUG_PRINT("info", ("INT_RESULT: null"));
+        goto return_null_item;
       }
-    case REAL_RESULT:
+      else
       {
-	double d= it->val_real();
+        DBUG_PRINT("info", ("INT_RESULT: %d", i));
+        CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i),
+                          use_callers_arena, &backup_current_arena);
+      }
+      break;
+    }
+  case REAL_RESULT:
+    {
+      double d= it->val_real();
 
-	if (it->null_value)
-	{
-	  DBUG_PRINT("info", ("REAL_RESULT: null"));
-	  it= new(reuse, &rsize) Item_null();
-	}
-	else
-	{
-	  /* There's some difference between Item::new_item() and the
-	   * constructor; the former crashes, the latter works... weird. */
-	  uint8 decimals= it->decimals;
-	  uint32 max_length= it->max_length;
-	  DBUG_PRINT("info", ("REAL_RESULT: %g", d));
-          it= new(reuse, &rsize) Item_float(d);
-	  it->decimals= decimals;
-	  it->max_length= max_length;
-	}
-	break;
+      if (it->null_value)
+      {
+        DBUG_PRINT("info", ("REAL_RESULT: null"));
+        goto return_null_item;
       }
-    case DECIMAL_RESULT:
+      else
       {
-        my_decimal value, *val= it->val_decimal(&value);
-        if (it->null_value)
-          it= new(reuse, &rsize) Item_null();
-        else
-          it= new(reuse, &rsize) Item_decimal(val);
+        /* There's some difference between Item::new_item() and the
+         * constructor; the former crashes, the latter works... weird. */
+        uint8 decimals= it->decimals;
+        uint32 max_length= it->max_length;
+        DBUG_PRINT("info", ("REAL_RESULT: %g", d));
+        CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d),
+                          use_callers_arena, &backup_current_arena);
+        it->decimals= decimals;
+        it->max_length= max_length;
+      }
+      break;
+    }
+  case DECIMAL_RESULT:
+    {
+      my_decimal value, *val= it->val_decimal(&value);
+      if (it->null_value)
+        goto return_null_item;
+      else
+        CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val),
+                          use_callers_arena, &backup_current_arena);
 #ifndef DBUG_OFF
-        char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
-        DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val)));
+      char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
+      DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val)));
 #endif
-        break;
+      break;
+    }
+  case STRING_RESULT:
+    {
+      char buffer[MAX_FIELD_WIDTH];
+      String tmp(buffer, sizeof(buffer), it->collation.collation);
+      String *s= it->val_str(&tmp);
+
+      if (it->null_value)
+      {
+        DBUG_PRINT("info", ("default result: null"));
+        goto return_null_item;
       }
-    case STRING_RESULT:
+      else
       {
-	char buffer[MAX_FIELD_WIDTH];
-	String tmp(buffer, sizeof(buffer), it->collation.collation);
-	String *s= it->val_str(&tmp);
-
-	if (it->null_value)
-	{
-	  DBUG_PRINT("info", ("default result: null"));
-	  it= new(reuse, &rsize) Item_null();
-	}
-	else
-	{
-	  DBUG_PRINT("info",("default result: %*s",
-                             s->length(), s->c_ptr_quick()));
-	  it= new(reuse, &rsize) Item_string(thd->strmake(s->ptr(),
-							  s->length()),
-					     s->length(),
-					     it->collation.collation);
-	}
-	break;
+        DBUG_PRINT("info",("default result: %*s",
+                           s->length(), s->c_ptr_quick()));
+        CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize)
+                              Item_string(thd->strmake(s->ptr(),
+                                          s->length()), s->length(),
+                                          it->collation.collation),
+                          use_callers_arena, &backup_current_arena);
       }
-    case ROW_RESULT:
-    default:
-      DBUG_ASSERT(0);
+      break;
     }
+  case ROW_RESULT:
+  default:
+    DBUG_ASSERT(0);
   }
   it->rsize= rsize;
 
   DBUG_RETURN(it);
+
+return_null_item:
+  CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
+                    use_callers_arena, &backup_current_arena);
+  it->rsize= rsize;
+
+  DBUG_RETURN(it);
 }
 
 
@@ -545,23 +588,14 @@
 sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
 {
   Field *field;
-  MEM_ROOT *tmp_mem_root;
-  THD *thd;
   DBUG_ENTER("sp_head::make_field");
 
-  thd= current_thd;
-  tmp_mem_root= thd->mem_root;
-  if (thd->spcont && thd->spcont->callers_mem_root)
-    thd->mem_root= thd->spcont->callers_mem_root;
-  else
-    thd->mem_root= &thd->main_mem_root;
   field= ::make_field((char *)0,
 		!m_returns_len ? max_length : m_returns_len, 
 		(uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
 		(enum Field::geometry_type)0, Field::NONE, 
 		m_returns_typelib,
 		name ? name : (const char *)m_name.str, dummy);
-  thd->mem_root= tmp_mem_root;
   DBUG_RETURN(field);
 }
 
@@ -576,12 +610,19 @@
   uint ip= 0;
   ulong save_sql_mode;
   Query_arena *old_arena;
+  /* per-instruction arena */
+  MEM_ROOT execute_mem_root;
+  Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP),
+              execute_backup_arena;
   query_id_t old_query_id;
   TABLE *old_derived_tables;
   LEX *old_lex;
   Item_change_list old_change_list;
   String old_packet;
 
+  /* init per-instruction memroot */
+  init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+
   /* Use some extra margin for possible SP recursion and functions */
   if (check_stack_overrun(thd, 4*STACK_MIN_SIZE, olddb))
   {
@@ -660,6 +701,14 @@
       break;
     DBUG_PRINT("execute", ("Instruction %u", ip));
     thd->set_time();		// Make current_time() et al work
+
+    thd->set_n_backup_item_arena(&execute_arena, &execute_backup_arena);
+    /*
+      Save callers arena in order to store instruction results and out
+      parameters in it later during sp_eval_func_item()
+    */
+    thd->spcont->callers_arena= &execute_backup_arena;
+
     /*
       We have to set thd->current_arena before executing the instruction
       to store in the instruction free_list all new items, created
@@ -668,6 +717,7 @@
     */
     thd->current_arena= i;
     ret= i->execute(thd, &ip);
+
     /*
       If this SP instruction have sent eof, it has caused no_send_error to be
       set. Clear it back to allow the next instruction to send error. (multi-
@@ -678,6 +728,11 @@
       cleanup_items(i->free_list);
     i->state= Query_arena::EXECUTED;
 
+    thd->restore_backup_item_arena(&execute_arena, &execute_backup_arena);
+
+    execute_arena.free_items();
+    free_root(&execute_mem_root, MYF(0));
+
     // Check if an exception has occurred and a handler has been found
     // Note: We havo to check even if ret==0, since warnings (and some
     //       errors don't return a non-zero value.
@@ -754,8 +809,6 @@
   sp_rcontext *nctx = NULL;
   uint i;
   int ret;
-  MEM_ROOT call_mem_root;
-  Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena;
 
   if (argcount != params)
   {
@@ -766,16 +819,13 @@
     DBUG_RETURN(-1);
   }
 
-  init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
-
 
   // QQ Should have some error checking here? (types, etc...)
   nctx= new sp_rcontext(csize, hmax, cmax);
-  nctx->callers_mem_root= thd->mem_root;
   for (i= 0 ; i < argcount ; i++)
   {
     sp_pvar_t *pvar = m_pcont->find_pvar(i);
-    Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL);
+    Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL, FALSE);
 
     if (it)
       nctx->push_item(it);
@@ -797,24 +847,16 @@
     }
   }
   thd->spcont= nctx;
-  thd->set_n_backup_item_arena(&call_arena, &backup_arena);
-  /* mem_root was moved to backup_arena */
-  DBUG_ASSERT(nctx->callers_mem_root == backup_arena.mem_root);
 
   ret= execute(thd);
 
-  // Partially restore context now.
-  // We still need the call mem root and free list for processing
-  // of the result.
-  thd->restore_backup_item_arena(&call_arena, &backup_arena);
-
   if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
   {
     /* We need result only in function but not in trigger */
     Item *it= nctx->get_result();
 
     if (it)
-      *resp= sp_eval_func_item(thd, &it, m_returns, NULL);
+      *resp= sp_eval_func_item(thd, &it, m_returns, NULL, FALSE);
     else
     {
       my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
@@ -825,10 +867,6 @@
   nctx->pop_all_cursors();	// To avoid memory leaks after an error
   thd->spcont= octx;
 
-  // Now get rid of the rest of the callee context
-  call_arena.free_items();
-  free_root(&call_mem_root, MYF(0));
-
   DBUG_RETURN(ret);
 }
 
@@ -857,9 +895,7 @@
   uint cmax = m_pcont->max_cursors();
   sp_rcontext *octx = thd->spcont;
   sp_rcontext *nctx = NULL;
-  my_bool tmp_octx = FALSE;	// True if we have allocated a temporary octx
-  MEM_ROOT call_mem_root;
-  Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena;
+  my_bool is_tmp_octx = FALSE;  // True if we have allocated a temporary octx
 
   if (args->elements != params)
   {
@@ -868,7 +904,17 @@
     DBUG_RETURN(-1);
   }
 
-  init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
+  if (! octx)
+  {				// Create a temporary old context
+    octx= new sp_rcontext(csize, hmax, cmax);
+    is_tmp_octx= TRUE;
+    thd->spcont= octx;
+
+    /* set callers_arena to thd, for upper-level function to work */
+    thd->spcont->callers_arena= thd;
+  }
+
+  nctx= new sp_rcontext(csize, hmax, cmax);
 
   if (csize > 0 || hmax > 0 || cmax > 0)
   {
@@ -877,12 +923,6 @@
     List_iterator<Item> li(*args);
     Item *it;
 
-    nctx= new sp_rcontext(csize, hmax, cmax);
-    if (! octx)
-    {				// Create a temporary old context
-      octx= new sp_rcontext(csize, hmax, cmax);
-      tmp_octx= TRUE;
-    }
 
     /* Evaluate SP arguments (i.e. get the values passed as parameters) */
     // QQ: Should do type checking?
@@ -910,7 +950,7 @@
 	}
 	else
 	{
-	  Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL);
+	  Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL, FALSE);
 
 	  if (it2)
 	    nctx->push_item(it2); // IN or INOUT
@@ -941,15 +981,20 @@
 	nit= new Item_null();
       nctx->push_item(nit);
     }
-    thd->spcont= nctx;
   }
 
+  thd->spcont= nctx;
+
   if (! ret)
-  {
-    thd->set_n_backup_item_arena(&call_arena, &backup_arena);
     ret= execute(thd);
-    thd->restore_backup_item_arena(&call_arena, &backup_arena);
-  }
+
+  /*
+    In the case when we weren't able to employ reuse mechanism for
+    OUT/INOUT paranmeters, we should reallocate memory. This
+    allocation should be done on the same arena, which was uses to
+    create procedure parameters.
+  */
+  thd->spcont->callers_arena= octx->callers_arena;
 
   if (!ret && csize > 0)
   {
@@ -972,12 +1017,20 @@
 	  Item *val= nctx->get_item(i);
 	  Item *orig= octx->get_item(offset);
 	  Item *o_item_next;
-	  Item *o_free_list= thd->free_list;
+          /* 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;
-	  copy= sp_eval_func_item(thd, &val, pvar->type, orig); // Copy
+
+          /*
+            We might need to allocate new item if we weren't able to
+            employ reuse mechanism. Then we should do it on the callers arena.
+          */
+	  copy= sp_eval_func_item(thd, &val, pvar->type, orig, TRUE); // Copy
+
 	  if (!copy)
 	  {
 	    ret= -1;
@@ -989,7 +1042,7 @@
 	  {
 	    // A reused item slot, where the constructor put it in the
 	    // free_list, so we have to restore the list.
-	    thd->free_list= o_free_list;
+	    thd->spcont->callers_arena->free_list= o_free_list;
 	    copy->next= o_item_next;
 	  }
 	}
@@ -1017,16 +1070,14 @@
     }
   }
 
-  if (tmp_octx)
+  if (is_tmp_octx)
+  {
+    delete octx;                                /* call destructor */
     octx= NULL;
-  if (nctx)
-    nctx->pop_all_cursors();	// To avoid memory leaks after an error
-  thd->spcont= octx;
+  }
 
-  // Now get rid of the rest of the callee context
-  call_arena.free_items();
-  thd->lex->unit.cleanup();
-  free_root(&call_mem_root, MYF(0));
+  nctx->pop_all_cursors();	// To avoid memory leaks after an error
+  thd->spcont= octx;
 
   DBUG_RETURN(ret);
 }
@@ -1866,7 +1917,7 @@
   Item *it;
   int res;
 
-  it= sp_eval_func_item(thd, &m_value, m_type, NULL);
+  it= sp_eval_func_item(thd, &m_value, m_type, NULL, TRUE);
   if (! it)
     res= -1;
   else
@@ -2009,9 +2060,23 @@
 int
 sp_instr_cpush::execute(THD *thd, uint *nextp)
 {
+  Query_arena backup_current_arena;
   DBUG_ENTER("sp_instr_cpush::execute");
+
+  /*
+    We should create cursors in the callers arena, as
+    it could be (and usually is) used in several instructions.
+  */
+  thd->set_n_backup_item_arena(thd->spcont->callers_arena,
+                               &backup_current_arena);
+
   thd->spcont->push_cursor(&m_lex_keeper, this);
+
+  thd->restore_backup_item_arena(thd->spcont->callers_arena,
+                                 &backup_current_arena);
+
   *nextp= m_ip+1;
+
   DBUG_RETURN(0);
 }
 
@@ -2151,12 +2216,20 @@
 {
   sp_cursor *c= thd->spcont->get_cursor(m_cursor);
   int res;
+  Query_arena backup_current_arena;
   DBUG_ENTER("sp_instr_cfetch::execute");
 
   if (! c)
     res= -1;
   else
+  {
+    thd->set_n_backup_item_arena(thd->spcont->callers_arena,
+                                 &backup_current_arena);
     res= c->fetch(thd, &m_varlist);
+    thd->restore_backup_item_arena(thd->spcont->callers_arena,
+                                   &backup_current_arena);
+  }
+
   *nextp= m_ip+1;
   DBUG_RETURN(res);
 }

--- 1.31/sql/sp_rcontext.cc	2005-06-30 20:07:01 +04:00
+++ 1.32/sql/sp_rcontext.cc	2005-08-16 23:11:10 +04:00
@@ -32,7 +32,6 @@
   : m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
     m_hfound(-1), m_ccount(0)
 {
-  callers_mem_root= NULL;
   in_handler= FALSE;
   m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
   m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
@@ -47,17 +46,18 @@
 			   enum_field_types type)
 {
   extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
-				 Item *reuse);
+				 Item *reuse, bool use_callers_arena);
   Item *it;
   Item *reuse_it;
   Item *old_item_next;
-  Item *old_free_list= thd->free_list;
+  /* sp_eval_func_item will use callers_arena */
+  Item *old_free_list= thd->spcont->callers_arena->free_list;
   int res;
   LINT_INIT(old_item_next);
 
   if ((reuse_it= get_item(idx)))
     old_item_next= reuse_it->next;
-  it= sp_eval_func_item(thd, item_addr, type, reuse_it);
+  it= sp_eval_func_item(thd, item_addr, type, reuse_it, TRUE);
   if (! it)
     res= -1;
   else
@@ -67,7 +67,7 @@
     {
       // A reused item slot, where the constructor put it in the free_list,
       // so we have to restore the list.
-      thd->free_list= old_free_list;
+      thd->spcont->callers_arena->free_list= old_free_list;
       it->next= old_item_next;
     }
     set_item(idx, it);

--- 1.21/sql/sp_rcontext.h	2005-06-30 20:07:01 +04:00
+++ 1.22/sql/sp_rcontext.h	2005-08-16 23:11:10 +04:00
@@ -48,8 +48,14 @@
 
  public:
 
-  MEM_ROOT *callers_mem_root;	// Used to store result fields
   bool in_handler;
+  /*
+    Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT
+    SP parameters when they don't fit into prealloced items. This
+    is common situation with String items. It is used mainly in
+    sp_eval_func_item().
+  */
+  Query_arena *callers_arena;
 
   sp_rcontext(uint fsize, uint hmax, uint cmax);
 
Thread
bk commit into 5.0 tree (petr:1.1976) BUG#11247Petr Chardin16 Aug