diff --git a/sql/item_sum.h b/sql/item_sum.h
index d53d8d861ae886381ca26779e39b8c57e18d1736..a1a232c43081abbdf1f187205321bd3520bc384f 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -27,9 +27,9 @@ class Item_sum :public Item_result_field
 {
 public:
   enum Sumfunctype
-  { COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
-    MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
-    UDF_SUM_FUNC, GROUP_CONCAT_FUNC
+  { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
+    AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC,
+    VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC
   };
 
   Item **args, *tmp_args[2];
@@ -66,6 +66,9 @@ class Item_sum :public Item_result_field
     a temporary table. Similar to reset(), but must also store value in
     result_field. Like reset() it is supposed to reset start value to
     default.
+    This set of methods (reult_field(), reset_field, update_field()) of
+    Item_sum is used only if quick_group is not null. Otherwise
+    copy_or_same() is used to obtain a copy of this item.
   */
   virtual void reset_field()=0;
   /*
@@ -76,9 +79,24 @@ class Item_sum :public Item_result_field
   virtual void update_field()=0;
   virtual bool keep_field_type(void) const { return 0; }
   virtual void fix_length_and_dec() { maybe_null=1; null_value=1; }
-  virtual const char *func_name() const { return "?"; }
+  /*
+    This method is used for debug purposes to print the name of an
+    item to the debug log. The second use of this method is as
+    a helper function of print(), where it is applicable.
+    To suit both goals it should return a meaningful,
+    distinguishable and sintactically correct string.  This method
+    should not be used for runtime type identification, use enum
+    {Sum}Functype and Item_func::functype()/Item_sum::sum_func()
+    instead.
+
+    NOTE: for Items inherited from Item_sum, func_name() return part of
+    function name till first argument (including '(') to make difference in
+    names for functions with 'distinct' clause and without 'distinct' and
+    also to make printing of items inherited from Item_sum uniform.
+  */
+  virtual const char *func_name() const= 0;
   virtual Item *result_item(Field *field)
-    { return new Item_field(field);}
+    { return new Item_field(field); }
   table_map used_tables() const { return ~(table_map) 0; } /* Not used */
   bool const_item() const { return 0; }
   bool is_null() { return null_value; }
@@ -90,7 +108,8 @@ class Item_sum :public Item_result_field
   virtual bool setup(THD *thd) {return 0;}
   virtual void make_unique() {}
   Item *get_tmp_table_item(THD *thd);
-
+  virtual Field *create_tmp_field(bool group, TABLE *table,
+                                  uint convert_blob_length);
   bool walk (Item_processor processor, byte *argument);
 };
 
@@ -103,10 +122,14 @@ class Item_sum_num :public Item_sum
   Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {}
   Item_sum_num(List<Item> &list) :Item_sum(list) {}
   Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {}
-  bool fix_fields(THD *, TABLE_LIST *, Item **);
+  bool fix_fields(THD *, Item **);
   longlong val_int()
-    { DBUG_ASSERT(fixed == 1); return (longlong) val(); } /* Real as default */
+  {
+    DBUG_ASSERT(fixed == 1);
+    return (longlong) val_real();             /* Real as default */
+  }
   String *val_str(String*str);
+  my_decimal *val_decimal(my_decimal *);
   void reset_field();
 };
 
@@ -117,8 +140,9 @@ class Item_sum_int :public Item_sum_num
   Item_sum_int(Item *item_par) :Item_sum_num(item_par) {}
   Item_sum_int(List<Item> &list) :Item_sum_num(list) {}
   Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {}
-  double val() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+  double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
   String *val_str(String*str);
+  my_decimal *val_decimal(my_decimal *);
   enum Item_result result_type () const { return INT_RESULT; }
   void fix_length_and_dec()
   { decimals=0; max_length=21; maybe_null=null_value=0; }
