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.cc549
1 files changed, 254 insertions, 295 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 2ecc1eb083c..b8da1423871 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -125,15 +125,6 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
}
-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)
@@ -178,38 +169,26 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
String *
Item_sum_num::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- double nr= val_real();
- if (null_value)
- return 0;
- str->set(nr,decimals, &my_charset_bin);
- return str;
+ return val_string_from_real(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);
+ return val_decimal_from_real(decimal_value);
}
String *
Item_sum_int::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- longlong nr= val_int();
- if (null_value)
- return 0;
- if (unsigned_flag)
- str->set((ulonglong) nr, &my_charset_bin);
- else
- str->set(nr, &my_charset_bin);
- return str;
+ return val_string_from_int(str);
+}
+
+
+my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value)
+{
+ return val_decimal_from_int(decimal_value);
}
@@ -249,8 +228,8 @@ Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
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)
- {
+ /* copy results from old value */
+ switch (hybrid_type) {
case INT_RESULT:
sum_int= item->sum_int;
break;
@@ -288,8 +267,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return TRUE;
decimals=item->decimals;
- switch (hybrid_type= item->result_type())
- {
+ switch (hybrid_type= item->result_type()) {
case INT_RESULT:
max_length= 20;
sum_int= 0;
@@ -334,6 +312,7 @@ 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)
{
+ /* TODO: check if the following assignments are really needed */
if (hybrid_type == DECIMAL_RESULT)
{
my_decimal2decimal(item->dec_buffs, dec_buffs);
@@ -369,8 +348,7 @@ 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())
- {
+ switch (args[0]->result_type()) {
case REAL_RESULT:
case STRING_RESULT:
hybrid_type= REAL_RESULT;
@@ -434,7 +412,7 @@ longlong Item_sum_sum::val_int()
&result);
return result;
}
- return Item_sum_num::val_int();
+ return (longlong) val_real();
}
@@ -447,28 +425,22 @@ double Item_sum_sum::val_real()
}
-String *Item_sum_sum::val_str(String*str)
+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);
+ return val_string_from_decimal(str);
+ return val_string_from_real(str);
}
my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
{
- DBUG_ASSERT(hybrid_type == DECIMAL_RESULT);
- return(dec_buffs + curr_dec_buff);
+ if (hybrid_type == DECIMAL_RESULT)
+ return (dec_buffs + curr_dec_buff);
+ return val_decimal_from_real(val);
}
+
/* Item_sum_sum_distinct */
Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
@@ -519,6 +491,7 @@ static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
C_MODE_END
+
bool Item_sum_sum_distinct::setup(THD *thd)
{
DBUG_ENTER("Item_sum_sum_distinct::setup");
@@ -539,15 +512,20 @@ 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
*/
- 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,
+
+ /*
+ 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.
+ */
+ 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,
thd->variables.max_heap_table_size);
DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree,
- *key_length_ptr));
+ key_length));
DBUG_RETURN(tree == 0);
}
@@ -640,6 +618,7 @@ static int sum_sum_distinct_decimal(void *element, element_count num_of_dups,
C_MODE_END
+
double Item_sum_sum_distinct::val_real()
{
DBUG_ENTER("Item_sum_sum_distinct::val");
@@ -685,17 +664,17 @@ my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake)
longlong Item_sum_sum_distinct::val_int()
{
- longlong i;
+ 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, &i);
+ my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
}
else
- i= (longlong) val_real();
- return i;
+ result= (longlong) val_real();
+ return result;
}
@@ -703,22 +682,8 @@ 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;
+ return val_string_from_decimal(str);
+ return val_string_from_real(str);
}
@@ -792,23 +757,21 @@ 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)
{
- 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);
+ /*
+ We must store both value and counter in the temporary table in one field.
+ The easyest way is to do this is to store both value in a string
+ and unpack on access.
+ */
+ return new Field_string(((hybrid_type == DECIMAL_RESULT) ?
+ dec_bin_size : sizeof(double)) + sizeof(longlong),
+ 0, name, table, &my_charset_bin);
}
+ if (hybrid_type == DECIMAL_RESULT)
+ return new Field_new_decimal(f_precision,
+ maybe_null, name, table, f_scale);
+ return new Field_double(max_length, maybe_null, name, table, decimals);
}
@@ -842,14 +805,15 @@ double Item_sum_avg::val_real()
my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
{
+ my_decimal sum, cnt;
+ const my_decimal *sum_dec;
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);
+ 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;
@@ -859,23 +823,11 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *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;
+ return val_string_from_decimal(str);
+ return val_string_from_real(str);
}
-
/*
Standard deviation
*/
@@ -922,11 +874,10 @@ Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item):
void Item_sum_variance::fix_length_and_dec()
{
- DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
- maybe_null=null_value=1;
+ DBUG_ENTER("Item_sum_variance::fix_length_and_dec");
+ maybe_null= null_value= 1;
decimals= args[0]->decimals + 4;
- switch (args[0]->result_type())
- {
+ switch (args[0]->result_type()) {
case REAL_RESULT:
case STRING_RESULT:
hybrid_type= REAL_RESULT;
@@ -934,12 +885,21 @@ void Item_sum_variance::fix_length_and_dec()
break;
case INT_RESULT:
case DECIMAL_RESULT:
- /* SUM result can't be longer than length(arg)*2 + digits_after_the_point_to_add*/
+ /*
+ 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);
+
+ /*
+ The maxium value to usable for variance is DECIMAL_MAX_LENGTH/2
+ becasue we need to be able to calculate in dec_bin_size1
+ column_value * column_value
+ */
f_scale0= args[0]->decimals;
f_precision0= DECIMAL_MAX_LENGTH / 2;
f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1);
@@ -971,23 +931,22 @@ Item *Item_sum_variance::copy_or_same(THD* thd)
Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
uint convert_blob_len)
{
- if (hybrid_type == DECIMAL_RESULT)
+ if (group)
{
- 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);
+ /*
+ We must store both value and counter in the temporary table in one field.
+ The easyest way is to do this is to store both value in a string
+ and unpack on access.
+ */
+ return new Field_string(((hybrid_type == DECIMAL_RESULT) ?
+ dec_bin_size0 + dec_bin_size1 :
+ sizeof(double)*2) + sizeof(longlong),
+ 0, name, table, &my_charset_bin);
}
+ if (hybrid_type == DECIMAL_RESULT)
+ return new Field_new_decimal(DECIMAL_MAX_LENGTH,
+ maybe_null, name, table, f_scale1 + 4);
+ return new Field_double(max_length, maybe_null,name,table,decimals);
}
@@ -1038,19 +997,15 @@ bool Item_sum_variance::add()
double Item_sum_variance::val_real()
{
DBUG_ASSERT(fixed == 1);
+ if (hybrid_type == DECIMAL_RESULT)
+ return val_real_from_decimal();
+
if (!count)
{
null_value=1;
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;
@@ -1060,22 +1015,17 @@ double Item_sum_variance::val_real()
my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf)
{
+ my_decimal count_buf, sum_sqr_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;
- }
+ return val_decimal_from_real(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);
@@ -1085,49 +1035,53 @@ my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf)
return dec_buf;
}
+
void Item_sum_variance::reset_field()
{
- char *res=result_field->ptr;
+ double nr;
+ char *res= result_field->ptr;
+
if (hybrid_type == DECIMAL_RESULT)
{
- my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+ my_decimal value, *arg_dec, *arg2_dec;
+ longlong tmp;
+
+ 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);
+ arg_dec= arg2_dec= &decimal_zero;
+ tmp= 0;
}
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);
+ arg2_dec= dec_sum;
+ tmp= 1;
}
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec,
+ res, f_precision0, f_scale0);
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg2_dec,
+ res+dec_bin_size0, f_precision1, f_scale1);
+ res+= dec_bin_size0 + dec_bin_size1;
+ int8store(res,tmp);
return;
}
- double nr= args[0]->val_real();
+ nr= args[0]->val_real();
if (args[0]->null_value)
bzero(res,sizeof(double)*2+sizeof(longlong));
else
{
+ longlong tmp;
float8store(res,nr);
nr*=nr;
float8store(res+sizeof(double),nr);
- longlong tmp=1;
+ tmp= 1;
int8store(res+sizeof(double)*2,tmp);
}
}
+
void Item_sum_variance::update_field()
{
longlong field_count;
@@ -1170,15 +1124,16 @@ void Item_sum_variance::update_field()
}
float8store(res,old_nr);
float8store(res+sizeof(double),old_sqr);
- int8store(res+sizeof(double)*2,field_count);
+ res+= sizeof(double)*2;
+ int8store(res,field_count);
}
+
/* min & max */
void Item_sum_hybrid::clear()
{
- switch (hybrid_type)
- {
+ switch (hybrid_type) {
case INT_RESULT:
sum_int= 0;
break;
@@ -1231,8 +1186,7 @@ longlong Item_sum_hybrid::val_int()
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
- switch (hybrid_type)
- {
+ switch (hybrid_type) {
case INT_RESULT:
return sum_int;
case DECIMAL_RESULT:
@@ -1539,8 +1493,7 @@ void Item_sum_num::reset_field()
void Item_sum_hybrid::reset_field()
{
- switch(hybrid_type)
- {
+ switch(hybrid_type) {
case STRING_RESULT:
{
char buff[MAX_FIELD_WIDTH];
@@ -1604,8 +1557,13 @@ void Item_sum_hybrid::reset_field()
else
result_field->set_notnull();
}
- if (!args[0]->null_value)
- result_field->store_decimal(arg_dec);
+ /*
+ We must store zero in the field as we will use the field value in
+ add()
+ */
+ if (!arg_dec) // Null
+ arg_dec= &decimal_zero;
+ result_field->store_decimal(arg_dec);
break;
}
case ROW_RESULT:
@@ -1620,10 +1578,9 @@ void Item_sum_sum::reset_field()
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);
+ if (!arg_val) // Null
+ arg_val= &decimal_zero;
+ result_field->store_decimal(arg_val);
}
else
{
@@ -1660,23 +1617,18 @@ void Item_sum_avg::reset_field()
char *res=result_field->ptr;
if (hybrid_type == DECIMAL_RESULT)
{
+ longlong tmp;
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);
+ arg_dec= &decimal_zero;
+ tmp= 0;
}
else
- {
- my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec,
- res, f_precision, f_scale);
- res+= dec_bin_size;
- longlong tmp=1;
- int8store(res,tmp);
- }
+ tmp= 1;
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale);
+ res+= dec_bin_size;
+ int8store(res, tmp);
}
else
{
@@ -1686,14 +1638,15 @@ void Item_sum_avg::reset_field()
bzero(res,sizeof(double)+sizeof(longlong));
else
{
+ longlong tmp= 1;
float8store(res,nr);
res+=sizeof(double);
- longlong tmp=1;
int8store(res,tmp);
}
}
}
+
void Item_sum_bit::reset_field()
{
reset();
@@ -1708,6 +1661,7 @@ void Item_sum_bit::update_field()
int8store(res, bits);
}
+
/*
** calc next value and merge it with field_value
*/
@@ -1781,36 +1735,36 @@ void Item_sum_avg::update_field()
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;
+ field_count++;
int8store(res, field_count);
}
}
else
{
- double nr, old_nr;
-
- float8get(old_nr, res);
- field_count= sint8korr(res + sizeof(double));
+ double nr;
nr= args[0]->val_real();
if (!args[0]->null_value)
{
+ double old_nr;
+ float8get(old_nr, res);
+ field_count= sint8korr(res + sizeof(double));
old_nr+= nr;
+ float8store(res,old_nr);
+ res+= sizeof(double);
field_count++;
+ int8store(res, field_count);
}
- float8store(res,old_nr);
- res+= sizeof(double);
- int8store(res, field_count);
}
}
+
void Item_sum_hybrid::update_field()
{
- switch (hybrid_type)
- {
+ switch (hybrid_type) {
case STRING_RESULT:
min_max_update_str_field();
break;
@@ -1938,52 +1892,45 @@ Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item)
double Item_avg_field::val_real()
{
// fix_fields() never calls for this Item
+ double nr;
+ longlong count;
+ char *res;
+
if (hybrid_type == DECIMAL_RESULT)
- {
- 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;
- }
- else
- {
- double nr;
- longlong count;
- float8get(nr,field->ptr);
- char *res=(field->ptr+sizeof(double));
- count=sint8korr(res);
+ return val_real_from_decimal();
- if (!count)
- {
- null_value=1;
- return 0.0;
- }
- null_value=0;
- return nr/(double) count;
- }
+ float8get(nr,field->ptr);
+ res= (field->ptr+sizeof(double));
+ count= sint8korr(res);
+
+ if ((null_value= !count))
+ return 0.0;
+ return nr/(double) count;
}
+
longlong Item_avg_field::val_int()
{
- return (longlong)val_real();
+ return (longlong) val_real();
}
-my_decimal *Item_avg_field::val_decimal(my_decimal * val)
+my_decimal *Item_avg_field::val_decimal(my_decimal *dec_buf)
{
// fix_fields() never calls for this Item
+ if (hybrid_type == REAL_RESULT)
+ return val_decimal_from_real(dec_buf);
+
longlong count= sint8korr(field->ptr + dec_bin_size);
if ((null_value= !count))
- return NULL;
+ return 0;
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;
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_field, &dec_count, 4);
+ return dec_buf;
}
@@ -1991,35 +1938,64 @@ String *Item_avg_field::val_str(String *str)
{
// fix_fields() never calls for this Item
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;
+ return val_string_from_decimal(str);
+ return val_string_from_real(str);
}
+
Item_std_field::Item_std_field(Item_sum_std *item)
: Item_variance_field(item)
{
}
+
double Item_std_field::val_real()
{
+ double nr;
// fix_fields() never calls for this Item
- double tmp= Item_variance_field::val_real();
- return tmp <= 0.0 ? 0.0 : sqrt(tmp);
+ if (hybrid_type == REAL_RESULT)
+ {
+ /*
+ We can't call Item_variance_field::val_real() on a DECIMAL_RESULT
+ as this would call Item_std_field::val_decimal() and we would
+ calculate sqrt() twice
+ */
+ nr= Item_variance_field::val_real();
+ }
+ else
+ {
+ my_decimal dec_buf,*dec;
+ dec= Item_variance_field::val_decimal(&dec_buf);
+ if (!dec)
+ nr= 0.0; // NULL; Return 0.0
+ else
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr);
+ }
+ return nr <= 0.0 ? 0.0 : sqrt(nr);
}
+
+my_decimal *Item_std_field::val_decimal(my_decimal *dec_buf)
+{
+ /*
+ We can't call val_decimal_from_real() for DECIMAL_RESULT as
+ Item_variance_field::val_real() would cause an infinite loop
+ */
+ my_decimal tmp_dec, *dec;
+ double nr;
+ if (hybrid_type == REAL_RESULT)
+ return val_decimal_from_real(dec_buf);
+ dec= Item_variance_field::val_decimal(dec_buf);
+ if (!dec)
+ return 0;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr);
+ nr= nr <= 0.0 ? 0.0 : sqrt(nr);
+ double2my_decimal(E_DEC_FATAL_ERROR, nr, &tmp_dec);
+ my_decimal_round(E_DEC_FATAL_ERROR, &tmp_dec, decimals, FALSE, dec_buf);
+ return dec_buf;
+}
+
+
Item_variance_field::Item_variance_field(Item_sum_variance *item)
{
name=item->name;
@@ -2038,49 +2014,42 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item)
}
}
+
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;
- }
+ return val_real_from_decimal();
+
double sum,sum_sqr;
longlong count;
float8get(sum,field->ptr);
float8get(sum_sqr,(field->ptr+sizeof(double)));
count=sint8korr(field->ptr+sizeof(double)*2);
- if (!count)
- {
- null_value=1;
+ if ((null_value= !count))
return 0.0;
- }
- null_value=0;
+
double tmp= (double) count;
double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
return tmp2 <= 0.0 ? 0.0 : tmp2;
}
+
String *Item_variance_field::val_str(String *str)
{
- // fix_fields() never calls for this Item
- double nr= val_real();
- if (null_value)
- return 0;
- str->set(nr,decimals, &my_charset_bin);
- return str;
+ if (hybrid_type == DECIMAL_RESULT)
+ return val_string_from_decimal(str);
+ return val_string_from_real(str);
}
my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf)
{
// fix_fields() never calls for this Item
+ if (hybrid_type == REAL_RESULT)
+ return val_decimal_from_real(dec_buf);
+
longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1);
if ((null_value= !count))
return 0;
@@ -2478,55 +2447,34 @@ double Item_sum_udf_float::val_real()
DBUG_RETURN(udf.val(&null_value));
}
+
String *Item_sum_udf_float::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- double nr= val_real();
- if (null_value)
- return 0; /* purecov: inspected */
- str->set(nr,decimals, &my_charset_bin);
- return str;
+ return val_string_from_real(str);
}
-Item *Item_sum_udf_int::copy_or_same(THD* thd)
+my_decimal *Item_sum_udf_float::val_decimal(my_decimal *dec)
{
- return new (thd->mem_root) Item_sum_udf_int(thd, this);
+ return val_decimal_from_real(dec);
}
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;
+ return val_string_from_decimal(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;
+ return val_real_from_decimal();
}
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;
+ return val_int_from_decimal();
}
@@ -2547,6 +2495,11 @@ Item *Item_sum_udf_decimal::copy_or_same(THD* thd)
}
+Item *Item_sum_udf_int::copy_or_same(THD* thd)
+{
+ return new (thd->mem_root) Item_sum_udf_int(thd, this);
+}
+
longlong Item_sum_udf_int::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -2559,14 +2512,15 @@ longlong Item_sum_udf_int::val_int()
String *Item_sum_udf_int::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- longlong nr=val_int();
- if (null_value)
- return 0;
- str->set(nr, &my_charset_bin);
- return str;
+ return val_string_from_int(str);
}
+my_decimal *Item_sum_udf_int::val_decimal(my_decimal *dec)
+{
+ return val_decimal_from_int(dec);
+}
+
+
/* Default max_length is max argument length */
void Item_sum_udf_str::fix_length_and_dec()
@@ -2585,6 +2539,11 @@ Item *Item_sum_udf_str::copy_or_same(THD* thd)
}
+my_decimal *Item_sum_udf_str::val_decimal(my_decimal *dec)
+{
+ return val_decimal_from_string(dec);
+}
+
String *Item_sum_udf_str::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);