=== modified file 'sql/field.h'
--- sql/field.h	2013-03-10 11:46:56 +0000
+++ sql/field.h	2013-03-25 20:40:22 +0000
@@ -70,6 +70,7 @@ struct ha_field_option_struct;
 
 struct st_cache_field;
 int field_conv(Field *to,Field *from);
+bool memcmp_possible(Field *to, Field *from);
 int truncate_double(double *nr, uint field_length, uint dec,
                     bool unsigned_flag, double max_value);
 longlong double_to_longlong(double nr, bool unsigned_flag, bool *error);

=== modified file 'sql/field_conv.cc'
--- sql/field_conv.cc	2012-06-14 18:05:31 +0000
+++ sql/field_conv.cc	2013-03-25 20:40:22 +0000
@@ -823,40 +823,48 @@ Copy_field::get_copy_func(Field *to,Fiel
   return do_field_eq;
 }
 
+bool memcmp_possible(Field *to,Field *from)
+{
+  const enum_field_types to_real_type= to->real_type();
+  const enum_field_types from_real_type= from->real_type();
+
+  return (to_real_type == from_real_type &&
+          !(to->type() == MYSQL_TYPE_BLOB && to->table->copy_blobs) &&
+          to->pack_length() == from->pack_length() &&
+          !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) &&
+          to->decimals() == from->decimals() &&
+          to_real_type != MYSQL_TYPE_ENUM &&
+          to_real_type != MYSQL_TYPE_SET &&
+          to_real_type != MYSQL_TYPE_BIT &&
+          (to_real_type != MYSQL_TYPE_NEWDECIMAL ||
+           to->field_length == from->field_length) &&
+          from->charset() == to->charset() &&
+          (!(to->table->in_use->variables.sql_mode &
+             (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) ||
+           (to->type() != MYSQL_TYPE_DATE &&
+            to->type() != MYSQL_TYPE_DATETIME)) &&
+          (from_real_type != MYSQL_TYPE_VARCHAR ||
+           ((Field_varstring*)from)->length_bytes ==
+           ((Field_varstring*)to)->length_bytes));
+}
 
 /** Simple quick field convert that is called on insert. */
 
 int field_conv(Field *to,Field *from)
 {
-  if (to->real_type() == from->real_type() &&
-      !(to->type() == MYSQL_TYPE_BLOB && to->table->copy_blobs))
-  {
-    if (to->pack_length() == from->pack_length() &&
-        !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) &&
-        to->decimals() == from->decimals() &&
-	to->real_type() != MYSQL_TYPE_ENUM &&
-	to->real_type() != MYSQL_TYPE_SET &&
-        to->real_type() != MYSQL_TYPE_BIT &&
-        (to->real_type() != MYSQL_TYPE_NEWDECIMAL ||
-         to->field_length == from->field_length) &&
-        from->charset() == to->charset() &&
-        (!(to->table->in_use->variables.sql_mode &
-           (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) ||
-         (to->type() != MYSQL_TYPE_DATE &&
-          to->type() != MYSQL_TYPE_DATETIME)) &&
-        (from->real_type() != MYSQL_TYPE_VARCHAR ||
-         ((Field_varstring*)from)->length_bytes ==
-          ((Field_varstring*)to)->length_bytes))
-    {						// Identical fields
-      /*
-        This may happen if one does 'UPDATE ... SET x=x'
-        The test is here mostly for valgrind, but can also be relevant
-        if memcpy() is implemented with prefetch-write
-       */
-      if (to->ptr != from->ptr)
-        memcpy(to->ptr,from->ptr,to->pack_length());
-      return 0;
-    }
+  const enum_field_types to_real_type= to->real_type();
+  const enum_field_types from_real_type= from->real_type();
+
+  if (memcmp_possible(to, from))
+  {						// Identical fields
+    /*
+      This may happen if one does 'UPDATE ... SET x=x'
+      The test is here mostly for valgrind, but can also be relevant
+      if memcpy() is implemented with prefetch-write
+    */
+    if (to->ptr != from->ptr)
+      memcpy(to->ptr,from->ptr, to->pack_length());
+    return 0;
   }
   if (to->type() == MYSQL_TYPE_BLOB)
   {						// Be sure the value is stored
@@ -868,13 +876,13 @@ int field_conv(Field *to,Field *from)
     */
     if (to->table->copy_blobs ||
         (!blob->value.is_alloced() &&
-         from->real_type() != MYSQL_TYPE_STRING &&
-         from->real_type() != MYSQL_TYPE_VARCHAR))
+         from_real_type != MYSQL_TYPE_STRING &&
+         from_real_type != MYSQL_TYPE_VARCHAR))
       blob->value.copy();
     return blob->store(blob->value.ptr(),blob->value.length(),from->charset());
   }
