Commit 1534ed8e authored by unknown's avatar unknown
Browse files

WL#926 "SUM(DISTINCT) and AVG(DISTINCT)": improvement of SUM(DISTINCT) and

 implementation of AVG(DISTINCT) which utilizes the approach with Fields.
The patch implemented in October is portede to the up-to-date tree 
containing DECIMAL type.
Tests for AVG(DISTINCT) (although there is not much to test provided
that SUM(DISTINCT) works), cleanups for COUNT(DISTINCT) and GROUP_CONCAT()
will follow in another changeset.


sql/field.cc:
  A handy way to init create_field used for use with virtual tmp tables.
  Feel free to extend it for your own needs.
sql/field.h:
  Declaration for create_field::init_for_tmp_table()
sql/item.cc:
  Implementation for a framework used to easily handle different result
  types of SQL expressions. Instead of having instances of each possible 
  result type (integer, decimal, double) in every item, variables
  of all used types are moved to struct Hybrid_type.
  Hybrid_type can change its dynamic type in runtime, and become,
  for instance, DECIMAL from INTEGER.
  All type-specific Item operations are moved to the class hierarchy
  Hybrid_type_traits. Item::decimals and Item::max_length can
  be moved to Hybrid_type as well.
sql/item.h:
  Declaration for Hybrid_type framework. See also comments for item.cc
  in this changeset.
sql/item_sum.cc:
  Rewritten implementation for Item_sum_sum_distinct (SUM(DISTINCT))
  and added implementation for Item_sum_avg_distinct (AVG(DISTINCT)).
  The classes utilize Hybrid_type class hierarchy and Fields to
  convert SUM/AVG arguments to binary representation and store in a RB-tree.
sql/item_sum.h:
  Declarations for Item_sum_distinct (the new intermediate class used
  for SUM and AVG distinct), Item_sum_sum_distinct, Item_sum_avg_distinct.
sql/sql_select.cc:
  Implementatio of create_virtual_tmp_table().
sql/sql_select.h:
  Declaration for create_virtual_tmp_table.
sql/sql_yacc.yy:
  Grammar support for Item_sum_avg_distinct.
parent 08e23eb6
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -7150,6 +7150,24 @@ void create_field::create_length_to_internal_length(void)
}