@@ -127,25 +151,115 @@ class Item_sum_int :public Item_sum_num
 
 class Item_sum_sum :public Item_sum_num
 {
+protected:
+  Item_result hybrid_type;
   double sum;
-  void fix_length_and_dec() { maybe_null=null_value=1; }
+  my_decimal dec_buffs[2];
+  uint curr_dec_buff;
+  void fix_length_and_dec();
 
-  public:
-  Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {}
-  Item_sum_sum(THD *thd, Item_sum_sum *item) 
-    :Item_sum_num(thd, item), sum(item->sum) {}
+public:
+  Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {}
+  Item_sum_sum(THD *thd, Item_sum_sum *item);
   enum Sumfunctype sum_func () const {return SUM_FUNC;}
   void clear();
   bool add();
-  double val();
+  double val_real();
+  longlong val_int();
+  String *val_str(String*str);
+  my_decimal *val_decimal(my_decimal *);
+  enum Item_result result_type () const { return hybrid_type; }
   void reset_field();
   void update_field();
   void no_rows_in_result() {}
-  const char *func_name() const { return "sum"; }
+  const char *func_name() const { return "sum("; }
   Item *copy_or_same(THD* thd);
 };
 
 
+
+/* Common class for SUM(DISTINCT), AVG(DISTINCT) */
+
+class Unique;
+
+class Item_sum_distinct :public Item_sum_num
+{
+protected:
+  /* storage for the summation result */
+  ulonglong count;
+  Hybrid_type val;
+  /* storage for unique elements */
+  Unique *tree;
+  TABLE *table;
+  enum enum_field_types table_field_type;
+  uint tree_key_length;
+protected:
+  Item_sum_distinct(THD *thd, Item_sum_distinct *item);
+public:
+  Item_sum_distinct(Item *item_par);
+  ~Item_sum_distinct();
+
+  bool setup(THD *thd);
+  void clear();
+  void cleanup();
+  bool add();
+  double val_real();
+  my_decimal *val_decimal(my_decimal *);
+  longlong val_int();
+  String *val_str(String *str);
+
+  /* XXX: does it need make_unique? */
+
+  enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
+  void reset_field() {} // not used
+  void update_field() {} // not used
+  virtual void no_rows_in_result() {}
+  void fix_length_and_dec();
+  enum Item_result result_type () const { return val.traits->type(); }
+  virtual void calculate_val_and_count();
+  virtual bool unique_walk_function(void *elem);
+};
+
+
+/*
+  Item_sum_sum_distinct - implementation of SUM(DISTINCT expr).
+  See also: MySQL manual, chapter 'Adding New Functions To MySQL'
+  and comments in item_sum.cc.
+*/
+
+class Item_sum_sum_distinct :public Item_sum_distinct
+{
+private:
+  Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item)
+    :Item_sum_distinct(thd, item) {}
+public:
+  Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {}
+
+  enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
+  const char *func_name() const { return "sum(distinct "; }
+  Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); }
+};
+
+
+/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */
+
+class Item_sum_avg_distinct: public Item_sum_distinct
+{
+private:
+  Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original)
+    :Item_sum_distinct(thd, original) {}
+public:
+  uint prec_increment;
+  Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {}
+
+  void fix_length_and_dec();
+  virtual void calculate_val_and_count();
+  enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; }
+  const char *func_name() const { return "avg(distinct "; }
+  Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); }
+};
+
+
 class Item_sum_count :public Item_sum_int
 {
   longlong count;
@@ -170,7 +284,7 @@ class Item_sum_count :public Item_sum_int
   void reset_field();
   void cleanup();
   void update_field();
-  const char *func_name() const { return "count"; }
+  const char *func_name() const { return "count("; }
   Item *copy_or_same(THD* thd);
 };
 
