diff --git a/sql/item.cc b/sql/item.cc
index 4c7b30b041018dd95c73b177847eb82b16d85ddb..950f27c5d69d953305b78431162d036f2e52a3a4 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -183,44 +183,61 @@ CHARSET_INFO * Item::default_charset() const
   return current_thd->variables.collation_connection;
 }
 
-bool Item::set_charset(CHARSET_INFO *cs1, Derivation co1,
-		       CHARSET_INFO *cs2, Derivation co2)
+bool DTCollation::aggregate(DTCollation &dt)
 {
-  if (cs1 == &my_charset_bin || cs2 == &my_charset_bin)
+  if (collation == &my_charset_bin || dt.collation == &my_charset_bin)
   {
-    set_charset(&my_charset_bin, DERIVATION_NONE);
+    collation= &my_charset_bin;
+    derivation= derivation > dt.derivation ? derivation : dt.derivation;
     return 0;
   }
-
-  if (!my_charset_same(cs1,cs2))
-    return 1;
-
-  if (co1 < co2)
+  
+  if (!my_charset_same(collation, dt.collation))
   {
-    set_charset(cs1, co1);
+    /* 
+       We do allow to use binary strings (like BLOBS)
+       together with character strings.
+       Binaries have more precedance
+    */
+    if ((derivation <= dt.derivation) && (collation == &my_charset_bin))
+    {
+      // Do nothing
+    }
+    else if ((dt.derivation <= derivation) && (dt.collation==&my_charset_bin))
+    {
+      set(dt);
+    }
+    else
+    {
+      set(0, DERIVATION_NONE);
+      return 1; 
+    }
   }
-  else if (co2 < co1)
+  else if (derivation < dt.derivation)
   {
-    set_charset(cs2, co2);
+    // Do nothing
   }
-  else  // co2 == co1
+  else if (dt.derivation < derivation)
   {
-    if (cs1 != cs2)
+    set(dt);
+  }
+  else
+  { 
+    if (collation == dt.collation)
     {
-      if (co1 == DERIVATION_EXPLICIT)
-      {
-        return 1;
-      }
-      else
+      // Do nothing
+    }
+    else 
+    {
+      if (derivation == DERIVATION_EXPLICIT)
       {
-        CHARSET_INFO *bin= get_charset_by_csname(cs1->csname, MY_CS_BINSORT,MYF(0));
-        if (!bin)
-	  return 1;
-        set_charset(bin, DERIVATION_NONE);
+	set(0, DERIVATION_NONE);
+	return 1;
       }
+      CHARSET_INFO *bin= get_charset_by_csname(collation->csname, 
+					       MY_CS_BINSORT,MYF(0));
+      set(bin, DERIVATION_NONE);
     }
-    else
-      set_charset(cs2, co2);
   }
   return 0;
 }
diff --git a/sql/item.h b/sql/item.h
index ce79e70e5d696a280200734a0dbc57172f063c01..e80648b89deb78e55068275b62f0a4a175e9dd2d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -52,10 +52,10 @@ public:
     collation= collation_arg;
     derivation= derivation_arg;
   }
-  void set(DTCollation *dt)
+  void set(DTCollation &dt)
   { 
-    collation= dt->collation;
-    derivation= dt->derivation;
+    collation= dt.collation;
+    derivation= dt.derivation;
   }
   void set(CHARSET_INFO *collation_arg, Derivation derivation_arg)
   {
@@ -66,7 +66,9 @@ public:
   { collation= collation_arg; }
   void set(Derivation derivation_arg)
   { derivation= derivation_arg; }
-  bool aggregate(DTCollation *dt);
+  bool aggregate(DTCollation &dt);
+  bool set(DTCollation &dt1, DTCollation &dt2)
+  { set(dt1); return aggregate(dt2); }
   const char *derivation_name() const
   {
     switch(derivation)
@@ -183,8 +185,6 @@ public:
     collation.collation= collation_arg->collation; 
     collation.derivation= collation_arg->derivation;
   }
-  bool set_charset(CHARSET_INFO *cs1, Derivation dv1, 
-  		   CHARSET_INFO *cs2, Derivation dv2);
   bool binary() const
   { return charset()->state & MY_CS_BINSORT ? 1 : 0 ; }
   
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 035f85a45ba3e24d7e0596013b24ad7c5f416747..52bd14ed5159d2547d9951e92d4650e3b2d85dcd 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -96,72 +96,26 @@ static bool convert_constant_item(Field *field, Item **item)
   return 0;
 }
 