void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
                                      uint32 length_arg, uint32 decimals,
                                      bool maybe_null, bool is_unsigned)
{
  field_name= "";
  sql_type= sql_type_arg;
  length= length_arg;;
  unireg_check= Field::NONE;
  interval= 0;
  charset= &my_charset_bin;
  geom_type= Field::GEOM_GEOMETRY;
  pack_flag= (FIELDFLAG_NUMBER |
              ((decimals & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
              (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
              (is_unsigned ? 0 : FIELDFLAG_DECIMAL));
}


enum_field_types get_blob_type_from_length(ulong length)
{
  enum_field_types type;
+7 −1
Original line number Diff line number Diff line
@@ -1340,7 +1340,8 @@ class Field_bit :public Field {
  Create field class for CREATE TABLE
*/

class create_field :public Sql_alloc {
class create_field :public Sql_alloc
{
public:
  const char *field_name;
  const char *change;			// If done with alter table
@@ -1362,6 +1363,11 @@ class create_field :public Sql_alloc {
  create_field() :after(0) {}
  create_field(Field *field, Field *orig_field);
  void create_length_to_internal_length(void);

  /* Init for a tmp table field. To be extended if need be. */
  void init_for_tmp_table(enum_field_types sql_type_arg,
                          uint32 max_length, uint32 decimals,
                          bool maybe_null, bool is_unsigned);
};


+125 −0
Original line number Diff line number Diff line
@@ -33,6 +33,131 @@ static void mark_as_dependent(THD *thd,

const String my_null_string("NULL", 4, default_charset_info);

/****************************************************************************/

/* Hybrid_type_traits {_real} */

void Hybrid_type_traits::fix_length_and_dec(Item *item, Item *arg) const
{
  item->decimals= NOT_FIXED_DEC;
  item->max_length= item->float_length(arg->decimals);
}


const Hybrid_type_traits *Hybrid_type_traits::instance()
{
  const static Hybrid_type_traits real_traits;
  return &real_traits;
}


my_decimal *
Hybrid_type_traits::val_decimal(Hybrid_type *val, my_decimal *to) const
{
  double2my_decimal(E_DEC_FATAL_ERROR, val->real, val->dec_buf);
  return val->dec_buf;
}


String *
Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const
{
  to->set(val->real, decimals, &my_charset_bin);
  return to;
}

/* Hybrid_type_traits_decimal */

const Hybrid_type_traits_decimal *Hybrid_type_traits_decimal::instance()
{
  const static Hybrid_type_traits_decimal decimal_traits;
  return &decimal_traits;
}


void
Hybrid_type_traits_decimal::fix_length_and_dec(Item *item, Item *arg) const
{
  item->decimals= arg->decimals;
  item->max_length= min(arg->max_length + DECIMAL_LONGLONG_DIGITS,
                        DECIMAL_MAX_LENGTH);
}


void Hybrid_type_traits_decimal::set_zero(Hybrid_type *val) const
{
  my_decimal_set_zero(&val->dec_buf[0]);
  val->used_dec_buf_no= 0;
}


void Hybrid_type_traits_decimal::add(Hybrid_type *val, Field *f) const
{
  my_decimal_add(E_DEC_FATAL_ERROR,
                 &val->dec_buf[val->used_dec_buf_no ^ 1],
                 &val->dec_buf[val->used_dec_buf_no],
                 f->val_decimal(&val->dec_buf[2]));
  val->used_dec_buf_no^= 1;
}


void Hybrid_type_traits_decimal::div(Hybrid_type *val, ulonglong u) const
{
  int2my_decimal(E_DEC_FATAL_ERROR, u, TRUE, &val->dec_buf[2]);
  /* XXX: what is '4' for scale? */
  my_decimal_div(E_DEC_FATAL_ERROR,
                 &val->dec_buf[val->used_dec_buf_no ^ 1],
                 &val->dec_buf[val->used_dec_buf_no],
                 &val->dec_buf[2], 4);
  val->used_dec_buf_no^= 1;
}


longlong
Hybrid_type_traits_decimal::val_int(Hybrid_type *val, bool unsigned_flag) const
{
  longlong result;
  my_decimal2int(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
                 unsigned_flag, &result);
  return result;
}


double
Hybrid_type_traits_decimal::val_real(Hybrid_type *val) const
{
  my_decimal2double(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
                    &val->real);
  return val->real;
}


String *
Hybrid_type_traits_decimal::val_str(Hybrid_type *val, String *to,
                                    uint8 decimals) const
{
  my_decimal_round(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
                   decimals, FALSE, &val->dec_buf[2]);
  my_decimal2string(E_DEC_FATAL_ERROR, &val->dec_buf[2], 0, 0, 0, to);
  return to;
}

/* Hybrid_type_traits_integer */

const Hybrid_type_traits_integer *Hybrid_type_traits_integer::instance()
{
  const static Hybrid_type_traits_integer integer_traits;
  return &integer_traits;
}

void
Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
{
  item->decimals= 0;
  item->max_length= 21;
  item->unsigned_flag= 0;
}

/*****************************************************************************
** Item functions
*****************************************************************************/
+114 −0
Original line number Diff line number Diff line
@@ -106,6 +106,120 @@ class DTCollation {
  }
};


/*************************************************************************/
/*
  A framework to easily handle different return types for hybrid items
  (hybrid item is an item whose operand can be of any type, e.g. integer,
  real, decimal).
*/

struct Hybrid_type_traits;

struct Hybrid_type
{
  longlong integer;

  double real;
  /*
    Use two decimal buffers interchangeably to speed up += operation
    which has no native support in decimal library.
    Hybrid_type+= arg is implemented as dec_buf[1]= dec_buf[0] + arg.
    The third decimal is used as a handy temporary storage.
  */
  my_decimal dec_buf[3];
  int used_dec_buf_no;

  /*
    Traits moved to a separate class to
      a) be able to easily change object traits in runtime
      b) they work as a differentiator for the union above
  */
  const Hybrid_type_traits *traits;

  Hybrid_type() {}
  /* XXX: add traits->copy() when needed */
  Hybrid_type(const Hybrid_type &rhs) :traits(rhs.traits) {}
};


/* Hybryd_type_traits interface + default implementation for REAL_RESULT */

struct Hybrid_type_traits
{
  virtual Item_result type() const { return REAL_RESULT; }

  virtual void
  fix_length_and_dec(Item *item, Item *arg) const;

  /* Hybrid_type operations. */
  virtual void set_zero(Hybrid_type *val) const { val->real= 0.0; }
  virtual void add(Hybrid_type *val, Field *f) const
  { val->real+= f->val_real(); }
  virtual void div(Hybrid_type *val, ulonglong u) const
  { val->real/= ulonglong2double(u); }

  virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const
  { return (longlong) val->real; }
  virtual double val_real(Hybrid_type *val) const { return val->real; }
  virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const;
  virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
  static const Hybrid_type_traits *instance();
};


struct Hybrid_type_traits_decimal: public Hybrid_type_traits
{
  virtual Item_result type() const { return DECIMAL_RESULT; }

  virtual void
  fix_length_and_dec(Item *arg, Item *item) const;

  /* Hybrid_type operations. */
  virtual void set_zero(Hybrid_type *val) const;
  virtual void add(Hybrid_type *val, Field *f) const;
  virtual void div(Hybrid_type *val, ulonglong u) const;

  virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const;
  virtual double val_real(Hybrid_type *val) const;
  virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
  { return &val->dec_buf[val->used_dec_buf_no]; }
  virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
  static const Hybrid_type_traits_decimal *instance();
};


struct Hybrid_type_traits_integer: public Hybrid_type_traits
{
  virtual Item_result type() const { return INT_RESULT; }

  virtual void
  fix_length_and_dec(Item *arg, Item *item) const;

  /* Hybrid_type operations. */
  virtual void set_zero(Hybrid_type *val) const
  { val->integer= 0; }
  virtual void add(Hybrid_type *val, Field *f) const
  { val->integer+= f->val_int(); }
  virtual void div(Hybrid_type *val, ulonglong u) const
  { val->integer/= (longlong) u; }

  virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const
  { return val->integer; }
  virtual double val_real(Hybrid_type *val) const
  { return (double) val->integer; }
  virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
  {
    int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, &val->dec_buf[2]);
    return &val->dec_buf[2];
  }
  virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const
  { buf->set(val->integer, &my_charset_bin); return buf;}
  static const Hybrid_type_traits_integer *instance();
};

/*************************************************************************/

typedef bool (Item::*Item_processor)(byte *arg);
typedef Item* (Item::*Item_transformer) (byte *arg);

+187 −165
Original line number Diff line number Diff line
@@ -456,11 +456,30 @@ my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
  return val_decimal_from_real(val);
}

/***************************************************************************/

C_MODE_START

/* Declarations for auxilary C-callbacks */

static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
{
    return memcmp(key1, key2, *(uint *) arg);
}

/* Item_sum_sum_distinct */

Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
  :Item_sum_sum(item), tree(0)
static int item_sum_distinct_walk(void *element, element_count num_of_dups,
                                  void *item)
{
    return ((Item_sum_distinct*) (item))->unique_walk_function(element);
}

C_MODE_END

/* Item_sum_distinct */

Item_sum_distinct::Item_sum_distinct(Item *item_arg)
  :Item_sum_num(item_arg), tree(0)
{
  /*
    quick_group is an optimizer hint, which means that GROUP BY can be
@@ -472,239 +491,242 @@ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
}


Item_sum_sum_distinct::Item_sum_sum_distinct(THD *thd,
                                             Item_sum_sum_distinct *original)
  :Item_sum_sum(thd, original), tree(0), dec_bin_buff(original->dec_bin_buff)
Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original)
  :Item_sum_num(thd, original), val(original->val), tree(0),
  table_field_type(original->table_field_type)
{
  quick_group= 0;
}


void Item_sum_sum_distinct::fix_length_and_dec()
/*
  Behaves like an Integer except to fix_length_and_dec().
  Additionally div() converts val with this traits to a val with true
  decimal traits along with conversion of integer value to decimal value.
  This is to speedup SUM/AVG(DISTINCT) evaluation for 8-32 bit integer
  values.
*/

struct Hybrid_type_traits_fast_decimal: public
       Hybrid_type_traits_integer
{
  Item_sum_sum::fix_length_and_dec();
  if (hybrid_type == DECIMAL_RESULT)
  virtual Item_result type() const { return DECIMAL_RESULT; }
  virtual void fix_length_and_dec(Item *item, Item *arg) const
  { Hybrid_type_traits_decimal::instance()->fix_length_and_dec(item, arg); }

  virtual void div(Hybrid_type *val, ulonglong u) const
  {
    dec_bin_buff= (byte *)
      sql_alloc(my_decimal_get_binary_size(args[0]->max_length,
                                           args[0]->decimals));
    int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, val->dec_buf);
    val->used_dec_buf_no= 0;
    val->traits= Hybrid_type_traits_decimal::instance();
    val->traits->div(val, u);
  }
  static const Hybrid_type_traits_fast_decimal *instance()
  {
    static const Hybrid_type_traits_fast_decimal fast_decimal_traits;
    return &fast_decimal_traits;
  }
};


Item *
Item_sum_sum_distinct::copy_or_same(THD *thd)
void Item_sum_distinct::fix_length_and_dec()
{
  return new (thd->mem_root) Item_sum_sum_distinct(thd, this);
}
  DBUG_ASSERT(args[0]->fixed);

C_MODE_START
  table_field_type= args[0]->field_type();

static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
  /* Adjust tmp table type according to the chosen aggregation type */
  switch (args[0]->result_type()) {
  case STRING_RESULT:
  case REAL_RESULT:
    val.traits= Hybrid_type_traits::instance();
    if (table_field_type != MYSQL_TYPE_FLOAT)
      table_field_type= MYSQL_TYPE_DOUBLE;
    break;
  case INT_RESULT:
  /*
    Preserving int8, int16, int32 field types gives ~10% performance boost
    as the size of result tree becomes significantly smaller.
    Another speed up we gain by using longlong for intermediate
    calculations. The range of int64 is enough to hold sum 2^32 distinct
    integers each <= 2^32.
  */
  if (table_field_type == MYSQL_TYPE_INT24 ||
      table_field_type >= MYSQL_TYPE_TINY &&
      table_field_type <= MYSQL_TYPE_LONG)
  {
  return memcmp(key1, key2, *(uint *) arg);
    val.traits= Hybrid_type_traits_fast_decimal::instance();
    break;
  }
  table_field_type= MYSQL_TYPE_LONGLONG;
  /* fallthrough */
  case DECIMAL_RESULT:
    val.traits= Hybrid_type_traits_decimal::instance();
    if (table_field_type != MYSQL_TYPE_LONGLONG)
      table_field_type= MYSQL_TYPE_NEWDECIMAL;
    break;
  case ROW_RESULT:
  default:
    DBUG_ASSERT(0);
  }
  val.traits->fix_length_and_dec(this, args[0]);
}

C_MODE_END


bool Item_sum_sum_distinct::setup(THD *thd)
bool Item_sum_distinct::setup(THD *thd)
{
  DBUG_ENTER("Item_sum_sum_distinct::setup");
  SELECT_LEX *select_lex= thd->lex->current_select;
  /* what does it mean??? */
  if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
    DBUG_RETURN(1);
  List<create_field> field_list;
  create_field field_def;                              /* field definition */

  DBUG_ENTER("Item_sum_distinct::setup");

  DBUG_ASSERT(tree == 0);                 /* setup can not be called twice */

  /*
    Uniques handles all unique elements in a tree until they can't fit in.
    Then thee tree is dumped to the temporary file.
    See class Unique for details.
    Virtual table and the tree are created anew on each re-execution of
    PS/SP. Hence all further allocations are performed in the runtime
    mem_root.
  */
  if (field_list.push_back(&field_def))
    return TRUE;

  null_value= maybe_null= 1;
  /*
    TODO: if underlying item result fits in 4 bytes we can take advantage
    of it and have tree of long/ulong. It gives 10% performance boost
  */
  quick_group= 0;

  DBUG_ASSERT(args[0]->fixed);

  field_def.init_for_tmp_table(table_field_type, args[0]->max_length,
                               args[0]->decimals, args[0]->maybe_null,
                               args[0]->unsigned_flag);

  if (! (table= create_virtual_tmp_table(thd, field_list)))
      return TRUE;

  /* XXX: check that the case of CHAR(0) works OK */
  tree_key_length= table->s->reclength - table->s->null_bytes;

  /*
    It's safe to use key_length here as even if we do copy_or_same()
    the new item will just share the old items key_length, which will not
    change or disappear during the life time of this item.
    Unique handles all unique elements in a tree until they can't fit
    in.  Then the tree is dumped to the temporary file. We can use
    simple_raw_key_cmp because the table contains numbers only; decimals
    are converted to binary representation as well.
  */
  key_length= ((hybrid_type == DECIMAL_RESULT) ?
               my_decimal_get_binary_size(args[0]->max_length,
                                          args[0]->decimals) :
               sizeof(double));
  tree= new Unique(simple_raw_key_cmp, &key_length, key_length,
  tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length,
                   thd->variables.max_heap_table_size);
  DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree,
                      key_length));
  DBUG_RETURN(tree == 0);
}

void Item_sum_sum_distinct::clear()
{
  DBUG_ENTER("Item_sum_sum_distinct::clear");
  DBUG_ASSERT(tree != 0);                        /* we always have a tree */
  null_value= 1; 
  tree->reset();
  DBUG_VOID_RETURN;
}

void Item_sum_sum_distinct::cleanup()
{
  Item_sum_num::cleanup();
  delete tree;
  tree= 0;
  DBUG_RETURN(tree == 0);
}


bool Item_sum_sum_distinct::add()
bool Item_sum_distinct::add()
{
  DBUG_ENTER("Item_sum_sum_distinct::add");
  if (hybrid_type == DECIMAL_RESULT)
  args[0]->save_in_field(table->field[0], FALSE);
  if (!table->field[0]->is_null())
  {
    my_decimal value, *val= args[0]->val_decimal(&value);
    if (!args[0]->null_value)
    {
      DBUG_ASSERT(tree != 0);
      null_value= 0;
      my_decimal2binary(E_DEC_FATAL_ERROR, val, (char *) dec_bin_buff,
                        args[0]->max_length, args[0]->decimals);
      DBUG_RETURN(tree->unique_add(dec_bin_buff));
    }
  }
  else
  {
    /* args[0]->val() may reset args[0]->null_value */
    double val= args[0]->val_real();
    if (!args[0]->null_value)
    {
      DBUG_ASSERT(tree != 0);
    DBUG_ASSERT(tree);
    null_value= 0;
      DBUG_PRINT("info", ("real: %lg, tree 0x%lx", val, (ulong)tree));
      if (val)
        DBUG_RETURN(tree->unique_add(&val));
    }
    else
      DBUG_PRINT("info", ("real: NULL"));
    /*
      '0' values are also stored in the tree. This doesn't matter
      for SUM(DISTINCT), but is important for AVG(DISTINCT)
    */
    return tree->unique_add(table->field[0]->ptr);
  }
  DBUG_RETURN(0);
  return 0;
}


void Item_sum_sum_distinct::add_real(double val)
bool Item_sum_distinct::unique_walk_function(void *element)
{
  DBUG_ENTER("Item_sum_sum_distinct::add_real");
  sum+= val;
  DBUG_PRINT("info", ("sum %lg, val %lg", sum, val));
  DBUG_VOID_RETURN;
  memcpy(table->field[0]->ptr, element, tree_key_length);
  ++count;
  val.traits->add(&val, table->field[0]);
  return 0;
}


void Item_sum_sum_distinct::add_decimal(byte *val)
void Item_sum_distinct::clear()
{
  binary2my_decimal(E_DEC_FATAL_ERROR, (char *) val, &tmp_dec,
                    args[0]->max_length, args[0]->decimals);
  my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
                 &tmp_dec, dec_buffs + curr_dec_buff);
  curr_dec_buff^= 1;
  DBUG_ENTER("Item_sum_distinct::clear");
  DBUG_ASSERT(tree != 0);                        /* we always have a tree */
  null_value= 1;
  tree->reset();
  DBUG_VOID_RETURN;
}

C_MODE_START

static int sum_sum_distinct_real(void *element, element_count num_of_dups,
                                 void *item_sum_sum_distinct)
void Item_sum_distinct::cleanup()
{
  ((Item_sum_sum_distinct *)
   (item_sum_sum_distinct))->add_real(* (double *) element);
  return 0;
  Item_sum_num::cleanup();
  delete tree;
  tree= 0;
  table= 0;
}

static int sum_sum_distinct_decimal(void *element, element_count num_of_dups,
                                    void *item_sum_sum_distinct)
Item_sum_distinct::~Item_sum_distinct()
{
  ((Item_sum_sum_distinct *)
   (item_sum_sum_distinct))->add_decimal((byte *)element);
  return 0;
  delete tree;
  /* no need to free the table */
}

C_MODE_END


double Item_sum_sum_distinct::val_real()
void Item_sum_distinct::calculate_val_and_count()
{
  DBUG_ENTER("Item_sum_sum_distinct::val");
  count= 0;
  val.traits->set_zero(&val);
  /*
    We don't have a tree only if 'setup()' hasn't been called;
    this is the case of sql_select.cc:return_zero_rows.
  */
  if (hybrid_type == DECIMAL_RESULT)
  {
    /* Item_sum_sum_distinct::val_decimal do not use argument */
    my_decimal *val= val_decimal(0);
    if (!null_value)
      my_decimal2double(E_DEC_FATAL_ERROR, val, &sum);
  }
  else
  {
    sum= 0.0;
    DBUG_PRINT("info", ("tree 0x%lx", (ulong)tree));
  if (tree)
      tree->walk(sum_sum_distinct_real, (void *) this);
  {
    table->field[0]->set_notnull();
    tree->walk(item_sum_distinct_walk, (void*) this);
  }
  DBUG_RETURN(sum);
}


my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake)
{
  if (hybrid_type == DECIMAL_RESULT)
double Item_sum_distinct::val_real()
{
    my_decimal_set_zero(dec_buffs);
    curr_dec_buff= 0;
    if (tree)
      tree->walk(sum_sum_distinct_decimal, (void *)this);
  calculate_val_and_count();
  return val.traits->val_real(&val);
}
  else


my_decimal *Item_sum_distinct::val_decimal(my_decimal *to)
{
    double real= val_real();
    curr_dec_buff= 0;
    double2my_decimal(E_DEC_FATAL_ERROR, real, dec_buffs);
  }
  return(dec_buffs + curr_dec_buff);
  calculate_val_and_count();
  if (null_value)
    return 0;
  return val.traits->val_decimal(&val, to);
}


longlong Item_sum_sum_distinct::val_int()
longlong Item_sum_distinct::val_int()
{
  longlong result;
  if (hybrid_type == DECIMAL_RESULT)
  {
    /* Item_sum_sum_distinct::val_decimal do not use argument */
    my_decimal *val= val_decimal(0);
    if (!null_value)
      my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
  }
  else
    result= (longlong) val_real();
  return result;
  calculate_val_and_count();
  return val.traits->val_int(&val, unsigned_flag);
}


String *Item_sum_sum_distinct::val_str(String *str)
String *Item_sum_distinct::val_str(String *str)
{
  DBUG_ASSERT(fixed == 1);
  if (hybrid_type == DECIMAL_RESULT)
    return val_string_from_decimal(str);
  return val_string_from_real(str);
  calculate_val_and_count();
  if (null_value)
    return 0;
  return val.traits->val_str(&val, str, decimals);
}

/* end of Item_sum_distinct */

/* Item_sum_avg_distinct */

void
Item_sum_avg_distinct::calculate_val_and_count()
{
  Item_sum_distinct::calculate_val_and_count();
  if (count)
    val.traits->div(&val, count);
}

/* end of Item_sum_sum_distinct */

Item *Item_sum_count::copy_or_same(THD* thd)
{
Loading