diff options
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r-- | sql/item_sum.cc | 163 |
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 |