@@ -180,80 +294,55 @@ class TMP_TABLE_PARAM;
 class Item_sum_count_distinct :public Item_sum_int
 {
   TABLE *table;
-  table_map used_table_cache;
   uint32 *field_lengths;
   TMP_TABLE_PARAM *tmp_table_param;
-  TREE tree_base;
-  TREE *tree;
+  /*
+    If there are no blobs, we can use a tree, which
+    is faster than heap table. In that case, we still use the table
+    to help get things set up, but we insert nothing in it
+  */
+  Unique *tree;
   /*
     Following is 0 normal object and pointer to original one for copy 
     (to correctly free resources)
   */
   Item_sum_count_distinct *original;
+  uint tree_key_length;
 
-  uint key_length;
-  CHARSET_INFO *key_charset;
-  
-  /*
-    Calculated based on max_heap_table_size. If reached,
-    walk the tree and dump it into MyISAM table
-  */
-  uint max_elements_in_tree;
-
-  /*
-    The first few bytes of record ( at least one)
-    are just markers for deleted and NULLs. We want to skip them since
-    they will just bloat the tree without providing any valuable info
-  */
-  int rec_offset;
 
-  /*
-    If there are no blobs, we can use a tree, which
-    is faster than heap table. In that case, we still use the table
-    to help get things set up, but we insert nothing in it
-  */
-  bool use_tree;
   bool always_null;		// Set to 1 if the result is always NULL
 
-  int tree_to_myisam();
 
   friend int composite_key_cmp(void* arg, byte* key1, byte* key2);
   friend int simple_str_key_cmp(void* arg, byte* key1, byte* key2);
-  friend int simple_raw_key_cmp(void* arg, byte* key1, byte* key2);
-  friend int dump_leaf(byte* key, uint32 count __attribute__((unused)),
-		       Item_sum_count_distinct* item);
 
-  public:
+public:
   Item_sum_count_distinct(List<Item> &list)
-    :Item_sum_int(list), table(0), used_table_cache(~(table_map) 0),
-     tmp_table_param(0), tree(&tree_base), original(0), use_tree(0),
-     always_null(0)
+    :Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0),
+     tree(0), original(0), always_null(FALSE)
   { quick_group= 0; }
   Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item)
     :Item_sum_int(thd, item), table(item->table),
-     used_table_cache(item->used_table_cache),
      field_lengths(item->field_lengths),
      tmp_table_param(item->tmp_table_param),
-     tree(item->tree), original(item), key_length(item->key_length),
-     max_elements_in_tree(item->max_elements_in_tree),
-     rec_offset(item->rec_offset), use_tree(item->use_tree),
+     tree(item->tree), original(item), tree_key_length(item->tree_key_length),
      always_null(item->always_null)
   {}
+  ~Item_sum_count_distinct();
+
   void cleanup();
 
-  table_map used_tables() const { return used_table_cache; }
   enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; }
   void clear();
   bool add();
   longlong val_int();
   void reset_field() { return ;}		// Never called
   void update_field() { return ; }		// Never called
-  const char *func_name() const { return "count_distinct"; }
+  const char *func_name() const { return "count(distinct "; }
   bool setup(THD *thd);
   void make_unique();
   Item *copy_or_same(THD* thd);
   void no_rows_in_result() {}
-  void print(String *str);
 };
 
 
@@ -265,43 +354,55 @@ class Item_avg_field :public Item_result_field
 {
 public:
   Field *field;
-  Item_avg_field(Item_sum_avg *item);
+  Item_result hybrid_type;
+  uint f_precision, f_scale, dec_bin_size;
+  uint prec_increment;
+  Item_avg_field(Item_result res_type, Item_sum_avg *item);
   enum Type type() const { return FIELD_AVG_ITEM; }
-  double val();
-  longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val(); }
+  double val_real();
+  longlong val_int();
+  my_decimal *val_decimal(my_decimal *);
   bool is_null() { (void) val_int(); return null_value; }
   String *val_str(String*);
-  enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
+  enum_field_types field_type() const
+  {
+    return hybrid_type == DECIMAL_RESULT ?
+      MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
+  }
   void fix_length_and_dec() {}
+  enum Item_result result_type () const { return hybrid_type; }
 };
 
 
