diff --git a/sql/item.cc b/sql/item.cc
index 8100e78491b993b8b5537261d14648941a5ea662..5f215c295788279016e9d5820cc0abcf881782c8 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -307,8 +307,14 @@ Item::Item():
 
   /* Put item in free list so that we can free all items at end */
   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
     command => we should check thd->lex->current_select on zero (thd->lex
@@ -343,8 +349,13 @@ Item::Item(THD *thd, Item *item):
   fixed(item->fixed),
   collation(item->collation)
 {
-  next= thd->free_list;				// Put in free list
-  thd->free_list= this;
+  if (reused)
+    next= reuse_next;
+  else
+  {
+    next= thd->free_list;	// Put in free list
+    thd->free_list= this;
+  }
 }
 
 
diff --git a/sql/item.h b/sql/item.h
index 2bcc9482f4ec33c455b1be577b09b85d76e63476..cd3e86aecd32b0147c442d4e3e0497a70175c22e 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -229,9 +229,59 @@ class Item {
   Item(const Item &);			/* Prevent use of these */
   void operator=(Item &);
 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)
-  { 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, MEM_ROOT *mem_root) {}
 
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index ca2ec6d0acf2804b82afa31c0b5ca269c85144ce..0424f6caa9ffe2b2a43ca19b96d0c2502df7c87f 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -131,7 +131,9 @@ sp_prepare_func_item(THD* thd, Item **it_addr)
 ** if nothing else.
 */
 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");
   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)
 
   /* QQ How do we do this? Is there some better way? */
   if (type == MYSQL_TYPE_NULL)
-    it= new Item_null();
+    it= new(mem_root, reuse) Item_null();
   else
   {
     switch (sp_map_result_type(type)) {
@@ -155,12 +157,12 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type)
 	if (it->null_value)
 	{
 	  DBUG_PRINT("info", ("INT_RESULT: null"));
-	  it= new Item_null();
+	  it= new(mem_root, reuse) Item_null();
 	}
 	else
 	{
 	  DBUG_PRINT("info", ("INT_RESULT: %d", i));
-          it= new Item_int(i);
+          it= new(mem_root, reuse) Item_int(i);
 	}
 	break;
       }
@@ -171,7 +173,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type)
 	if (it->null_value)
 	{
 	  DBUG_PRINT("info", ("REAL_RESULT: null"));
-	  it= new Item_null();
+	  it= new(mem_root, reuse) Item_null();
 	}
 	else
 	{
@@ -180,7 +182,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type)
 	  uint8 decimals= it->decimals;
 	  uint32 max_length= it->max_length;
 	  DBUG_PRINT("info", ("REAL_RESULT: %g", d));
-          it= new Item_float(d);
+          it= new(mem_root, reuse) Item_float(d);
 	  it->decimals= decimals;
 	  it->max_length= max_length;
 	}
@@ -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);
         if (it->null_value)
-          it= new Item_null();
+          it= new(mem_root, reuse) Item_null();
         else
-          it= new Item_decimal(val);
+          it= new(mem_root, reuse) Item_decimal(val);
 #ifndef DBUG_OFF
         char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
         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)
 	if (it->null_value)
 	{
 	  DBUG_PRINT("info", ("default result: null"));
-	  it= new Item_null();
+	  it= new(mem_root, reuse) Item_null();
 	}
 	else
 	{
 	  DBUG_PRINT("info",("default result: %*s",
                              s->length(), s->c_ptr_quick()));
-	  it= new Item_string(thd->strmake(s->ptr(), s->length()),
-			      s->length(), it->collation.collation);
+	  it= new(mem_root, reuse) Item_string(thd->strmake(s->ptr(),
+							    s->length()),
+					       s->length(),
+					       it->collation.collation);
 	}
 	break;
       }
@@ -708,7 +712,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
   for (i= 0 ; i < params && i < argcount ; 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)
       nctx->push_item(it);
@@ -823,7 +827,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
 	}
 	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)
 	    nctx->push_item(it2); // IN or INOUT
@@ -1469,7 +1474,9 @@ sp_instr_set::exec_core(THD *thd, uint *nextp)
   Item *it;
   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)
     res= -1;
   else
@@ -1715,7 +1722,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp)
   Item *it;
   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)
     res= -1;
   else
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 672491a97f29b86f40ef35dbdab3cf744d8d67f3..fdffa7fb88d1a35fb63e458784f02aa0c022f0fe 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -43,8 +43,11 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
 int
 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);
-  Item *it= sp_eval_func_item(current_thd, item_addr, type);
+  extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types 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)
     return -1;
@@ -111,7 +114,12 @@ void
 sp_rcontext::save_variables(uint fp)
 {
   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