-bool Item_bool_func2::set_cmp_charset(CHARSET_INFO *cs1, Derivation co1,
-				      CHARSET_INFO *cs2, Derivation co2)
-{
-  if (cs1 == &my_charset_bin || cs2 == &my_charset_bin)
-  {
-    cmp_charset= &my_charset_bin;
-    //coercibility= co1 > co2 ? co1 : co2;
-    return 0;
-  }
-
-  if (!my_charset_same(cs1, cs2))
-  {
-    /* 
-       We do allow to use BLOBS together with character strings
-       BLOBS have more precedance
-    */
-    if ((co1 <= co2) && (cs1==&my_charset_bin))
-    {
-      cmp_charset= cs1;
-      //coercibility= co1;
-    }
-    else if ((co2 <= co1) && (cs2==&my_charset_bin))
-    {
-      cmp_charset= cs2;
-      //coercibility= co2;
-    }
-    else
-    {
-      cmp_charset= 0;
-      //coercibility= DERIVATION_NOCOLL;
-      return 1; 
-    }
-  }
-  else if (co1 < co2)
-  {
-    cmp_charset= cs1;
-    //coercibility= co1;
-  }
-  else if (co2 < co1)
-  {
-    cmp_charset= cs2;
-    //coercibility= co1;
-  }
-  else
-  { 
-    if (cs1 == cs2)
-    {
-      cmp_charset= cs1;
-      //coercibility= co1;
-    }
-    else 
-    {
-      //coercibility= DERIVATION_NOCOLL;
-      cmp_charset= 0;
-      return  (co1 == DERIVATION_EXPLICIT) ? 1 : 0;
-    }
-  }
-  return 0;
-}
-
 
 bool Item_bool_func2::fix_fields(THD *thd, struct st_table_list *tables,
 				 Item ** ref)
 {
   if (Item_int_func::fix_fields(thd, tables, ref))
     return 1;
+  return 0;
+}
+
+
+void Item_bool_func2::fix_length_and_dec()
+{
+  max_length= 1;				     // Function returns 0 or 1
+
+  /*
+    As some compare functions are generated after sql_yacc,
+    we have to check for out of memory conditions here
+  */
+  if (!args[0] || !args[1])
+    return;
 
   /* 
     We allow to convert to Unicode character sets in some cases.
@@ -209,35 +163,12 @@ bool Item_bool_func2::fix_fields(THD *thd, struct st_table_list *tables,
       else
       {
 	conv= new Item_func_conv_charset(args[weak],args[strong]->charset());
-        //conv->coercibility= args[weak]->derivation();
+        conv->collation.set(args[weak]->derivation());
       }
       args[weak]= conv ? conv : args[weak];
-      set_cmp_charset(args[0]->charset(), args[0]->derivation(),
-		      args[1]->charset(), args[1]->derivation());
     }
   }
-  if (!cmp_charset)
-  {
-    /* set_cmp_charset() failed */
-    my_coll_agg_error(args[0]->collation, args[1]->collation, func_name());
-    return 1;
-  }
-  return 0;
-}
-
-
-void Item_bool_func2::fix_length_and_dec()
-{
-  max_length= 1;				     // Function returns 0 or 1
-
-  /*
-    As some compare functions are generated after sql_yacc,
-    we have to check for out of memory conditions here
-  */
-  if (!args[0] || !args[1])
-    return;
-
-
+  
   // Make a special case of compare with fields to get nicer DATE comparisons
   if (args[0]->type() == FIELD_ITEM)
   {
@@ -248,7 +179,8 @@ void Item_bool_func2::fix_length_and_dec()
       {
 	cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
 			 INT_RESULT);		// Works for all types.
-	cmp_charset= &my_charset_bin;		// For test in fix_fields
+	cmp_collation.set(&my_charset_bin, 
+			  DERIVATION_NONE);	// For test in fix_fields
 	return;
       }
     }