-class Item_sum_avg :public Item_sum_num
+class Item_sum_avg :public Item_sum_sum
 {
-  void fix_length_and_dec()
-  {
-    decimals=min(decimals+4, NOT_FIXED_DEC);
-    maybe_null=1;
-  }
-
-  double sum;
+public:
   ulonglong count;
+  uint prec_increment;
+  uint f_precision, f_scale, dec_bin_size;
 
-  public:
-  Item_sum_avg(Item *item_par) :Item_sum_num(item_par), sum(0.0), count(0) {}
+  Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {}
   Item_sum_avg(THD *thd, Item_sum_avg *item)
-    :Item_sum_num(thd, item), sum(item->sum), count(item->count) {}
+    :Item_sum_sum(thd, item), count(item->count),
+    prec_increment(item->prec_increment) {}
+
+  void fix_length_and_dec();
   enum Sumfunctype sum_func () const {return AVG_FUNC;}
   void clear();
   bool add();
-  double val();
+  double val_real();
+  // In SPs we might force the "wrong" type with select into a declare variable
+  longlong val_int() { return (longlong)val_real(); }
+  my_decimal *val_decimal(my_decimal *);
+  String *val_str(String *str);
   void reset_field();
   void update_field();
   Item *result_item(Field *field)
-  { return new Item_avg_field(this); }
+  { return new Item_avg_field(hybrid_type, this); }
   void no_rows_in_result() {}
-  const char *func_name() const { return "avg"; }
+  const char *func_name() const { return "avg("; }
   Item *copy_or_same(THD* thd);
+  Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
 };
 
 class Item_sum_variance;
@@ -310,14 +411,27 @@ class Item_variance_field :public Item_result_field
 {
 public:
   Field *field;
+  Item_result hybrid_type;
+  uint f_precision0, f_scale0;
+  uint f_precision1, f_scale1;
+  uint dec_bin_size0, dec_bin_size1;
+  uint sample;
+  uint prec_increment;
   Item_variance_field(Item_sum_variance *item);
   enum Type type() const {return FIELD_VARIANCE_ITEM; }
-  double val();
-  longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val(); }
+  double val_real();
+  longlong val_int()
+  { /* can't be fix_fields()ed */ return (longlong) val_real(); }
   String *val_str(String*);
+  my_decimal *val_decimal(my_decimal *);
   bool is_null() { (void) val_int(); return null_value; }
-  enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
+  enum_field_types field_type() const
+  {
+    return hybrid_type == DECIMAL_RESULT ?
+      MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
+  }
   void fix_length_and_dec() {}
+  enum Item_result result_type () const { return hybrid_type; }
 };
 
 
@@ -335,30 +449,39 @@ class Item_variance_field :public Item_result_field
 
 class Item_sum_variance : public Item_sum_num
 {
+  void fix_length_and_dec();
+
+public:
+  Item_result hybrid_type;
   double sum, sum_sqr;
+  my_decimal dec_sum[2], dec_sqr[2];
+  int cur_dec;
   ulonglong count;
-  void fix_length_and_dec()
-  {
-    decimals=min(decimals+4, NOT_FIXED_DEC);
-    maybe_null=1;
-  }
-
-  public:
-  Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {}
-  Item_sum_variance(THD *thd, Item_sum_variance *item):
-    Item_sum_num(thd, item), sum(item->sum), sum_sqr(item->sum_sqr),
-    count(item->count) {}
+  uint f_precision0, f_scale0;
+  uint f_precision1, f_scale1;
+  uint dec_bin_size0, dec_bin_size1;
+  uint sample;
+  uint prec_increment;
+
+  Item_sum_variance(Item *item_par, uint sample_arg) :Item_sum_num(item_par),
+    hybrid_type(REAL_RESULT), cur_dec(0), count(0), sample(sample_arg)
+    {}
+  Item_sum_variance(THD *thd, Item_sum_variance *item);
   enum Sumfunctype sum_func () const { return VARIANCE_FUNC; }
   void clear();
   bool add();
-  double val();
+  double val_real();
+  my_decimal *val_decimal(my_decimal *);
   void reset_field();
   void update_field();
   Item *result_item(Field *field)
   { return new Item_variance_field(this); }
   void no_rows_in_result() {}
-  const char *func_name() const { return "variance"; }
+  const char *func_name() const
+    { return sample ? "var_samp(" : "variance("; }
   Item *copy_or_same(THD* thd);
+  Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
+  enum Item_result result_type () const { return hybrid_type; }
 };
 
 class Item_sum_std;
@@ -368,7 +491,10 @@ class Item_std_field :public Item_variance_field
 public:
   Item_std_field(Item_sum_std *item);
   enum Type type() const { return FIELD_STD_ITEM; }