-  if (from->real_type() == MYSQL_TYPE_ENUM &&
-      to->real_type() == MYSQL_TYPE_ENUM &&
+  if (from_real_type == MYSQL_TYPE_ENUM &&
+      to_real_type == MYSQL_TYPE_ENUM &&
       from->val_int() == 0)
   {
     ((Field_enum *)(to))->store_type(0);

=== modified file 'sql/item.cc'
--- sql/item.cc	2013-03-17 10:41:25 +0000
+++ sql/item.cc	2013-03-25 22:55:12 +0000
@@ -2196,6 +2196,7 @@ Item_field::Item_field(Field *f)
   */
   orig_table_name= orig_field_name= "";
   with_field= 1;
+  optimizer_setup= NULL;
 }
 
 
@@ -2245,6 +2246,7 @@ Item_field::Item_field(THD *thd, Name_re
   }
   set_field(f);
   with_field= 1;
+  optimizer_setup= NULL;
 }
 
 
@@ -2260,6 +2262,7 @@ Item_field::Item_field(Name_resolution_c
   if (select && select->parsing_place != IN_HAVING)
       select->select_n_where_fields++;
   with_field= 1;
+  optimizer_setup= NULL;
 }
 
 /**
@@ -5207,6 +5210,7 @@ void Item_field::cleanup()
   field= result_field= 0;
   item_equal= NULL;
   null_value= FALSE;
+  optimizer_setup= NULL;
   DBUG_VOID_RETURN;
 }
 
@@ -5797,14 +5801,56 @@ static int save_field_in_field(Field *fr
   DBUG_RETURN(res);
 }
 
+typedef int (*save_org_in_field_optimizer)(Field *to, Field *from);
+
+
+static int memcmp_func(Field *to, Field *from)
+{
+  if (to->ptr != from->ptr)
+    memcpy(to->ptr,from->ptr, to->pack_length());
+  return 0;
+}
+
+void *Item_field::save_field_optimizer_setup(Field *to)
+{
+  DBUG_ENTER("Item_field::save_field_optimizer_setup");
+  optimizer_setup= to;
+  DBUG_RETURN((void *)
+    (memcmp_possible(to, field) ?
+          &memcmp_func :
+          &field_conv));
+}
+
 
 /**
   Set a field's value from a item.
 */
 
-void Item_field::save_org_in_field(Field *to)
+void Item_field::save_org_in_field(Field *to, void *optimizer_data)
 {
-  save_field_in_field(field, &null_value, to, TRUE);
+  DBUG_ENTER("Item_field::save_org_in_field");
+  DBUG_PRINT("enter", ("setup: 0x%lx  to: 0x%lx  data: 0x%lx",
+                       (ulong) optimizer_setup,
+                       (ulong) to, (ulong) optimizer_data));
+  if (optimizer_data && optimizer_setup == to)
+  {
+    if (field->is_null())
+    {
+      null_value= TRUE;
+      set_field_to_null_with_conversions(to, TRUE);
+      DBUG_VOID_RETURN;
+    }
+    to->set_notnull();
+    if (to == field)
+    {
+      null_value= 0;
+      DBUG_VOID_RETURN;
+    }
+    (*((save_org_in_field_optimizer)(optimizer_data)))(to, field);
+  }
+  else
+    save_field_in_field(field, &null_value, to, TRUE);
+  DBUG_VOID_RETURN;
 }
 
 
@@ -7262,9 +7308,9 @@ int Item_ref::save_in_field(Field *to, b
 }
 
 
-void Item_ref::save_org_in_field(Field *field)
+void Item_ref::save_org_in_field(Field *field, void *optimizer_data)
 {
-  (*ref)->save_org_in_field(field);
+  (*ref)->save_org_in_field(field, optimizer_data);
 }
 
 