@@ -262,7 +194,8 @@ void Item_bool_func2::fix_length_and_dec()
       {
 	cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
 			 INT_RESULT); // Works for all types.
-	cmp_charset= &my_charset_bin;		// For test in fix_fields
+	cmp_collation.set(&my_charset_bin,
+			  DERIVATION_NONE);	// For test in fix_fields
 	return;
       }
     }
@@ -272,8 +205,12 @@ void Item_bool_func2::fix_length_and_dec()
     We must set cmp_charset here as we may be called from for an automatic
     generated item, like in natural join
   */
-  set_cmp_charset(args[0]->charset(), args[0]->derivation(),
-		  args[1]->charset(), args[1]->derivation());
+  if (cmp_collation.set(args[0]->collation, args[1]->collation))
+  {
+    /* set_cmp_charset() failed */
+    my_coll_agg_error(args[0]->collation, args[1]->collation, func_name());
+    return;
+  }
 }
 
 
@@ -315,7 +252,7 @@ int Arg_comparator::compare_string()
     if ((res2= (*b)->val_str(&owner->tmp_value2)))
     {
       owner->null_value= 0;
-      return sortcmp(res1,res2,owner->cmp_charset);
+      return sortcmp(res1,res2,owner->cmp_collation.collation);
     }
   }
   owner->null_value= 1;
@@ -329,7 +266,7 @@ int Arg_comparator::compare_e_string()
   res2= (*b)->val_str(&owner->tmp_value2);
   if (!res1 || !res2)
     return test(res1 == res2);
-  return test(sortcmp(res1, res2, owner->cmp_charset) == 0);
+  return test(sortcmp(res1, res2, owner->cmp_collation.collation) == 0);
 }
 
 
@@ -558,7 +495,7 @@ longlong Item_func_strcmp::val_int()
     null_value=1;
     return 0;
   }
-  int value= sortcmp(a,b,cmp_charset);
+  int value= sortcmp(a,b,cmp_collation.collation);
   null_value=0;
   return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1);
 }
@@ -750,8 +687,7 @@ Item_func_ifnull::fix_length_and_dec()
 					  args[1]->result_type())) !=
       REAL_RESULT)
     decimals= 0;
-  if (set_charset(args[0]->charset(),args[0]->derivation(),
-		  args[1]->charset(),args[1]->derivation()))
+  if (collation.set(args[0]->collation,args[1]->collation))
     my_coll_agg_error(args[0]->collation, args[1]->collation, func_name());
 }
 