-  double val();
+  double val_real();
+  my_decimal *val_decimal(my_decimal *);
+  enum Item_result result_type () const { return REAL_RESULT; }
+  enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;}
 };
 
 /*
@@ -378,26 +504,30 @@ class Item_std_field :public Item_variance_field
 class Item_sum_std :public Item_sum_variance
 {
   public:
-  Item_sum_std(Item *item_par) :Item_sum_variance(item_par) {}
+  Item_sum_std(Item *item_par, uint sample_arg)
+    :Item_sum_variance(item_par, sample_arg) {}
   Item_sum_std(THD *thd, Item_sum_std *item)
     :Item_sum_variance(thd, item)
     {}
   enum Sumfunctype sum_func () const { return STD_FUNC; }
-  double val();
+  double val_real();
   Item *result_item(Field *field)
     { return new Item_std_field(this); }
-  const char *func_name() const { return "std"; }
+  const char *func_name() const { return "std("; }
   Item *copy_or_same(THD* thd);
+  enum Item_result result_type () const { return REAL_RESULT; }
+  enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;}
 };
 
 // This class is a string or number function depending on num_func
 
 class Item_sum_hybrid :public Item_sum
 {
- protected:
+protected:
   String value,tmp_value;
   double sum;
   longlong sum_int;
+  my_decimal sum_dec;
   Item_result hybrid_type;
   enum_field_types hybrid_field_type;
   int cmp_sign;
@@ -408,22 +538,18 @@ class Item_sum_hybrid :public Item_sum
   Item_sum_hybrid(Item *item_par,int sign)
     :Item_sum(item_par), sum(0.0), sum_int(0),
     hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG),
-    cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE)
-  { collation.set(&my_charset_bin); }
-  Item_sum_hybrid(THD *thd, Item_sum_hybrid *item):
-    Item_sum(thd, item), value(item->value),
-    sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type),
-    hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign), 
-    used_table_cache(item->used_table_cache),
+    cmp_sign(sign), used_table_cache(~(table_map) 0),
     was_values(TRUE)
-    { collation.set(item->collation); }
-  bool fix_fields(THD *, TABLE_LIST *, Item **);
+  { collation.set(&my_charset_bin); }
+  Item_sum_hybrid(THD *thd, Item_sum_hybrid *item);
+  bool fix_fields(THD *, Item **);
   table_map used_tables() const { return used_table_cache; }
   bool const_item() const { return !used_table_cache; }
 
   void clear();
-  double val();
+  double val_real();
   longlong val_int();
+  my_decimal *val_decimal(my_decimal *);
   void reset_field();
   String *val_str(String *);
   void make_const() { used_table_cache=0; }
@@ -434,9 +560,12 @@ class Item_sum_hybrid :public Item_sum
   void min_max_update_str_field();
   void min_max_update_real_field();
   void min_max_update_int_field();
+  void min_max_update_decimal_field();
   void cleanup();
   bool any_value() { return was_values; }
   void no_rows_in_result();
+  Field *create_tmp_field(bool group, TABLE *table,
+			  uint convert_blob_length);
 };
 
 
@@ -448,7 +577,7 @@ class Item_sum_min :public Item_sum_hybrid
   enum Sumfunctype sum_func () const {return MIN_FUNC;}
 
   bool add();
-  const char *func_name() const { return "min"; }
+  const char *func_name() const { return "min("; }
   Item *copy_or_same(THD* thd);
 };
 
@@ -461,7 +590,7 @@ class Item_sum_max :public Item_sum_hybrid
   enum Sumfunctype sum_func () const {return MAX_FUNC;}
 
   bool add();
-  const char *func_name() const { return "max"; }
+  const char *func_name() const { return "max("; }
   Item *copy_or_same(THD* thd);
 };
 
@@ -482,7 +611,7 @@ class Item_sum_bit :public Item_sum_int
   void reset_field();
   void update_field();
   void fix_length_and_dec()
-  { decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; }
+  { decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; }
 };
 
 
@@ -492,7 +621,7 @@ class Item_sum_or :public Item_sum_bit
   Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
   Item_sum_or(THD *thd, Item_sum_or *item) :Item_sum_bit(thd, item) {}
   bool add();
-  const char *func_name() const { return "bit_or"; }
+  const char *func_name() const { return "bit_or("; }
   Item *copy_or_same(THD* thd);
 };
 
@@ -503,7 +632,7 @@ class Item_sum_and :public Item_sum_bit
   Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ULONGLONG_MAX) {}
   Item_sum_and(THD *thd, Item_sum_and *item) :Item_sum_bit(thd, item) {}
   bool add();
-  const char *func_name() const { return "bit_and"; }
+  const char *func_name() const { return "bit_and("; }
   Item *copy_or_same(THD* thd);
 };
 
@@ -513,7 +642,7 @@ class Item_sum_xor :public Item_sum_bit
   Item_sum_xor(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
   Item_sum_xor(THD *thd, Item_sum_xor *item) :Item_sum_bit(thd, item) {}
   bool add();
-  const char *func_name() const { return "bit_xor"; }
+  const char *func_name() const { return "bit_xor("; }
   Item *copy_or_same(THD* thd);
 };
 
@@ -530,18 +659,21 @@ class Item_udf_sum : public Item_sum
   udf_handler udf;
 
 public:
-  Item_udf_sum(udf_func *udf_arg) :Item_sum(), udf(udf_arg) { quick_group=0;}
-  Item_udf_sum( udf_func *udf_arg, List<Item> &list )
-    :Item_sum( list ), udf(udf_arg)
+  Item_udf_sum(udf_func *udf_arg)
+    :Item_sum(), udf(udf_arg)
+  { quick_group=0; }
+  Item_udf_sum(udf_func *udf_arg, List<Item> &list)
+    :Item_sum(list), udf(udf_arg)
   { quick_group=0;}
   Item_udf_sum(THD *thd, Item_udf_sum *item)
-    :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; }
+    :Item_sum(thd, item), udf(item->udf)
+  { udf.not_original= TRUE; }
   const char *func_name() const { return udf.name(); }
-  bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+  bool fix_fields(THD *thd, Item **ref)
   {
     DBUG_ASSERT(fixed == 0);
     fixed= 1;
-    return udf.fix_fields(thd,tables,this,this->arg_count,this->args);
+    return udf.fix_fields(thd, this, this->arg_count, this->args);
   }
   enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
   virtual bool have_field_update(void) const { return 0; }
@@ -551,21 +683,27 @@ class Item_udf_sum : public Item_sum
   void reset_field() {};
   void update_field() {};
   void cleanup();
+  void print(String *str);
 };
 
 
 class Item_sum_udf_float :public Item_udf_sum
 {
  public:
-  Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+  Item_sum_udf_float(udf_func *udf_arg)
+    :Item_udf_sum(udf_arg) {}
   Item_sum_udf_float(udf_func *udf_arg, List<Item> &list)
-    :Item_udf_sum(udf_arg,list) {}
+    :Item_udf_sum(udf_arg, list) {}
   Item_sum_udf_float(THD *thd, Item_sum_udf_float *item)
     :Item_udf_sum(thd, item) {}
   longlong val_int()
-    { DBUG_ASSERT(fixed == 1); return (longlong) Item_sum_udf_float::val(); }
-  double val();
+  {
+    DBUG_ASSERT(fixed == 1);
+    return (longlong) Item_sum_udf_float::val_real();
+  }
+  double val_real();
   String *val_str(String*str);
+  my_decimal *val_decimal(my_decimal *);
   void fix_length_and_dec() { fix_num_length_and_dec(); }
   Item *copy_or_same(THD* thd);
 };
@@ -574,15 +712,17 @@ class Item_sum_udf_float :public Item_udf_sum
 class Item_sum_udf_int :public Item_udf_sum
 {
 public:
-  Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+  Item_sum_udf_int(udf_func *udf_arg)
+    :Item_udf_sum(udf_arg) {}
   Item_sum_udf_int(udf_func *udf_arg, List<Item> &list)
-    :Item_udf_sum(udf_arg,list) {}
+    :Item_udf_sum(udf_arg, list) {}
   Item_sum_udf_int(THD *thd, Item_sum_udf_int *item)
     :Item_udf_sum(thd, item) {}
   longlong val_int();
-  double val()
+  double val_real()
     { DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); }
   String *val_str(String*str);
+  my_decimal *val_decimal(my_decimal *);
   enum Item_result result_type () const { return INT_RESULT; }
   void fix_length_and_dec() { decimals=0; max_length=21; }
   Item *copy_or_same(THD* thd);
@@ -592,43 +732,72 @@ class Item_sum_udf_int :public Item_udf_sum
 class Item_sum_udf_str :public Item_udf_sum
 {
 public:
-  Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+  Item_sum_udf_str(udf_func *udf_arg)
+    :Item_udf_sum(udf_arg) {}
   Item_sum_udf_str(udf_func *udf_arg, List<Item> &list)
     :Item_udf_sum(udf_arg,list) {}
   Item_sum_udf_str(THD *thd, Item_sum_udf_str *item)
     :Item_udf_sum(thd, item) {}
   String *val_str(String *);
-  double val()
+  double val_real()
   {
-    int err;
+    int err_not_used;
     char *end_not_used;
     String *res;
     res=val_str(&str_value);
     return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(),
-			    &end_not_used, &err) : 0.0;
+			    &end_not_used, &err_not_used) : 0.0;
   }
   longlong val_int()
   {
-    int err;
-    String *res;  res=val_str(&str_value);
-    return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err) : (longlong) 0;
+    int err_not_used;
+    char *end;
+    String *res;
+    CHARSET_INFO *cs;
+
+    if (!(res= val_str(&str_value)))
+      return 0;                                 /* Null value */
+    cs= res->charset();
+    end= (char*) res->ptr()+res->length();
+    return cs->cset->strtoll10(cs, res->ptr(), &end, &err_not_used);
   }