=== modified file 'sql/item.h'
--- sql/item.h	2013-03-13 21:33:52 +0000
+++ sql/item.h	2013-03-25 22:55:12 +0000
@@ -690,8 +690,11 @@ class Item {
   /* Function returns 1 on overflow and -1 on fatal errors */
   int save_in_field_no_warnings(Field *field, bool no_conversions);
   virtual int save_in_field(Field *field, bool no_conversions);
-  virtual void save_org_in_field(Field *field)
+  virtual void save_org_in_field(Field *field,
+                                 void *data __attribute__ ((__unused__)))
   { (void) save_in_field(field, 1); }
+  virtual void *save_field_optimizer_setup(Field *field)
+  { return NULL; }
   virtual int save_safe_in_field(Field *field)
   { return save_in_field(field, 1); }
   virtual bool send(Protocol *protocol, String *str);
@@ -923,7 +926,7 @@ class Item {
     save_val() is method of val_* family which stores value in the given
     field.
   */
-  virtual void save_val(Field *to) { save_org_in_field(to); }
+  virtual void save_val(Field *to) { save_org_in_field(to, NULL); }
   /*
     save_result() is method of val*result() family which stores value in
     the given field.
@@ -1967,6 +1970,7 @@ class Item_field :public Item_ident
 public:
   Field *field,*result_field;
   Item_equal *item_equal;
+  Field *optimizer_setup;
   bool no_const_subst;
   /*
     if any_privileges set to TRUE then here real effective privileges will
@@ -2013,7 +2017,8 @@ class Item_field :public Item_ident
   void fix_after_pullout(st_select_lex *new_parent, Item **ref);
   void make_field(Send_field *tmp_field);
   int save_in_field(Field *field,bool no_conversions);
-  void save_org_in_field(Field *field);
+  void save_org_in_field(Field *field, void *optimizer_data);
+  void *save_field_optimizer_setup(Field *field);
   table_map used_tables() const;
   table_map all_used_tables() const; 
   enum Item_result result_type () const
@@ -2866,7 +2871,9 @@ class Item_ref :public Item_ident
   bool fix_fields(THD *, Item **);
   void fix_after_pullout(st_select_lex *new_parent, Item **ref);
   int save_in_field(Field *field, bool no_conversions);
-  void save_org_in_field(Field *field);
+  void save_org_in_field(Field *field, void *optimizer_data);
+  void *save_field_optimizer_setup(Field *field)
+  { return (*ref)->save_field_optimizer_setup(field); }
   enum Item_result result_type () const { return (*ref)->result_type(); }
   enum_field_types field_type() const   { return (*ref)->field_type(); }
   Field *get_tmp_table_field()
@@ -3080,7 +3087,8 @@ class Item_cache_wrapper :public Item_re
   bool is_null();
   bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
   bool send(Protocol *protocol, String *buffer);
-  void save_org_in_field(Field *field)
+  void save_org_in_field(Field *field,
+                         void *data __attribute__ ((__unused__)))
   {
     save_val(field);
   }
@@ -3276,7 +3284,8 @@ class Item_direct_view_ref :public Item_
     return Item_direct_ref::get_date(ltime, fuzzydate);
   }
   bool send(Protocol *protocol, String *buffer);
-  void save_org_in_field(Field *field)
+  void save_org_in_field(Field *field,
+                                 void *data __attribute__ ((__unused__)))
   {
     if (check_null_ref())
       field->set_null();
@@ -3342,7 +3351,7 @@ class Item_outer_ref :public Item_direct
   {}
   void save_in_result_field(bool no_conversions)
   {
-    outer_ref->save_org_in_field(result_field);
+    outer_ref->save_org_in_field(result_field, NULL);
   }
   bool fix_fields(THD *, Item **);
   void fix_after_pullout(st_select_lex *new_parent, Item **ref);

=== modified file 'sql/item_func.h'
--- sql/item_func.h	2013-02-28 17:42:49 +0000
+++ sql/item_func.h	2013-03-25 21:09:46 +0000
@@ -1628,7 +1628,8 @@ class Item_func_set_user_var :public Ite
   {
     return save_in_field(field, no_conversions, 1);
   }
-  void save_org_in_field(Field *field) { (void)save_in_field(field, 1, 0); }
+  void save_org_in_field(Field *field, void *data __attribute__ ((__unused__)))
+    { (void)save_in_field(field, 1, 0); }
   bool register_field_in_read_map(uchar *arg);
   bool register_field_in_bitmap(uchar *arg);
   bool set_entry(THD *thd, bool create_if_not_exists);

=== modified file 'sql/sql_select.cc'
--- sql/sql_select.cc	2013-03-10 11:46:56 +0000
+++ sql/sql_select.cc	2013-03-25 22:42:30 +0000
@@ -17615,7 +17615,16 @@ end_update(JOIN *join, JOIN_TAB *join_ta
   for (group=table->group ; group ; group=group->next)
   {
     Item *item= *group->item;
-    item->save_org_in_field(group->field);
+    if (group->optimizer_setup != group->field)
+    {
+      DBUG_PRINT("info", ("new setup 0x%lx -> 0x%lx",
+                          (ulong)group->optimizer_setup,
+                          (ulong)group->field));
+      group->optimizer_setup= group->field;
+      group->save_field_optimizer_data=
+        item->save_field_optimizer_setup(group->field);
+    }
+    item->save_org_in_field(group->field, group->save_field_optimizer_data);
     /* Store in the used key if the field was 0 */
     if (item->maybe_null)
       group->buff[-1]= (char) group->field->is_null();

=== modified file 'sql/table.h'
--- sql/table.h	2013-03-04 22:53:18 +0000
+++ sql/table.h	2013-03-25 22:32:21 +0000
@@ -196,6 +196,8 @@ typedef struct st_order {
   struct st_order *next;
   Item	 **item;			/* Point at item in select fields */
   Item	 *item_ptr;			/* Storage for initial item */
+  void   *save_field_optimizer_data;    /* function of fast field copy */
+  Field  *optimizer_setup;             /* which field optimizer configured to */
   int    counter;                       /* position in SELECT list, correct
                                            only if counter_used is true*/
   bool	 asc;				/* true if ascending */