@@ -828,8 +764,7 @@ Item_func_if::fix_length_and_dec()
   else if (arg1_type == STRING_RESULT || arg2_type == STRING_RESULT)
   {
     cached_result_type = STRING_RESULT;
-    if (set_charset(args[1]->charset(), args[1]->derivation(),
-		args[2]->charset(), args[2]->derivation()))
+    if (collation.set(args[1]->collation, args[2]->collation))
     {
       my_coll_agg_error(args[0]->collation, args[1]->collation, func_name());
       return;
@@ -1944,7 +1879,7 @@ longlong Item_func_like::val_int()
   null_value=0;
   if (canDoTurboBM)
     return turboBM_matches(res->ptr(), res->length()) ? 1 : 0;
-  return my_wildcmp(cmp_charset,
+  return my_wildcmp(cmp_collation.collation,
 		    res->ptr(),res->ptr()+res->length(),
 		    res2->ptr(),res2->ptr()+res2->length(),
 		    escape,wild_one,wild_many) ? 0 : 1;
@@ -2148,7 +2083,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff)
 
   *splm1 = pattern_len;
 
-  if (cmp_charset == &my_charset_bin)
+  if (cmp_collation.collation == &my_charset_bin)
   {
     int i;
     for (i = pattern_len - 2; i >= 0; i--)
@@ -2251,7 +2186,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts()
   for (i = bmBc; i < end; i++)
     *i = pattern_len;
 
-  if (cmp_charset == &my_charset_bin)
+  if (cmp_collation.collation == &my_charset_bin)
   {
     for (j = 0; j < plm1; j++)
       bmBc[(uint) (uchar) pattern[j]] = plm1 - j;
@@ -2282,7 +2217,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
   const int tlmpl= text_len - pattern_len;
 
   /* Searching */
-  if (cmp_charset == &my_charset_bin)
+  if (cmp_collation.collation == &my_charset_bin)
   {
     while (j <= tlmpl)
     {
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index b38248d87e149ac188c3fec822e9ae2fea3033f6..70e477402d989805aca42ba563fc44dfe4bc8d67 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -112,25 +112,25 @@ class Item_bool_func2 :public Item_int_func
 protected:
   Arg_comparator cmp;
   String tmp_value1,tmp_value2;
-  CHARSET_INFO *cmp_charset;
+  DTCollation cmp_collation;
 
 public:
   Item_bool_func2(Item *a,Item *b):
-    Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), cmp_charset(0) {}
+    Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1)
+    { cmp_collation.set(0,DERIVATION_NONE);}
   bool fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref);
   void fix_length_and_dec();
   void set_cmp_func()
   {
     cmp.set_cmp_func(this, tmp_arg, tmp_arg+1);
   }
-  bool set_cmp_charset(CHARSET_INFO *cs1, Derivation co1, 
-  		       CHARSET_INFO *cs2, Derivation co2);
   optimize_type select_optimize() const { return OPTIMIZE_OP; }
   virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
   bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
   void print(String *str) { Item_func::print_op(str); }
   bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
-  virtual bool binary() const { return test(cmp_charset->state & MY_CS_BINSORT); }
+  virtual bool binary() const 
+  { return test(cmp_collation.collation->state & MY_CS_BINSORT); }
 
   static Item_bool_func2* eq_creator(Item *a, Item *b);
   static Item_bool_func2* ne_creator(Item *a, Item *b);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 170260c6819a42859138555a8f71644eb11bed15..d0362ea9369d428881533843b6a63a93df3debe8 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -867,9 +867,8 @@ void Item_func_min_max::fix_length_and_dec()
       maybe_null=0;
     cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
     if (i==0)
-      set_charset(*args[i]);
-    else if (set_charset(charset(), derivation(), 
-			args[i]->charset(), args[i]->derivation()))
+      collation.set(args[0]->collation);
+    if (collation.aggregate(args[i]->collation))
     {
       my_coll_agg_error(collation, args[i]->collation, func_name());
       break;
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 23df49c81bec9f412bbe068e424e874a533338f3..1c7704567930a65e6f86ea96560f706c35952f0d 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -324,12 +324,11 @@ void Item_func_concat::fix_length_and_dec()
   bool first_coll= 1;
   max_length=0;
 
-  set_charset(*args[0]);
+  collation.set(args[0]->collation);
   for (uint i=0 ; i < arg_count ; i++)
   {
     max_length+=args[i]->max_length;
-    if (set_charset(charset(), derivation(),
-		args[i]->charset(), args[i]->derivation()))
+    if (collation.aggregate(args[i]->collation))
     {
       my_coll_agg_error(collation, args[i]->collation, func_name());
       break;
@@ -627,13 +626,12 @@ void Item_func_concat_ws::split_sum_func(Item **ref_pointer_array,
 
 void Item_func_concat_ws::fix_length_and_dec()
 {
-  set_charset(*separator);
+  collation.set(separator->collation);
   max_length=separator->max_length*(arg_count-1);
   for (uint i=0 ; i < arg_count ; i++)
   {
     max_length+=args[i]->max_length;
-    if (set_charset(charset(), derivation(),
-		    args[i]->charset(), args[i]->derivation()))
+    if (collation.aggregate(args[i]->collation))
     {
       my_coll_agg_error(collation, args[i]->collation, func_name());
       break;
@@ -828,12 +826,11 @@ void Item_func_replace::fix_length_and_dec()
     max_length=MAX_BLOB_WIDTH;
     maybe_null=1;
   }
-  set_charset(*args[0]);
   
+  collation.set(args[0]->collation);
   for (i=1; i<3; i++)
   {
-    if (set_charset(charset(), derivation(),
-        args[i]->charset(), args[i]->derivation()))
+    if (collation.aggregate(args[i]->collation))
     {
       my_coll_agg_error(collation, args[i]->collation, func_name());
       break;
@@ -875,10 +872,10 @@ null:
 
 void Item_func_insert::fix_length_and_dec()
 {
-  if (set_charset(args[0]->charset(), args[0]->derivation(),
-      		  args[3]->charset(), args[3]->derivation()))
+  if (collation.set(args[0]->collation, args[3]->collation))
   {
       my_coll_agg_error(args[0]->collation, args[3]->collation, func_name());
+      return;
   }
   max_length=args[0]->max_length+args[3]->max_length;
   if (max_length > MAX_BLOB_WIDTH)
@@ -1316,13 +1313,12 @@ void Item_func_trim::fix_length_and_dec()
   max_length= args[0]->max_length;
   if (arg_count == 1)
   {
-    set_charset(*args[0]);
+    collation.set(args[0]->collation);
     remove.set_charset(charset());
     remove.set_ascii(" ",1);
   }
   else
-  if (set_charset(args[1]->charset(), args[1]->derivation(),
-		  args[0]->charset(), args[0]->derivation()))
+  if (collation.set(args[1]->collation, args[0]->collation))
   {
     my_coll_agg_error(args[1]->collation, args[0]->collation, func_name());
   }
@@ -1668,11 +1664,10 @@ void Item_func_elt::fix_length_and_dec()
     set_if_bigger(max_length,args[i]->max_length);
     set_if_bigger(decimals,args[i]->decimals);
     if (i == 0)
-      set_charset(*args[0]);
+      collation.set(args[0]->collation);
     else
     {
-      if (set_charset(charset(), derivation(),
-		      args[i]->charset(), args[i]->derivation()))
+      if (collation.aggregate(args[i]->collation))
       {
         my_coll_agg_error(collation, args[i]->collation, func_name());
         break;
@@ -1770,12 +1765,11 @@ void Item_func_make_set::split_sum_func(Item **ref_pointer_array,
 void Item_func_make_set::fix_length_and_dec()
 {
   max_length=arg_count-1;
-  set_charset(*args[0]);
+  collation.set(args[0]->collation);
   for (uint i=0 ; i < arg_count ; i++)
   {
     max_length+=args[i]->max_length;
-    if (set_charset(charset(), derivation(),
-		    args[i]->charset(), args[i]->derivation()))
+    if (collation.aggregate(args[i]->collation))
     {
       my_coll_agg_error(collation, args[i]->collation, func_name());
       break;
@@ -1963,10 +1957,10 @@ err:
 
 void Item_func_rpad::fix_length_and_dec()
 {
-  if (set_charset(args[0]->charset(), args[0]->derivation(),
- 		  args[2]->charset(), args[2]->derivation()))
+  if (collation.set(args[0]->collation, args[2]->collation))
   {
     my_coll_agg_error(args[0]->collation, args[2]->collation, func_name());
+    return;
   }
   
   if (args[1]->const_item())
@@ -2029,10 +2023,10 @@ String *Item_func_rpad::val_str(String *str)
 
 void Item_func_lpad::fix_length_and_dec()
 {
-  if (set_charset(args[0]->charset(), args[0]->derivation(),
- 		  args[2]->charset(), args[2]->derivation()))
+  if (collation.set(args[0]->collation, args[2]->collation))
   {
     my_coll_agg_error(args[0]->collation, args[2]->collation, func_name());
+    return;
   }
   
   if (args[1]->const_item())
@@ -2152,9 +2146,8 @@ String *Item_func_conv_charset::val_str(String *str)
 
 void Item_func_conv_charset::fix_length_and_dec()
 {
-  set_charset(conv_charset);
-  max_length = args[0]->max_length*conv_charset->mbmaxlen;
   set_charset(conv_charset, DERIVATION_IMPLICIT);
+  max_length = args[0]->max_length*conv_charset->mbmaxlen;
 }
 
 
@@ -2449,11 +2442,10 @@ void Item_func_export_set::fix_length_and_dec()
   uint sep_length=(arg_count > 3 ? args[3]->max_length : 1);
   max_length=length*64+sep_length*63;
 
-  set_charset(*args[1]);
+  collation.set(args[1]->collation);
   for (i=2 ; i < 4 && i < arg_count ; i++)
   {
-    if (set_charset(charset(), derivation(),
-		    args[i]->charset(), args[i]->derivation()))
+    if (collation.aggregate(args[i]->collation))
     {
       my_coll_agg_error(collation, args[i]->collation, func_name());
       break;