+  my_decimal *val_decimal(my_decimal *dec);
   enum Item_result result_type () const { return STRING_RESULT; }
   void fix_length_and_dec();
   Item *copy_or_same(THD* thd);
 };
 
+
+class Item_sum_udf_decimal :public Item_udf_sum
+{
+public:
+  Item_sum_udf_decimal(udf_func *udf_arg)
+    :Item_udf_sum(udf_arg) {}
+  Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list)
+    :Item_udf_sum(udf_arg, list) {}
+  Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item)
+    :Item_udf_sum(thd, item) {}
+  String *val_str(String *);
+  double val_real();
+  longlong val_int();
+  my_decimal *val_decimal(my_decimal *);
+  enum Item_result result_type () const { return DECIMAL_RESULT; }
+  void fix_length_and_dec() { fix_num_length_and_dec(); }
+  Item *copy_or_same(THD* thd);
+};
+
 #else /* Dummy functions to get sql_yacc.cc compiled */
 
 class Item_sum_udf_float :public Item_sum_num
 {
  public:
-  Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {}
+  Item_sum_udf_float(udf_func *udf_arg)
+    :Item_sum_num() {}
   Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
   Item_sum_udf_float(THD *thd, Item_sum_udf_float *item)
     :Item_sum_num(thd, item) {}
   enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
-  double val() { DBUG_ASSERT(fixed == 1); return 0.0; }
+  double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
   void clear() {}
   bool add() { return 0; }  
   void update_field() {}
@@ -638,29 +807,50 @@ class Item_sum_udf_float :public Item_sum_num
 class Item_sum_udf_int :public Item_sum_num
 {
 public:
-  Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {}
+  Item_sum_udf_int(udf_func *udf_arg)
+    :Item_sum_num() {}
   Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
   Item_sum_udf_int(THD *thd, Item_sum_udf_int *item)
     :Item_sum_num(thd, item) {}
   enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
   longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; }
-  double val() { DBUG_ASSERT(fixed == 1); return 0; }
+  double val_real() { DBUG_ASSERT(fixed == 1); return 0; }
   void clear() {}
   bool add() { return 0; }  
   void update_field() {}
 };
 
 
