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.cc163
1 files changed, 90 insertions, 73 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 4a7f2a54659..c3835c7536c 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -557,24 +557,27 @@ Item *Item_sum::set_arg(uint i, THD *thd, Item *new_val)
int Item_sum::set_aggregator(Aggregator::Aggregator_type aggregator)
{
- if (aggr)
+ /*
+ Dependent subselects may be executed multiple times, making
+ set_aggregator to be called multiple times. The aggregator type
+ will be the same, but it needs to be reset so that it is
+ reevaluated with the new dependent data.
+ This function may also be called multiple times during query optimization.
+ In this case, the type may change, so we delete the old aggregator,
+ and create a new one.
+ */
+ if (aggr && aggregator == aggr->Aggrtype())
{
- /*
- Dependent subselects may be executed multiple times, making
- set_aggregator to be called multiple times. The aggregator type
- will be the same, but it needs to be reset so that it is
- reevaluated with the new dependent data.
- */
- DBUG_ASSERT(aggregator == aggr->Aggrtype());
aggr->clear();
return FALSE;
}
+
+ delete aggr;
switch (aggregator)
{
case Aggregator::DISTINCT_AGGREGATOR:
aggr= new Aggregator_distinct(this);
break;
-
case Aggregator::SIMPLE_AGGREGATOR:
aggr= new Aggregator_simple(this);
break;
@@ -1143,17 +1146,13 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
switch (hybrid_type= item->result_type()) {
case INT_RESULT:
- max_length= 20;
- break;
case DECIMAL_RESULT:
+ case STRING_RESULT:
max_length= item->max_length;
break;
case REAL_RESULT:
max_length= float_length(decimals);
break;
- case STRING_RESULT:
- max_length= item->max_length;
- break;
case ROW_RESULT:
default:
DBUG_ASSERT(0);
@@ -1197,8 +1196,10 @@ void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg)
value= Item_cache::get_cache(item);
value->setup(item);
value->store(value_arg);
+ arg_cache= Item_cache::get_cache(item);
+ arg_cache->setup(item);
cmp= new Arg_comparator();
- cmp->set_cmp_func(this, args, (Item**)&value, FALSE);
+ cmp->set_cmp_func(this, (Item**)&arg_cache, (Item**)&value, FALSE);
collation.set(item->collation);
}
@@ -1326,27 +1327,11 @@ void Item_sum_sum::fix_length_and_dec()
bool Item_sum_sum::add()
{
DBUG_ENTER("Item_sum_sum::add");
- bool arg_is_null;
if (hybrid_type == DECIMAL_RESULT)
{
- my_decimal value, *val;
- if (aggr->use_distinct_values)
- {
- /*
- We are aggregating distinct rows. Get the value from the distinct
- table pointer
- */
- Aggregator_distinct *daggr= (Aggregator_distinct *)aggr;
- val= daggr->table->field[0]->val_decimal (&value);
- arg_is_null= daggr->table->field[0]->is_null();
- }
- else
- {
- /* non-distinct aggregation */
- val= args[0]->val_decimal(&value);
- arg_is_null= args[0]->null_value;
- }
- if (!arg_is_null)
+ my_decimal value;
+ const my_decimal *val= aggr->arg_val_decimal(&value);
+ if (!aggr->arg_is_null())
{
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
val, dec_buffs + curr_dec_buff);
@@ -1356,25 +1341,8 @@ bool Item_sum_sum::add()
}
else
{
- double val;
- if (aggr->use_distinct_values)
- {
- /*
- We are aggregating distinct rows. Get the value from the distinct
- table pointer
- */
- Aggregator_distinct *daggr= (Aggregator_distinct *)aggr;
- val= daggr->table->field[0]->val_real ();
- arg_is_null= daggr->table->field[0]->is_null();
- }
- else
- {
- /* non-distinct aggregation */
- val= args[0]->val_real();
- arg_is_null= args[0]->null_value;
- }
- sum+= val;
- if (!arg_is_null)
+ sum+= aggr->arg_val_real();
+ if (!aggr->arg_is_null())
null_value= 0;
}
DBUG_RETURN(0);
@@ -1472,6 +1440,45 @@ Aggregator_distinct::~Aggregator_distinct()
}
+my_decimal *Aggregator_simple::arg_val_decimal(my_decimal *value)
+{
+ return item_sum->args[0]->val_decimal(value);
+}
+
+
+double Aggregator_simple::arg_val_real()
+{
+ return item_sum->args[0]->val_real();
+}
+
+
+bool Aggregator_simple::arg_is_null()
+{
+ return item_sum->args[0]->null_value;
+}
+
+
+my_decimal *Aggregator_distinct::arg_val_decimal(my_decimal * value)
+{
+ return use_distinct_values ? table->field[0]->val_decimal(value) :
+ item_sum->args[0]->val_decimal(value);
+}
+
+
+double Aggregator_distinct::arg_val_real()
+{
+ return use_distinct_values ? table->field[0]->val_real() :
+ item_sum->args[0]->val_real();
+}
+
+
+bool Aggregator_distinct::arg_is_null()
+{
+ return use_distinct_values ? table->field[0]->is_null() :
+ item_sum->args[0]->null_value;
+}
+
+
Item *Item_sum_count::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_count(thd, this);
@@ -1577,7 +1584,7 @@ bool Item_sum_avg::add()
{
if (Item_sum_sum::add())
return TRUE;
- if (!args[0]->null_value)
+ if (!aggr->arg_is_null())
count++;
return FALSE;
}
@@ -1893,7 +1900,10 @@ double Item_sum_hybrid::val_real()
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0.0;
- return value->val_real();
+ double retval= value->val_real();
+ if ((null_value= value->null_value))
+ DBUG_ASSERT(retval == 0.0);
+ return retval;
}
longlong Item_sum_hybrid::val_int()
@@ -1901,7 +1911,10 @@ longlong Item_sum_hybrid::val_int()
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
- return value->val_int();
+ longlong retval= value->val_int();
+ if ((null_value= value->null_value))
+ DBUG_ASSERT(retval == 0);
+ return retval;
}
@@ -1910,7 +1923,10 @@ my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val)
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
- return value->val_decimal(val);
+ my_decimal *retval= value->val_decimal(val);
+ if ((null_value= value->null_value))
+ DBUG_ASSERT(retval == NULL);
+ return retval;
}
@@ -1920,7 +1936,10 @@ Item_sum_hybrid::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
- return value->val_str(str);
+ String *retval= value->val_str(str);
+ if ((null_value= value->null_value))
+ DBUG_ASSERT(retval == NULL);
+ return retval;
}
@@ -1975,11 +1994,11 @@ Item *Item_sum_min::copy_or_same(THD* thd)
bool Item_sum_min::add()
{
/* args[0] < value */
- int res= cmp->compare();
- if (!args[0]->null_value &&
- (null_value || res < 0))
+ arg_cache->cache_value();
+ if (!arg_cache->null_value &&
+ (null_value || cmp->compare() < 0))
{
- value->store(args[0]);
+ value->store(arg_cache);
value->cache_value();
null_value= 0;
}
@@ -1998,11 +2017,11 @@ Item *Item_sum_max::copy_or_same(THD* thd)
bool Item_sum_max::add()
{
/* args[0] > value */
- int res= cmp->compare();
- if (!args[0]->null_value &&
- (null_value || res > 0))
+ arg_cache->cache_value();
+ if (!arg_cache->null_value &&
+ (null_value || cmp->compare() > 0))
{
- value->store(args[0]);
+ value->store(arg_cache);
value->cache_value();
null_value= 0;
}
@@ -2244,7 +2263,7 @@ void Item_sum_avg::reset_field()
void Item_sum_bit::reset_field()
{
- reset();
+ reset_and_add();
int8store(result_field->ptr, bits);
}
@@ -3057,6 +3076,7 @@ Item_func_group_concat(Name_resolution_context *context_arg,
order_item->item= arg_ptr++;
}
}
+ memcpy(orig_args, args, sizeof(Item*) * arg_count);
}
@@ -3267,7 +3287,6 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
if (check_sum_func(thd, ref))
return TRUE;
- memcpy (orig_args, args, sizeof (Item *) * arg_count);
fixed= 1;
return FALSE;
}
@@ -3423,8 +3442,6 @@ String* Item_func_group_concat::val_str(String* str)
void Item_func_group_concat::print(String *str, enum_query_type query_type)
{
- /* orig_args is not filled with valid values until fix_fields() */
- Item **pargs= fixed ? orig_args : args;
str->append(STRING_WITH_LEN("group_concat("));
if (distinct)
str->append(STRING_WITH_LEN("distinct "));
@@ -3432,7 +3449,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
{
if (i)
str->append(',');
- pargs[i]->print(str, query_type);
+ orig_args[i]->print(str, query_type);
}
if (arg_count_order)
{
@@ -3441,7 +3458,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
{
if (i)
str->append(',');
- pargs[i + arg_count_field]->print(str, query_type);
+ orig_args[i + arg_count_field]->print(str, query_type);
if (order[i]->asc)
str->append(STRING_WITH_LEN(" ASC"));
else