summaryrefslogtreecommitdiff
path: root/sql/item_sum.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r--sql/item_sum.cc1178
1 files changed, 1064 insertions, 114 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 29837c3afbd..2ecc1eb083c 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -124,6 +124,16 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
return sum_item;
}
+
+my_decimal *Item_sum::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed);
+ DBUG_ASSERT(decimal_value);
+ int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
+
bool Item_sum::walk (Item_processor processor, byte *argument)
{
if (arg_count)
@@ -139,6 +149,32 @@ bool Item_sum::walk (Item_processor processor, byte *argument)
}
+Field *Item_sum::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length)
+{
+ switch (result_type()) {
+ case REAL_RESULT:
+ return new Field_double(max_length,maybe_null,name,table,decimals);
+ case INT_RESULT:
+ return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag);
+ case STRING_RESULT:
+ if (max_length > 255 && convert_blob_length)
+ return new Field_varstring(convert_blob_length, maybe_null,
+ name, table,
+ collation.collation);
+ return make_string_field(table);
+ case DECIMAL_RESULT:
+ return new Field_new_decimal(max_length - (decimals?1:0),
+ maybe_null, name, table, decimals);
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
+ }
+}
+
+
String *
Item_sum_num::val_str(String *str)
{
@@ -151,6 +187,17 @@ Item_sum_num::val_str(String *str)
}
+my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ double nr= val_real();
+ if (null_value)
+ return 0;
+ double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value);
+ return (decimal_value);
+}
+
+
String *
Item_sum_int::val_str(String *str)
{
@@ -184,8 +231,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
return TRUE;
- if (decimals < args[i]->decimals)
- decimals=args[i]->decimals;
+ set_if_bigger(decimals, args[i]->decimals);
maybe_null |= args[i]->maybe_null;
}
result_field=0;
@@ -198,6 +244,29 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
+Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
+ :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type),
+ hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign),
+ used_table_cache(item->used_table_cache), was_values(item->was_values)
+{
+ switch (hybrid_type)
+ {
+ case INT_RESULT:
+ sum_int= item->sum_int;
+ break;
+ case DECIMAL_RESULT:
+ my_decimal2decimal(&item->sum_dec, &sum_dec);
+ break;
+ case REAL_RESULT:
+ sum= item->sum;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ collation.set(item->collation);
+}
+
bool
Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
@@ -217,20 +286,29 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
item->fix_fields(thd, tables, args) ||
(item= args[0])->check_cols(1))
return TRUE;
+ decimals=item->decimals;
- hybrid_type= item->result_type();
- if (hybrid_type == INT_RESULT)
- {
- max_length=20;
- }
- else if (hybrid_type == REAL_RESULT)
- {
- max_length=float_length(decimals);
- }else
+ switch (hybrid_type= item->result_type())
{
- max_length=item->max_length;
- }
- decimals=item->decimals;
+ case INT_RESULT:
+ max_length= 20;
+ sum_int= 0;
+ break;
+ case DECIMAL_RESULT:
+ max_length= item->max_length;
+ my_decimal_set_zero(&sum_dec);
+ break;
+ case REAL_RESULT:
+ max_length= float_length(decimals);
+ sum= 0.0;
+ break;
+ case STRING_RESULT:
+ max_length= item->max_length;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ };
/* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= 1;
unsigned_flag=item->unsigned_flag;
@@ -252,6 +330,19 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
** reset and add of sum_func
***********************************************************************/
+Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item)
+ :Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
+ curr_dec_buff(item->curr_dec_buff)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal2decimal(item->dec_buffs, dec_buffs);
+ my_decimal2decimal(item->dec_buffs + 1, dec_buffs + 1);
+ }
+ else
+ sum= item->sum;
+}
+
Item *Item_sum_sum::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_sum(thd, this);
@@ -260,30 +351,128 @@ Item *Item_sum_sum::copy_or_same(THD* thd)
void Item_sum_sum::clear()
{
- null_value=1; sum=0.0;
+ DBUG_ENTER("Item_sum_sum::clear");
+ null_value=1;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ curr_dec_buff= 0;
+ my_decimal_set_zero(dec_buffs);
+ }
+ else
+ sum= 0.0;
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_sum_sum::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
+ maybe_null=null_value=1;
+ decimals= args[0]->decimals;
+ switch (args[0]->result_type())
+ {
+ case REAL_RESULT:
+ case STRING_RESULT:
+ hybrid_type= REAL_RESULT;
+ sum= 0.0;
+ break;
+ case INT_RESULT:
+ case DECIMAL_RESULT:
+ /* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
+ max_length= min(args[0]->max_length + DECIMAL_LONGLONG_DIGITS,
+ DECIMAL_MAX_LENGTH);
+ curr_dec_buff= 0;
+ hybrid_type= DECIMAL_RESULT;
+ my_decimal_set_zero(dec_buffs);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_PRINT("info", ("Type: %s (%d, %d)",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--"),
+ max_length,
+ (int)decimals));
+ DBUG_VOID_RETURN;
}
bool Item_sum_sum::add()
{
- sum+= args[0]->val_real();
- if (!args[0]->null_value)
- null_value= 0;
- return 0;
+ DBUG_ENTER("Item_sum_sum::add");
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
+ val, dec_buffs + curr_dec_buff);
+ curr_dec_buff^= 1;
+ null_value= 0;
+ }
+ }
+ else
+ {
+ sum+= args[0]->val_real();
+ if (!args[0]->null_value)
+ null_value= 0;
+ }
+ DBUG_RETURN(0);
+}
+
+
+longlong Item_sum_sum::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag,
+ &result);
+ return result;
+ }
+ return Item_sum_num::val_int();
}
double Item_sum_sum::val_real()
{
DBUG_ASSERT(fixed == 1);
+ if (hybrid_type == DECIMAL_RESULT)
+ my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum);
return sum;
}
+String *Item_sum_sum::val_str(String*str)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ if (null_value)
+ return NULL;
+ my_decimal_round(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, decimals,
+ FALSE, dec_buffs + curr_dec_buff);
+ my_decimal2string(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff,
+ 0, 0, 0, str);
+ return str;
+ }
+ return Item_sum_num::val_str(str);
+}
+
+
+my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(hybrid_type == DECIMAL_RESULT);
+ return(dec_buffs + curr_dec_buff);
+}
+
/* Item_sum_sum_distinct */
Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
- :Item_sum_num(item), sum(0.0), tree(0)
+ :Item_sum_sum(item), tree(0)
{
/*
quick_group is an optimizer hint, which means that GROUP BY can be
@@ -297,12 +486,24 @@ 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_num(thd, original), sum(0.0), tree(0)
+ :Item_sum_sum(thd, original), tree(0), dec_bin_buff(original->dec_bin_buff)
{
quick_group= 0;
}
+void Item_sum_sum_distinct::fix_length_and_dec()
+{
+ Item_sum_sum::fix_length_and_dec();
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ dec_bin_buff= (byte *)
+ sql_alloc(my_decimal_get_binary_size(args[0]->max_length,
+ args[0]->decimals));
+ }
+}
+
+
Item *
Item_sum_sum_distinct::copy_or_same(THD *thd)
{
@@ -320,10 +521,11 @@ C_MODE_END
bool Item_sum_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)
- return 1;
+ DBUG_RETURN(1);
DBUG_ASSERT(tree == 0); /* setup can not be called twice */
@@ -337,17 +539,25 @@ bool Item_sum_sum_distinct::setup(THD *thd)
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
*/
- static uint key_length= sizeof(double);
- tree= new Unique(simple_raw_key_cmp, &key_length, key_length,
+ uint *key_length_ptr= (uint *)thd->alloc(sizeof(uint));
+ *key_length_ptr= ((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_ptr, *key_length_ptr,
thd->variables.max_heap_table_size);
- return tree == 0;
+ DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree,
+ *key_length_ptr));
+ DBUG_RETURN(tree == 0);
}
void Item_sum_sum_distinct::clear()
{
+ DBUG_ENTER("Item_sum_sum_distinct::clear");
DBUG_ASSERT(tree); /* we always have a tree */
null_value= 1;
tree->reset();
+ DBUG_VOID_RETURN;
}
void Item_sum_sum_distinct::cleanup()
@@ -360,25 +570,71 @@ void Item_sum_sum_distinct::cleanup()
bool Item_sum_sum_distinct::add()
{
- /* args[0]->val_real() may reset args[0]->null_value */
- double val= args[0]->val_real();
- if (!args[0]->null_value)
+ DBUG_ENTER("Item_sum_sum_distinct::add");
+ if (hybrid_type == DECIMAL_RESULT)
{
- DBUG_ASSERT(tree);
- null_value= 0;
- if (val)
- return tree->unique_add(&val);
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ DBUG_ASSERT(tree);
+ null_value= 0;
+ my_decimal2binary(E_DEC_FATAL_ERROR, val, dec_bin_buff,
+ args[0]->max_length, args[0]->decimals);
+ DBUG_RETURN(tree->unique_add(dec_bin_buff));
+ }
}
- return 0;
+ else
+ {
+ /* args[0]->val() may reset args[0]->null_value */
+ double val= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ 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"));
+ }
+ DBUG_RETURN(0);
+}
+
+
+void Item_sum_sum_distinct::add_real(double val)
+{
+ DBUG_ENTER("Item_sum_sum_distinct::add_real");
+ sum+= val;
+ DBUG_PRINT("info", ("sum %lg, val %lg", sum, val));
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_sum_sum_distinct::add_decimal(byte *val)
+{
+ binary2my_decimal(E_DEC_FATAL_ERROR, 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;
}
C_MODE_START
-static int sum_sum_distinct(void *element, element_count num_of_dups,
- void *item_sum_sum_distinct)
+static int sum_sum_distinct_real(void *element, element_count num_of_dups,
+ void *item_sum_sum_distinct)
+{
+ ((Item_sum_sum_distinct *)
+ (item_sum_sum_distinct))->add_real(* (double *) element);
+ return 0;
+}
+
+static int sum_sum_distinct_decimal(void *element, element_count num_of_dups,
+ void *item_sum_sum_distinct)
{
((Item_sum_sum_distinct *)
- (item_sum_sum_distinct))->add(* (double *) element);
+ (item_sum_sum_distinct))->add_decimal((byte *)element);
return 0;
}
@@ -386,16 +642,86 @@ C_MODE_END
double Item_sum_sum_distinct::val_real()
{
+ DBUG_ENTER("Item_sum_sum_distinct::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.
*/
- sum= 0.0;
- if (tree)
- tree->walk(sum_sum_distinct, (void *) this);
- return sum;
+ 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);
+ }
+ DBUG_RETURN(sum);
}
+
+my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal_set_zero(dec_buffs);
+ curr_dec_buff= 0;
+ if (tree)
+ tree->walk(sum_sum_distinct_decimal, (void *)this);
+ }
+ else
+ {
+ double real= val_real();
+ double2my_decimal(E_DEC_FATAL_ERROR, real, dec_buffs + curr_dec_buff);
+ }
+ return(dec_buffs + curr_dec_buff);
+}
+
+
+longlong Item_sum_sum_distinct::val_int()
+{
+ longlong i;
+ 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, &i);
+ }
+ else
+ i= (longlong) val_real();
+ return i;
+}
+
+
+String *Item_sum_sum_distinct::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ /* Item_sum_sum_distinct::val_decimal do not use argument */
+ my_decimal *val= val_decimal(0);
+ if (null_value)
+ return 0;
+ my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
+ my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
+ }
+ else
+ {
+ double nr= val_real();
+ if (null_value)
+ return 0;
+ str->set(nr, decimals, &my_charset_bin);
+ }
+ return str;
+}
+
+
/* end of Item_sum_sum_distinct */
Item *Item_sum_count::copy_or_same(THD* thd)
@@ -442,6 +768,20 @@ void Item_sum_count::cleanup()
/*
Avgerage
*/
+void Item_sum_avg::fix_length_and_dec()
+{
+ Item_sum_sum::fix_length_and_dec();
+ maybe_null=null_value=1;
+ decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ f_scale= args[0]->decimals;
+ max_length= DECIMAL_MAX_LENGTH + (f_scale ? 1 : 0);
+ f_precision= DECIMAL_MAX_LENGTH;
+ dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
+ }
+}
+
Item *Item_sum_avg::copy_or_same(THD* thd)
{
@@ -449,21 +789,43 @@ Item *Item_sum_avg::copy_or_same(THD* thd)
}
+Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_len)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ if (group)
+ return new Field_string(dec_bin_size + sizeof(longlong),
+ 0, name, table, &my_charset_bin);
+ else
+ return new Field_new_decimal(f_precision,
+ maybe_null, name, table, f_scale);
+ }
+ else
+ {
+ if (group)
+ return new Field_string(sizeof(double)+sizeof(longlong),
+ 0, name,table,&my_charset_bin);
+ else
+ return new Field_double(max_length, maybe_null, name, table, decimals);
+ }
+}
+
+
void Item_sum_avg::clear()
{
- sum=0.0; count=0;
+ Item_sum_sum::clear();
+ count=0;
}
bool Item_sum_avg::add()
{
- double nr= args[0]->val_real();
+ if (Item_sum_sum::add())
+ return TRUE;
if (!args[0]->null_value)
- {
- sum+=nr;
count++;
- }
- return 0;
+ return FALSE;
}
double Item_sum_avg::val_real()
@@ -474,11 +836,46 @@ double Item_sum_avg::val_real()
null_value=1;
return 0.0;
}
- null_value=0;
- return sum/ulonglong2double(count);
+ return Item_sum_sum::val_real() / ulonglong2double(count);
}
+my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (!count)
+ {
+ null_value=1;
+ return NULL;
+ }
+ my_decimal sum, cnt;
+ const my_decimal *sum_dec= Item_sum_sum::val_decimal(&sum);
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt);
+ my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, 4);
+ return val;
+}
+
+
+String *Item_sum_avg::val_str(String *str)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *dec_val= val_decimal(&value);
+ if (null_value)
+ return NULL;
+ my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value);
+ my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str);
+ return str;
+ }
+ double nr= val_real();
+ if (null_value)
+ return NULL;
+ str->set(nr, decimals, &my_charset_bin);
+ return str;
+}
+
+
+
/*
Standard deviation
*/
@@ -500,26 +897,140 @@ Item *Item_sum_std::copy_or_same(THD* thd)
Variance
*/
+
+Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item):
+ Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
+ cur_dec(item->cur_dec), count(item->count)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ memcpy(dec_sum, item->dec_sum, sizeof(item->dec_sum));
+ memcpy(dec_sqr, item->dec_sqr, sizeof(item->dec_sqr));
+ for (int i=0; i<2; i++)
+ {
+ dec_sum[i].fix_buffer_pointer();
+ dec_sqr[i].fix_buffer_pointer();
+ }
+ }
+ else
+ {
+ sum= item->sum;
+ sum_sqr= item->sum_sqr;
+ }
+}
+
+
+void Item_sum_variance::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
+ maybe_null=null_value=1;
+ decimals= args[0]->decimals + 4;
+ switch (args[0]->result_type())
+ {
+ case REAL_RESULT:
+ case STRING_RESULT:
+ hybrid_type= REAL_RESULT;
+ sum= 0.0;
+ break;
+ case INT_RESULT:
+ case DECIMAL_RESULT:
+ /* SUM result can't be longer than length(arg)*2 + digits_after_the_point_to_add*/
+ max_length= args[0]->max_length*2 + 4;
+ cur_dec= 0;
+ hybrid_type= DECIMAL_RESULT;
+ my_decimal_set_zero(dec_sum);
+ my_decimal_set_zero(dec_sqr);
+ f_scale0= args[0]->decimals;
+ f_precision0= DECIMAL_MAX_LENGTH / 2;
+ f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1);
+ f_precision1= DECIMAL_MAX_LENGTH;
+ dec_bin_size0= my_decimal_get_binary_size(f_precision0, f_scale0);
+ dec_bin_size1= my_decimal_get_binary_size(f_precision1, f_scale1);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_PRINT("info", ("Type: %s (%d, %d)",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--"),
+ max_length,
+ (int)decimals));
+ DBUG_VOID_RETURN;
+}
+
+
Item *Item_sum_variance::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_variance(thd, this);
}
+Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_len)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ if (group)
+ return new Field_string(dec_bin_size0+dec_bin_size1+sizeof(longlong),
+ 0, name,table,&my_charset_bin);
+ else
+ return new Field_new_decimal(DECIMAL_MAX_LENGTH,
+ maybe_null, name, table, f_scale1 + 4);
+ }
+ else
+ {
+ if (group)
+ return new Field_string(sizeof(double)*2+sizeof(longlong),
+ 0, name,table,&my_charset_bin);
+ else
+ return new Field_double(max_length, maybe_null,name,table,decimals);
+ }
+}
+
+
void Item_sum_variance::clear()
{
- sum=sum_sqr=0.0;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal_set_zero(dec_sum);
+ my_decimal_set_zero(dec_sqr);
+ cur_dec= 0;
+ }
+ else
+ sum=sum_sqr=0.0;
count=0;
}
bool Item_sum_variance::add()
{
- double nr= args[0]->val_real();
- if (!args[0]->null_value)
+ if (hybrid_type == DECIMAL_RESULT)
{
- sum+=nr;
- sum_sqr+=nr*nr;
- count++;
+ my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf);
+ my_decimal sqr_buf;
+ if (!args[0]->null_value)
+ {
+ count++;
+ int next_dec= cur_dec ^ 1;
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr+next_dec,
+ dec_sqr+cur_dec, &sqr_buf);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sum+next_dec,
+ dec_sum+cur_dec, dec);
+ cur_dec= next_dec;
+ }
+ }
+ else
+ {
+ double nr= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ sum+=nr;
+ sum_sqr+=nr*nr;
+ count++;
+ }
}
return 0;
}
@@ -533,16 +1044,77 @@ double Item_sum_variance::val_real()
return 0.0;
}
null_value=0;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ double result;
+ my_decimal dec_buf, *dec= Item_sum_variance::val_decimal(&dec_buf);
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
+ return result;
+ }
/* Avoid problems when the precision isn't good enough */
double tmp=ulonglong2double(count);
double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
return tmp2 <= 0.0 ? 0.0 : tmp2;
}
+
+my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf)
+{
+ DBUG_ASSERT(fixed ==1 );
+ if (hybrid_type == REAL_RESULT)
+ {
+ double result= Item_sum_variance::val_real();
+ if (null_value)
+ return 0;
+ double2my_decimal(E_DEC_FATAL_ERROR, result, dec_buf);
+ return dec_buf;
+ }
+ if (!count)
+ {
+ null_value= 1;
+ return 0;
+ }
+ null_value= 0;
+ my_decimal count_buf, sum_sqr_buf;
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_buf);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf,
+ dec_sum+cur_dec, dec_sum+cur_dec);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count_buf, 2);
+ my_decimal_sub(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sqr+cur_dec, dec_buf);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count_buf, 2);
+ return dec_buf;
+}
+
void Item_sum_variance::reset_field()
{
- double nr= args[0]->val_real();
char *res=result_field->ptr;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+ if (args[0]->null_value)
+ {
+ my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero,
+ res, f_precision0, f_scale0);
+ my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero,
+ res+dec_bin_size0, f_precision1, f_scale1);
+ res+= dec_bin_size0 + dec_bin_size1;
+ longlong tmp=0;
+ int8store(res,tmp);
+ }
+ else
+ {
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec,
+ res, f_precision0, f_scale0);
+ my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum, arg_dec, arg_dec);
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum,
+ res+dec_bin_size0, f_precision1, f_scale1);
+ res+= dec_bin_size0 + dec_bin_size1;
+ longlong tmp=1;
+ int8store(res,tmp);
+ }
+ return;
+ }
+ double nr= args[0]->val_real();
if (args[0]->null_value)
bzero(res,sizeof(double)*2+sizeof(longlong));
@@ -558,10 +1130,33 @@ void Item_sum_variance::reset_field()
void Item_sum_variance::update_field()
{
- double nr,old_nr,old_sqr;
longlong field_count;
char *res=result_field->ptr;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ binary2my_decimal(E_DEC_FATAL_ERROR, res,
+ dec_sum+1, f_precision0, f_scale0);
+ binary2my_decimal(E_DEC_FATAL_ERROR, res+dec_bin_size0,
+ dec_sqr+1, f_precision1, f_scale1);
+ field_count= sint8korr(res + (dec_bin_size0 + dec_bin_size1));
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sum, arg_val, dec_sum+1);
+ my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum+1, arg_val, arg_val);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr, dec_sqr+1, dec_sum+1);
+ field_count++;
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum,
+ res, f_precision0, f_scale0);
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_sqr,
+ res+dec_bin_size0, f_precision1, f_scale1);
+ res+= dec_bin_size0 + dec_bin_size1;
+ int8store(res, field_count);
+ }
+ return;
+ }
+ double nr,old_nr,old_sqr;
float8get(old_nr, res);
float8get(old_sqr, res+sizeof(double));
field_count=sint8korr(res+sizeof(double)*2);
@@ -582,9 +1177,20 @@ void Item_sum_variance::update_field()
void Item_sum_hybrid::clear()
{
- sum= 0.0;
- sum_int= 0;
- value.length(0);
+ switch (hybrid_type)
+ {
+ case INT_RESULT:
+ sum_int= 0;
+ break;
+ case DECIMAL_RESULT:
+ my_decimal_set_zero(&sum_dec);
+ break;
+ case REAL_RESULT:
+ sum= 0.0;
+ break;
+ default:
+ value.length(0);
+ }
null_value= 1;
}
@@ -606,6 +1212,9 @@ double Item_sum_hybrid::val_real()
if (unsigned_flag)
return ulonglong2double(sum_int);
return (double) sum_int;
+ case DECIMAL_RESULT:
+ my_decimal2double(E_DEC_FATAL_ERROR, &sum_dec, &sum);
+ return sum;
case REAL_RESULT:
return sum;
case ROW_RESULT:
@@ -622,9 +1231,47 @@ longlong Item_sum_hybrid::val_int()
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
- if (hybrid_type == INT_RESULT)
+ switch (hybrid_type)
+ {
+ case INT_RESULT:
+ return sum_int;
+ case DECIMAL_RESULT:
+ {
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, &sum_dec, unsigned_flag, &result);
return sum_int;
- return (longlong) Item_sum_hybrid::val_real();
+ }
+ default:
+ return (longlong) Item_sum_hybrid::val_real();
+ }
+}
+
+
+my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (null_value)
+ return 0;
+ switch (hybrid_type) {
+ case STRING_RESULT:
+ string2my_decimal(E_DEC_FATAL_ERROR, &value, val);
+ break;
+ case REAL_RESULT:
+ double2my_decimal(E_DEC_FATAL_ERROR, sum, val);
+ break;
+ case DECIMAL_RESULT:
+ val= &sum_dec;
+ break;
+ case INT_RESULT:
+ int2my_decimal(E_DEC_FATAL_ERROR, sum_int, unsigned_flag, val);
+ break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
+ }
+ return val; // Keep compiler happy
}
@@ -640,6 +1287,9 @@ Item_sum_hybrid::val_str(String *str)
case REAL_RESULT:
str->set(sum,decimals, &my_charset_bin);
break;
+ case DECIMAL_RESULT:
+ my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str);
+ return str;
case INT_RESULT:
if (unsigned_flag)
str->set((ulonglong) sum_int, &my_charset_bin);
@@ -713,6 +1363,17 @@ bool Item_sum_min::add()
}
}
break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value &&
+ (null_value || (my_decimal_cmp(&sum_dec, val) > 0)))
+ {
+ my_decimal2decimal(val, &sum_dec);
+ null_value= 0;
+ }
+ }
+ break;
case REAL_RESULT:
{
double nr= args[0]->val_real();
@@ -766,6 +1427,17 @@ bool Item_sum_max::add()
}
}
break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value &&
+ (null_value || (my_decimal_cmp(val, &sum_dec) > 0)))
+ {
+ my_decimal2decimal(val, &sum_dec);
+ null_value= 0;
+ }
+ }
+ break;
case REAL_RESULT:
{
double nr= args[0]->val_real();
@@ -867,7 +1539,9 @@ void Item_sum_num::reset_field()
void Item_sum_hybrid::reset_field()
{
- if (hybrid_type == STRING_RESULT)
+ switch(hybrid_type)
+ {
+ case STRING_RESULT:
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff),result_field->charset()),*res;
@@ -883,8 +1557,9 @@ void Item_sum_hybrid::reset_field()
result_field->set_notnull();
result_field->store(res->ptr(),res->length(),tmp.charset());
}
+ break;
}
- else if (hybrid_type == INT_RESULT)
+ case INT_RESULT:
{
longlong nr=args[0]->val_int();
@@ -899,8 +1574,9 @@ void Item_sum_hybrid::reset_field()
result_field->set_notnull();
}
result_field->store(nr);
+ break;
}
- else // REAL_RESULT
+ case REAL_RESULT:
{
double nr= args[0]->val_real();
@@ -915,14 +1591,46 @@ void Item_sum_hybrid::reset_field()
result_field->set_notnull();
}
result_field->store(nr);
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+
+ if (maybe_null)
+ {
+ if (args[0]->null_value)
+ result_field->set_null();
+ else
+ result_field->set_notnull();
+ }
+ if (!args[0]->null_value)
+ result_field->store_decimal(arg_dec);
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
}
void Item_sum_sum::reset_field()
{
- double nr= args[0]->val_real(); // Nulls also return 0
- float8store(result_field->ptr,nr);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (args[0]->null_value)
+ result_field->reset();
+ else
+ result_field->store_decimal(arg_val);
+ }
+ else
+ {
+ DBUG_ASSERT(hybrid_type == REAL_RESULT);
+ double nr= args[0]->val_real(); // Nulls also return 0
+ float8store(result_field->ptr, nr);
+ }
if (args[0]->null_value)
result_field->set_null();
else
@@ -949,17 +1657,40 @@ void Item_sum_count::reset_field()
void Item_sum_avg::reset_field()
{
- double nr= args[0]->val_real();
char *res=result_field->ptr;
-
- if (args[0]->null_value)
- bzero(res,sizeof(double)+sizeof(longlong));
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+ if (args[0]->null_value)
+ {
+ my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero,
+ res, f_precision, f_scale);
+ res+= dec_bin_size;
+ longlong tmp=0;
+ int8store(res,tmp);
+ }
+ else
+ {
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec,
+ res, f_precision, f_scale);
+ res+= dec_bin_size;
+ longlong tmp=1;
+ int8store(res,tmp);
+ }
+ }
else
{
- float8store(res,nr);
- res+=sizeof(double);
- longlong tmp=1;
- int8store(res,tmp);
+ double nr= args[0]->val_real();
+
+ if (args[0]->null_value)
+ bzero(res,sizeof(double)+sizeof(longlong));
+ else
+ {
+ float8store(res,nr);
+ res+=sizeof(double);
+ longlong tmp=1;
+ int8store(res,tmp);
+ }
}
}
@@ -983,17 +1714,39 @@ void Item_sum_bit::update_field()
void Item_sum_sum::update_field()
{
- double old_nr,nr;
- char *res=result_field->ptr;
-
- float8get(old_nr,res);
- nr= args[0]->val_real();
- if (!args[0]->null_value)
+ if (hybrid_type == DECIMAL_RESULT)
{
- old_nr+=nr;
- result_field->set_notnull();
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ if (!result_field->is_null())
+ {
+ my_decimal field_value,
+ *field_val= result_field->val_decimal(&field_value);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, field_val);
+ result_field->store_decimal(dec_buffs);
+ }
+ else
+ {
+ result_field->store_decimal(arg_val);
+ result_field->set_notnull();
+ }
+ }
+ }
+ else
+ {
+ double old_nr,nr;
+ char *res=result_field->ptr;
+
+ float8get(old_nr,res);
+ nr= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ old_nr+=nr;
+ result_field->set_notnull();
+ }
+ float8store(res,old_nr);
}
- float8store(res,old_nr);
}
@@ -1017,32 +1770,59 @@ void Item_sum_count::update_field()
void Item_sum_avg::update_field()
{
- double nr,old_nr;
longlong field_count;
char *res=result_field->ptr;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ binary2my_decimal(E_DEC_FATAL_ERROR, res,
+ dec_buffs + 1, f_precision, f_scale);
+ field_count= sint8korr(res + dec_bin_size);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1);
+ field_count++;
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs,
+ res, f_precision, f_scale);
+ res+= dec_bin_size;
+ int8store(res, field_count);
+ }
+ }
+ else
+ {
+ double nr, old_nr;
- float8get(old_nr,res);
- field_count=sint8korr(res+sizeof(double));
+ float8get(old_nr, res);
+ field_count= sint8korr(res + sizeof(double));
- nr= args[0]->val_real();
- if (!args[0]->null_value)
- {
- old_nr+=nr;
- field_count++;
+ nr= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ old_nr+= nr;
+ field_count++;
+ }
+ float8store(res,old_nr);
+ res+= sizeof(double);
+ int8store(res, field_count);
}
- float8store(res,old_nr);
- res+=sizeof(double);
- int8store(res,field_count);
}
void Item_sum_hybrid::update_field()
{
- if (hybrid_type == STRING_RESULT)
+ switch (hybrid_type)
+ {
+ case STRING_RESULT:
min_max_update_str_field();
- else if (hybrid_type == INT_RESULT)
+ break;
+ case INT_RESULT:
min_max_update_int_field();
- else
+ break;
+ case DECIMAL_RESULT:
+ min_max_update_decimal_field();
+ break;
+ default:
min_max_update_real_field();
+ }
}
@@ -1112,41 +1892,119 @@ Item_sum_hybrid::min_max_update_int_field()
}
-Item_avg_field::Item_avg_field(Item_sum_avg *item)
+void
+Item_sum_hybrid::min_max_update_decimal_field()
+{
+ /* TODO: optimize: do not get result_field in case of args[0] is NULL */
+ my_decimal old_val, nr_val;
+ const my_decimal *old_nr= result_field->val_decimal(&old_val);
+ const my_decimal *nr= args[0]->val_decimal(&nr_val);
+ if (!args[0]->null_value)
+ {
+ if (result_field->is_null(0))
+ old_nr=nr;
+ else
+ {
+ bool res= my_decimal_cmp(old_nr, nr) > 0;
+ /* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */
+ if ((cmp_sign > 0) ^ (!res))
+ old_nr=nr;
+ }
+ result_field->set_notnull();
+ }
+ else if (result_field->is_null(0))
+ result_field->set_null();
+ result_field->store_decimal(old_nr);
+}
+
+
+Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item)
{
name=item->name;
decimals=item->decimals;
max_length=item->max_length;
field=item->result_field;
maybe_null=1;
+ hybrid_type= res_type;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ f_scale= item->f_scale;
+ f_precision= item->f_precision;
+ dec_bin_size= item->dec_bin_size;
+ }
}
double Item_avg_field::val_real()
{
// fix_fields() never calls for this Item
- double nr;
- longlong count;
- float8get(nr,field->ptr);
- char *res=(field->ptr+sizeof(double));
- count=sint8korr(res);
-
- if (!count)
+ if (hybrid_type == DECIMAL_RESULT)
{
- null_value=1;
- return 0.0;
+ my_decimal value, *dec_val= val_decimal(&value);
+ if (null_value)
+ return 0.0;
+ double d;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d);
+ return d;
}
- null_value=0;
- return nr/(double) count;
+ else
+ {
+ double nr;
+ longlong count;
+ float8get(nr,field->ptr);
+ char *res=(field->ptr+sizeof(double));
+ count=sint8korr(res);
+
+ if (!count)
+ {
+ null_value=1;
+ return 0.0;
+ }
+ null_value=0;
+ return nr/(double) count;
+ }
+}
+
+longlong Item_avg_field::val_int()
+{
+ return (longlong)val_real();
+}
+
+
+my_decimal *Item_avg_field::val_decimal(my_decimal * val)
+{
+ // fix_fields() never calls for this Item
+ longlong count= sint8korr(field->ptr + dec_bin_size);
+ if ((null_value= !count))
+ return NULL;
+
+ my_decimal dec_count, dec_field;
+ binary2my_decimal(E_DEC_FATAL_ERROR,
+ field->ptr, &dec_field, f_precision, f_scale);
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
+ my_decimal_div(E_DEC_FATAL_ERROR, val, &dec_field, &dec_count, 4);
+ return val;
}
+
String *Item_avg_field::val_str(String *str)
{
// fix_fields() never calls for this Item
- double nr= Item_avg_field::val_real();
- if (null_value)
- return 0;
- str->set(nr,decimals, &my_charset_bin);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *dec_val= val_decimal(&value);
+ if (null_value)
+ return NULL;
+ my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value);
+ my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str);
+ }
+ else
+ {
+ double nr= Item_avg_field::val_real();
+ if (null_value)
+ return 0;
+ str->set(nr, decimals, &my_charset_bin);
+ }
return str;
}
@@ -1169,11 +2027,29 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item)
max_length=item->max_length;
field=item->result_field;
maybe_null=1;
+ if ((hybrid_type= item->hybrid_type) == DECIMAL_RESULT)
+ {
+ f_scale0= item->f_scale0;
+ f_precision0= item->f_precision0;
+ dec_bin_size0= item->dec_bin_size0;
+ f_scale1= item->f_scale1;
+ f_precision1= item->f_precision1;
+ dec_bin_size1= item->dec_bin_size1;
+ }
}
double Item_variance_field::val_real()
{
// fix_fields() never calls for this Item
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal dec_buf, *dec_val= val_decimal(&dec_buf);
+ if (null_value)
+ return 0.0;
+ double d;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d);
+ return d;
+ }
double sum,sum_sqr;
longlong count;
float8get(sum,field->ptr);
@@ -1201,6 +2077,28 @@ String *Item_variance_field::val_str(String *str)
return str;
}
+
+my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf)
+{
+ // fix_fields() never calls for this Item
+ longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1);
+ if ((null_value= !count))
+ return 0;
+
+ my_decimal dec_count, dec_sum, dec_sqr, tmp;
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
+ binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr,
+ &dec_sum, f_precision0, f_scale0);
+ binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr+dec_bin_size0,
+ &dec_sqr, f_precision1, f_scale1);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &tmp, &dec_sum, &dec_sum);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &tmp, &dec_count, 2);
+ my_decimal_sub(E_DEC_FATAL_ERROR, &dec_sum, &dec_sqr, dec_buf);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_sum, &dec_count, 2);
+ return dec_buf;
+}
+
+
/****************************************************************************
** COUNT(DISTINCT ...)
****************************************************************************/
@@ -1597,6 +2495,58 @@ Item *Item_sum_udf_int::copy_or_same(THD* thd)
}
+String *Item_sum_udf_decimal::val_str(String *str)
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0;
+ if (str->length() < DECIMAL_MAX_STR_LENGTH)
+ str->length(DECIMAL_MAX_STR_LENGTH);
+ my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
+ my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str);
+ return str;
+}
+
+
+double Item_sum_udf_decimal::val_real()
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0.0;
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
+ return result;
+}
+
+
+longlong Item_sum_udf_decimal::val_int()
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0;
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
+ return result;
+}
+
+
+my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf)
+{
+ DBUG_ASSERT(fixed == 1);
+ DBUG_ENTER("Item_func_udf_decimal::val_decimal");
+ DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ args[0]->result_type(), arg_count));
+
+ DBUG_RETURN(udf.val_decimal(&null_value, dec_buf));
+}
+
+
+Item *Item_sum_udf_decimal::copy_or_same(THD* thd)
+{
+ return new (thd->mem_root) Item_sum_udf_decimal(thd, this);
+}
+
+
longlong Item_sum_udf_int::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -2037,7 +2987,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
for (i=0 ; i < arg_count ; i++)
{
- if ((!args[i]->fixed &&
+ if ((!args[i]->fixed &&
args[i]->fix_fields(thd, tables, args + i)) ||
args[i]->check_cols(1))
return TRUE;