+class Item_sum_udf_decimal :public Item_sum_num
+{
+ public:
+  Item_sum_udf_decimal(udf_func *udf_arg)
+    :Item_sum_num() {}
+  Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list)
+    :Item_sum_num() {}
+  Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item)
+    :Item_sum_num(thd, item) {}
+  enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
+  double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
+  my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; }
+  void clear() {}
+  bool add() { return 0; }
+  void update_field() {}
+};
+
+
 class Item_sum_udf_str :public Item_sum_num
 {
 public:
-  Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {}
-  Item_sum_udf_str(udf_func *udf_arg, List<Item> &list)  :Item_sum_num() {}
+  Item_sum_udf_str(udf_func *udf_arg)
+    :Item_sum_num() {}
+  Item_sum_udf_str(udf_func *udf_arg, List<Item> &list)
+    :Item_sum_num() {}
   Item_sum_udf_str(THD *thd, Item_sum_udf_str *item)
     :Item_sum_num(thd, item) {}
   String *val_str(String *)
     { DBUG_ASSERT(fixed == 1); null_value=1; return 0; }
-  double val() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; }
+  double val_real() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; }
   longlong val_int() { DBUG_ASSERT(fixed == 1); null_value=1; return 0; }
   enum Item_result result_type () const { return STRING_RESULT; }
   void fix_length_and_dec() { maybe_null=1; max_length=0; }
@@ -676,15 +866,26 @@ class MYSQL_ERROR;
 
 class Item_func_group_concat : public Item_sum
 {
-  THD *item_thd;
   TMP_TABLE_PARAM *tmp_table_param;
-  uint max_elements_in_tree;
   MYSQL_ERROR *warning;
-  uint key_length;
-  bool tree_mode;
+  String result;
+  String *separator;
+  TREE tree_base;
+  TREE *tree;
+  TABLE *table;
+  ORDER **order;
+  Name_resolution_context *context;
+  uint arg_count_order;               // total count of ORDER BY items
+  uint arg_count_field;               // count of arguments
+  uint count_cut_values;
   bool distinct;
   bool warning_for_row;
   bool always_null;
+  /*
+    Following is 0 normal object and pointer to original one for copy
+    (to correctly free resources)
+  */
+  Item_func_group_concat *original;
 
   friend int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
 					      byte* key2);
@@ -693,7 +894,8 @@ class Item_func_group_concat : public Item_sum
   friend int group_concat_key_cmp_with_distinct_and_order(void* arg,
 							byte* key1,
 							byte* key2);
-  friend int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
+  friend int dump_leaf_key(byte* key,
+                           element_count count __attribute__((unused)),
 			   Item_func_group_concat *group_concat_item);
 
  public:
@@ -719,8 +921,13 @@ class Item_func_group_concat : public Item_sum
   Item_func_group_concat(bool is_distinct,List<Item> *is_select,
                          SQL_LIST *is_order,String *is_separator);
 			 
+public:
+  Item_func_group_concat(Name_resolution_context *context_arg,
+                         bool is_distinct, List<Item> *is_select,
+                         SQL_LIST *is_order, String *is_separator);
+
   Item_func_group_concat(THD *thd, Item_func_group_concat *item);
-  ~Item_func_group_concat();
+  ~Item_func_group_concat() {}
   void cleanup();
 
   enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;}
@@ -728,12 +935,12 @@ class Item_func_group_concat : public Item_sum
   virtual Item_result result_type () const { return STRING_RESULT; }
   void clear();
   bool add();
-  void reset_field();
-  bool fix_fields(THD *, TABLE_LIST *, Item **);
+  void reset_field() {}                         // not used
+  void update_field() {}                        // not used
+  bool fix_fields(THD *,Item **);
   bool setup(THD *thd);
   void make_unique();
-  virtual void update_field() {}
-  double val()
+  double val_real()
   {
     String *res;  res=val_str(&str_value);
     return res ? my_atof(res->c_ptr()) : 0.0;
@@ -748,8 +955,14 @@ class Item_func_group_concat : public Item_sum
     end_ptr= (char*) res->ptr()+ res->length();
     return my_strtoll10(res->ptr(), &end_ptr, &error);
   }
+  my_decimal *val_decimal(my_decimal *decimal_value)
+  {
+    return val_decimal_from_string(decimal_value);
+  }
   String* val_str(String* str);
   Item *copy_or_same(THD* thd);
   void no_rows_in_result() {}
   void print(String *str);
+  virtual bool change_context_processor(byte *cntx)
+    { context= (Name_resolution_context *)cntx; return FALSE; }
 };