diff options
-rw-r--r-- | sql/item_sum.cc.orig | 4113 | ||||
-rw-r--r-- | sql/item_sum.h.orig | 1821 |
2 files changed, 0 insertions, 5934 deletions
diff --git a/sql/item_sum.cc.orig b/sql/item_sum.cc.orig deleted file mode 100644 index aa61c19306d..00000000000 --- a/sql/item_sum.cc.orig +++ /dev/null @@ -1,4113 +0,0 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2015, MariaDB - - 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 - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - - -/** - @file - - @brief - Sum functions (COUNT, MIN...) -*/ - -#ifdef USE_PRAGMA_IMPLEMENTATION -#pragma implementation // gcc: Class implementation -#endif - -#include "mariadb.h" -#include "sql_priv.h" -#include "sql_select.h" -#include "uniques.h" -#include "sp_rcontext.h" -#include "sp.h" -#include "sql_parse.h" -#include "sp_head.h" - -/** - Calculate the affordable RAM limit for structures like TREE or Unique - used in Item_sum_* -*/ - -size_t Item_sum::ram_limitation(THD *thd) -{ - return (size_t)MY_MIN(thd->variables.tmp_memory_table_size, - thd->variables.max_heap_table_size); -} - - -/** - Prepare an aggregate function item for checking context conditions. - - The function initializes the members of the Item_sum object created - for a set function that are used to check validity of the set function - occurrence. - If the set function is not allowed in any subquery where it occurs - an error is reported immediately. - - @param thd reference to the thread context info - - @note - This function is to be called for any item created for a set function - object when the traversal of trees built for expressions used in the query - is performed at the phase of context analysis. This function is to - be invoked at the descent of this traversal. - @retval - TRUE if an error is reported - @retval - FALSE otherwise -*/ - -bool Item_sum::init_sum_func_check(THD *thd) -{ - SELECT_LEX *curr_sel= thd->lex->current_select; - if (!curr_sel->name_visibility_map) - { - for (SELECT_LEX *sl= curr_sel; sl; sl= sl->context.outer_select()) - { - curr_sel->name_visibility_map|= (1 << sl-> nest_level); - } - } - if (!(thd->lex->allow_sum_func & curr_sel->name_visibility_map)) - { - my_message(ER_INVALID_GROUP_FUNC_USE, ER_THD(thd, ER_INVALID_GROUP_FUNC_USE), - MYF(0)); - return TRUE; - } - /* Set a reference to the nesting set function if there is any */ - in_sum_func= thd->lex->in_sum_func; - /* Save a pointer to object to be used in items for nested set functions */ - thd->lex->in_sum_func= this; - nest_level= thd->lex->current_select->nest_level; - ref_by= 0; - aggr_level= -1; - aggr_sel= NULL; - max_arg_level= -1; - max_sum_func_level= -1; - outer_fields.empty(); - return FALSE; -} - -/** - Check constraints imposed on a usage of a set function. - - The method verifies whether context conditions imposed on a usage - of any set function are met for this occurrence. - - The function first checks if we are using any window functions as - arguments to the set function. In that case it returns an error. - - Afterwards, it checks whether the set function occurs in the position where it - can be aggregated and, when it happens to occur in argument of another - set function, the method checks that these two functions are aggregated in - different subqueries. - If the context conditions are not met the method reports an error. - If the set function is aggregated in some outer subquery the method - adds it to the chain of items for such set functions that is attached - to the the st_select_lex structure for this subquery. - - A number of designated members of the object are used to check the - conditions. They are specified in the comment before the Item_sum - class declaration. - Additionally a bitmap variable called allow_sum_func is employed. - It is included into the thd->lex structure. - The bitmap contains 1 at n-th position if the set function happens - to occur under a construct of the n-th level subquery where usage - of set functions are allowed (i.e either in the SELECT list or - in the HAVING clause of the corresponding subquery) - Consider the query: - @code - SELECT SUM(t1.b) FROM t1 GROUP BY t1.a - HAVING t1.a IN (SELECT t2.c FROM t2 WHERE AVG(t1.b) > 20) AND - t1.a > (SELECT MIN(t2.d) FROM t2); - @endcode - allow_sum_func will contain: - - for SUM(t1.b) - 1 at the first position - - for AVG(t1.b) - 1 at the first position, 0 at the second position - - for MIN(t2.d) - 1 at the first position, 1 at the second position. - - @param thd reference to the thread context info - @param ref location of the pointer to this item in the embedding expression - - @note - This function is to be called for any item created for a set function - object when the traversal of trees built for expressions used in the query - is performed at the phase of context analysis. This function is to - be invoked at the ascent of this traversal. - - @retval - TRUE if an error is reported - @retval - FALSE otherwise -*/ - -bool Item_sum::check_sum_func(THD *thd, Item **ref) -{ - SELECT_LEX *curr_sel= thd->lex->current_select; - nesting_map allow_sum_func= (thd->lex->allow_sum_func & - curr_sel->name_visibility_map); - bool invalid= FALSE; - DBUG_ASSERT(curr_sel->name_visibility_map); // should be set already - - /* - Window functions can not be used as arguments to sum functions. - Aggregation happes before window function computation, so there - are no values to aggregate over. - */ - if (with_window_func) - { - my_message(ER_SUM_FUNC_WITH_WINDOW_FUNC_AS_ARG, - ER_THD(thd, ER_SUM_FUNC_WITH_WINDOW_FUNC_AS_ARG), - MYF(0)); - return TRUE; - } - - if (window_func_sum_expr_flag) - return false; - /* - The value of max_arg_level is updated if an argument of the set function - contains a column reference resolved against a subquery whose level is - greater than the current value of max_arg_level. - max_arg_level cannot be greater than nest level. - nest level is always >= 0 - */ - if (nest_level == max_arg_level) - { - /* - The function must be aggregated in the current subquery, - If it is there under a construct where it is not allowed - we report an error. - */ - invalid= !(allow_sum_func & ((nesting_map)1 << max_arg_level)); - } - else if (max_arg_level >= 0 || - !(allow_sum_func & ((nesting_map)1 << nest_level))) - { - /* - The set function can be aggregated only in outer subqueries. - Try to find a subquery where it can be aggregated; - If we fail to find such a subquery report an error. - */ - if (register_sum_func(thd, ref)) - return TRUE; - invalid= aggr_level < 0 && - !(allow_sum_func & ((nesting_map)1 << nest_level)); - if (!invalid && thd->variables.sql_mode & MODE_ANSI) - invalid= aggr_level < 0 && max_arg_level < nest_level; - } - if (!invalid && aggr_level < 0) - { - aggr_level= nest_level; - aggr_sel= curr_sel; - } - /* - By this moment we either found a subquery where the set function is - to be aggregated and assigned a value that is >= 0 to aggr_level, - or set the value of 'invalid' to TRUE to report later an error. - */ - /* - Additionally we have to check whether possible nested set functions - are acceptable here: they are not, if the level of aggregation of - some of them is less than aggr_level. - */ - if (!invalid) - invalid= aggr_level <= max_sum_func_level; - if (invalid) - { - my_message(ER_INVALID_GROUP_FUNC_USE, - ER_THD(thd, ER_INVALID_GROUP_FUNC_USE), - MYF(0)); - return TRUE; - } - - if (in_sum_func) - { - /* - If the set function is nested adjust the value of - max_sum_func_level for the nesting set function. - We take into account only enclosed set functions that are to be - aggregated on the same level or above of the nest level of - the enclosing set function. - But we must always pass up the max_sum_func_level because it is - the maximum nested level of all directly and indirectly enclosed - set functions. We must do that even for set functions that are - aggregated inside of their enclosing set function's nest level - because the enclosing function may contain another enclosing - function that is to be aggregated outside or on the same level - as its parent's nest level. - */ - if (in_sum_func->nest_level >= aggr_level) - set_if_bigger(in_sum_func->max_sum_func_level, aggr_level); - set_if_bigger(in_sum_func->max_sum_func_level, max_sum_func_level); - } - - /* - Check that non-aggregated fields and sum functions aren't mixed in the - same select in the ONLY_FULL_GROUP_BY mode. - */ - if (outer_fields.elements) - { - Item_field *field; - /* - Here we compare the nesting level of the select to which an outer field - belongs to with the aggregation level of the sum function. All fields in - the outer_fields list are checked. - - If the nesting level is equal to the aggregation level then the field is - aggregated by this sum function. - If the nesting level is less than the aggregation level then the field - belongs to an outer select. In this case if there is an embedding sum - function add current field to functions outer_fields list. If there is - no embedding function then the current field treated as non aggregated - and the select it belongs to is marked accordingly. - If the nesting level is greater than the aggregation level then it means - that this field was added by an inner sum function. - Consider an example: - - select avg ( <-- we are here, checking outer.f1 - select ( - select sum(outer.f1 + inner.f1) from inner - ) from outer) - from most_outer; - - In this case we check that no aggregate functions are used in the - select the field belongs to. If there are some then an error is - raised. - */ - List_iterator<Item_field> of(outer_fields); - while ((field= of++)) - { - SELECT_LEX *sel= field->field->table->pos_in_table_list->select_lex; - if (sel->nest_level < aggr_level) - { - if (in_sum_func) - { - /* - Let upper function decide whether this field is a non - aggregated one. - */ - in_sum_func->outer_fields.push_back(field, thd->mem_root); - } - else - sel->set_non_agg_field_used(true); - } - if (sel->nest_level > aggr_level && - (sel->agg_func_used()) && - !sel->group_list.elements) - { - my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, - ER_THD(thd, ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); - return TRUE; - } - } - } - aggr_sel->set_agg_func_used(true); - update_used_tables(); - thd->lex->in_sum_func= in_sum_func; - return FALSE; -} - -/** - Attach a set function to the subquery where it must be aggregated. - - The function looks for an outer subquery where the set function must be - aggregated. If it finds such a subquery then aggr_level is set to - the nest level of this subquery and the item for the set function - is added to the list of set functions used in nested subqueries - inner_sum_func_list defined for each subquery. When the item is placed - there the field 'ref_by' is set to ref. - - @note - Now we 'register' only set functions that are aggregated in outer - subqueries. Actually it makes sense to link all set function for - a subquery in one chain. It would simplify the process of 'splitting' - for set functions. - - @param thd reference to the thread context info - @param ref location of the pointer to this item in the embedding expression - - @retval - FALSE if the executes without failures (currently always) - @retval - TRUE otherwise -*/ - -bool Item_sum::register_sum_func(THD *thd, Item **ref) -{ - SELECT_LEX *sl; - nesting_map allow_sum_func= thd->lex->allow_sum_func; - for (sl= thd->lex->current_select->context.outer_select() ; - sl && sl->nest_level > max_arg_level; - sl= sl->context.outer_select()) - { - if (aggr_level < 0 && - (allow_sum_func & ((nesting_map)1 << sl->nest_level))) - { - /* Found the most nested subquery where the function can be aggregated */ - aggr_level= sl->nest_level; - aggr_sel= sl; - } - } - if (sl && (allow_sum_func & ((nesting_map)1 << sl->nest_level))) - { - /* - We reached the subquery of level max_arg_level and checked - that the function can be aggregated here. - The set function will be aggregated in this subquery. - */ - aggr_level= sl->nest_level; - aggr_sel= sl; - - } - if (aggr_level >= 0) - { - ref_by= ref; - /* Add the object to the list of registered objects assigned to aggr_sel */ - if (!aggr_sel->inner_sum_func_list) - next= this; - else - { - next= aggr_sel->inner_sum_func_list->next; - aggr_sel->inner_sum_func_list->next= this; - } - aggr_sel->inner_sum_func_list= this; - aggr_sel->with_sum_func= 1; - - /* - Mark Item_subselect(s) as containing aggregate function all the way up - to aggregate function's calculation context. - Note that we must not mark the Item of calculation context itself - because with_sum_func on the calculation context st_select_lex is - already set above. - - with_sum_func being set for an Item means that this Item refers - (somewhere in it, e.g. one of its arguments if it's a function) directly - or through intermediate items to an aggregate function that is calculated - in a context "outside" of the Item (e.g. in the current or outer select). - - with_sum_func being set for an st_select_lex means that this st_select_lex - has aggregate functions directly referenced (i.e. not through a sub-select). - */ - for (sl= thd->lex->current_select; - sl && sl != aggr_sel && sl->master_unit()->item; - sl= sl->master_unit()->outer_select() ) - sl->master_unit()->item->with_sum_func= 1; - } - thd->lex->current_select->mark_as_dependent(thd, aggr_sel, NULL); - - if ((thd->lex->describe & DESCRIBE_EXTENDED) && aggr_sel) - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_WARN_AGGFUNC_DEPENDENCE, - ER_THD(thd, ER_WARN_AGGFUNC_DEPENDENCE), - func_name(), - thd->lex->current_select->select_number, - aggr_sel->select_number); - } - return FALSE; -} - - -bool Item_sum::collect_outer_ref_processor(void *param) -{ - Collect_deps_prm *prm= (Collect_deps_prm *)param; - SELECT_LEX *ds; - if ((ds= depended_from()) && - ds->nest_level_base == prm->nest_level_base && - ds->nest_level < prm->nest_level) - { - if (prm->collect) - prm->parameters->add_unique(this, &cmp_items); - else - prm->count++; - } - return FALSE; -} - - -Item_sum::Item_sum(THD *thd, List<Item> &list): Item_func_or_sum(thd, list) -{ - if (!(orig_args= (Item **) thd->alloc(sizeof(Item *) * arg_count))) - { - args= NULL; - } - mark_as_sum_func(); - init_aggregator(); - list.empty(); // Fields are used -} - - -/** - Constructor used in processing select with temporary tebles. -*/ - -Item_sum::Item_sum(THD *thd, Item_sum *item): - Item_func_or_sum(thd, item), - aggr_sel(item->aggr_sel), - nest_level(item->nest_level), aggr_level(item->aggr_level), - quick_group(item->quick_group), - orig_args(NULL) -{ - if (arg_count <= 2) - { - orig_args=tmp_orig_args; - } - else - { - if (!(orig_args= (Item**) thd->alloc(sizeof(Item*)*arg_count))) - return; - } - memcpy(orig_args, item->orig_args, sizeof(Item*)*arg_count); - init_aggregator(); - with_distinct= item->with_distinct; - if (item->aggr) - set_aggregator(item->aggr->Aggrtype()); -} - - -void Item_sum::mark_as_sum_func() -{ - SELECT_LEX *cur_select= current_thd->lex->current_select; - cur_select->n_sum_items++; - cur_select->with_sum_func= 1; - const_item_cache= false; - with_sum_func= 1; - with_field= 0; - window_func_sum_expr_flag= false; -} - - -void Item_sum::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(func_name()); - /* - TODO: - The fact that func_name() may return a name with an extra '(' - is really annoying. This shoud be fixed. - */ - if (!is_aggr_sum_func()) - str->append('('); - for (uint i=0 ; i < arg_count ; i++) - { - if (i) - str->append(','); - pargs[i]->print(str, query_type); - } - str->append(')'); -} - -void Item_sum::fix_num_length_and_dec() -{ - decimals=0; - for (uint i=0 ; i < arg_count ; i++) - set_if_bigger(decimals,args[i]->decimals); - max_length=float_length(decimals); -} - -Item *Item_sum::get_tmp_table_item(THD *thd) -{ - Item_sum* sum_item= (Item_sum *) copy_or_same(thd); - if (sum_item && sum_item->result_field) // If not a const sum func - { - Field *result_field_tmp= sum_item->result_field; - for (uint i=0 ; i < sum_item->arg_count ; i++) - { - Item *arg= sum_item->args[i]; - if (!arg->const_item()) - { - if (arg->type() == Item::FIELD_ITEM) - ((Item_field*) arg)->field= result_field_tmp++; - else - sum_item->args[i]= new (thd->mem_root) Item_temptable_field(thd, result_field_tmp++); - } - } - } - return sum_item; -} - - -void Item_sum::update_used_tables () -{ - if (!Item_sum::const_item()) - { - used_tables_cache= 0; - for (uint i=0 ; i < arg_count ; i++) - { - args[i]->update_used_tables(); - used_tables_cache|= args[i]->used_tables(); - } - /* - MariaDB: don't run the following { - - used_tables_cache&= PSEUDO_TABLE_BITS; - - // the aggregate function is aggregated into its local context - used_tables_cache|= ((table_map)1 << aggr_sel->join->tables) - 1; - - } because if we do it, table elimination will assume that - - constructs like "COUNT(*)" use columns from all tables - - so, it is not possible to eliminate any table - our solution for COUNT(*) is that it has - item->used_tables() == 0 && !item->const_item() - */ - } -} - - -Item *Item_sum::set_arg(uint i, THD *thd, Item *new_val) -{ - thd->change_item_tree(args + i, new_val); - return new_val; -} - - -int Item_sum::set_aggregator(Aggregator::Aggregator_type aggregator) -{ - /* - 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()) - { - 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; - }; - return aggr ? FALSE : TRUE; -} - - -void Item_sum::cleanup() -{ - if (aggr) - { - delete aggr; - aggr= NULL; - } - Item_result_field::cleanup(); - const_item_cache= false; -} - -Item *Item_sum::result_item(THD *thd, Field *field) -{ - return new (thd->mem_root) Item_field(thd, field); -} - -bool Item_sum::check_vcol_func_processor(void *arg) -{ - return mark_unsupported_function(func_name(), - is_aggr_sum_func() ? ")" : "()", - arg, VCOL_IMPOSSIBLE); -} - - -/** - Compare keys consisting of single field that cannot be compared as binary. - - Used by the Unique class to compare keys. Will do correct comparisons - for all field types. - - @param arg Pointer to the relevant Field class instance - @param key1 left key image - @param key2 right key image - @return comparison result - @retval < 0 if key1 < key2 - @retval = 0 if key1 = key2 - @retval > 0 if key1 > key2 -*/ - -int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2) -{ - Field *f= (Field*) arg; - return f->cmp(key1, key2); -} - - -C_MODE_START - -int count_distinct_walk(void *elem, element_count count, void *arg) -{ - (*((ulonglong*)arg))++; - return 0; -} - -C_MODE_END - - -/** - Correctly compare composite keys. - - Used by the Unique class to compare keys. Will do correct comparisons - for composite keys with various field types. - - @param arg Pointer to the relevant Aggregator_distinct instance - @param key1 left key image - @param key2 right key image - @return comparison result - @retval <0 if key1 < key2 - @retval =0 if key1 = key2 - @retval >0 if key1 > key2 -*/ - -int Aggregator_distinct::composite_key_cmp(void* arg, uchar* key1, uchar* key2) -{ - Aggregator_distinct *aggr= (Aggregator_distinct *) arg; - Field **field = aggr->table->field; - Field **field_end= field + aggr->table->s->fields; - uint32 *lengths=aggr->field_lengths; - for (; field < field_end; ++field) - { - Field* f = *field; - int len = *lengths++; - int res = f->cmp(key1, key2); - if (res) - return res; - key1 += len; - key2 += len; - } - return 0; -} - - -/***************************************************************************/ - -C_MODE_START - -/* Declarations for auxilary C-callbacks */ - -int simple_raw_key_cmp(void* arg, const void* key1, const void* key2) -{ - return memcmp(key1, key2, *(uint *) arg); -} - - -static int item_sum_distinct_walk_for_count(void *element, - element_count num_of_dups, - void *item) -{ - return ((Aggregator_distinct*) (item))->unique_walk_function_for_count(element); -} - - -static int item_sum_distinct_walk(void *element, element_count num_of_dups, - void *item) -{ - return ((Aggregator_distinct*) (item))->unique_walk_function(element); -} - -C_MODE_END - -/***************************************************************************/ -/** - Called before feeding the first row. Used to allocate/setup - the internal structures used for aggregation. - - @param thd Thread descriptor - @return status - @retval FALSE success - @retval TRUE faliure - - Prepares Aggregator_distinct to process the incoming stream. - Creates the temporary table and the Unique class if needed. - Called by Item_sum::aggregator_setup() -*/ - -bool Aggregator_distinct::setup(THD *thd) -{ - endup_done= FALSE; - /* - Setup can be called twice for ROLLUP items. This is a bug. - Please add DBUG_ASSERT(tree == 0) here when it's fixed. - */ - if (tree || table || tmp_table_param) - return FALSE; - - if (item_sum->setup(thd)) - return TRUE; - if (item_sum->sum_func() == Item_sum::COUNT_FUNC || - item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC) - { - List<Item> list; - SELECT_LEX *select_lex= thd->lex->current_select; - - if (!(tmp_table_param= new TMP_TABLE_PARAM)) - return TRUE; - - /* Create a table with an unique key over all parameters */ - for (uint i=0; i < item_sum->get_arg_count() ; i++) - { - Item *item=item_sum->get_arg(i); - if (list.push_back(item, thd->mem_root)) - return TRUE; // End of memory - if (item->const_item() && item->is_null()) - always_null= true; - } - if (always_null) - return FALSE; - count_field_types(select_lex, tmp_table_param, list, 0); - tmp_table_param->force_copy_fields= item_sum->has_force_copy_fields(); - DBUG_ASSERT(table == 0); - /* - Make create_tmp_table() convert BIT columns to BIGINT. - This is needed because BIT fields store parts of their data in table's - null bits, and we don't have methods to compare two table records, which - is needed by Unique which is used when HEAP table is used. - */ - { - List_iterator_fast<Item> li(list); - Item *item; - while ((item= li++)) - { - if (item->type() == Item::FIELD_ITEM && - ((Item_field*)item)->field->type() == FIELD_TYPE_BIT) - item->marker=4; - } - } - if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, - 0, - (select_lex->options | thd->variables.option_bits), - HA_POS_ERROR, const_cast<char*>("")))) - return TRUE; - table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows - table->no_rows=1; - - if (table->s->db_type() == heap_hton) - { - /* - No blobs, otherwise it would have been MyISAM: set up a compare - function and its arguments to use with Unique. - */ - qsort_cmp2 compare_key; - void* cmp_arg; - Field **field= table->field; - Field **field_end= field + table->s->fields; - bool all_binary= TRUE; - - for (tree_key_length= 0; field < field_end; ++field) - { - Field *f= *field; - enum enum_field_types type= f->type(); - tree_key_length+= f->pack_length(); - if ((type == MYSQL_TYPE_VARCHAR) || - (!f->binary() && (type == MYSQL_TYPE_STRING || - type == MYSQL_TYPE_VAR_STRING))) - { - all_binary= FALSE; - break; - } - } - if (all_binary) - { - cmp_arg= (void*) &tree_key_length; - compare_key= (qsort_cmp2) simple_raw_key_cmp; - } - else - { - if (table->s->fields == 1) - { - /* - If we have only one field, which is the most common use of - count(distinct), it is much faster to use a simpler key - compare method that can take advantage of not having to worry - about other fields. - */ - compare_key= (qsort_cmp2) simple_str_key_cmp; - cmp_arg= (void*) table->field[0]; - /* tree_key_length has been set already */ - } - else - { - uint32 *length; - compare_key= (qsort_cmp2) composite_key_cmp; - cmp_arg= (void*) this; - field_lengths= (uint32*) thd->alloc(table->s->fields * sizeof(uint32)); - for (tree_key_length= 0, length= field_lengths, field= table->field; - field < field_end; ++field, ++length) - { - *length= (*field)->pack_length(); - tree_key_length+= *length; - } - } - } - DBUG_ASSERT(tree == 0); - tree= new Unique(compare_key, cmp_arg, tree_key_length, - item_sum->ram_limitation(thd)); - /* - The only time tree_key_length could be 0 is if someone does - count(distinct) on a char(0) field - stupid thing to do, - but this has to be handled - otherwise someone can crash - the server with a DoS attack - */ - if (! tree) - return TRUE; - } - return FALSE; - } - else - { - Item *arg; - DBUG_ENTER("Aggregator_distinct::setup"); - /* It's legal to call setup() more than once when in a subquery */ - if (tree) - DBUG_RETURN(FALSE); - - /* - 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. - */ - - item_sum->null_value= item_sum->maybe_null= 1; - item_sum->quick_group= 0; - - DBUG_ASSERT(item_sum->get_arg(0)->fixed); - - arg= item_sum->get_arg(0); - if (arg->const_item()) - { - (void) arg->is_null(); - if (arg->null_value) - always_null= true; - } - - if (always_null) - DBUG_RETURN(FALSE); - - Field *field= arg->type_handler()-> - make_num_distinct_aggregator_field(thd->mem_root, arg); - if (!field || !(table= create_virtual_tmp_table(thd, field))) - DBUG_RETURN(TRUE); - - /* XXX: check that the case of CHAR(0) works OK */ - tree_key_length= table->s->reclength - table->s->null_bytes; - - /* - 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. - */ - tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length, - item_sum->ram_limitation(thd)); - - DBUG_RETURN(tree == 0); - } -} - - -/** - Invalidate calculated value and clear the distinct rows. - - Frees space used by the internal data structures. - Removes the accumulated distinct rows. Invalidates the calculated result. -*/ - -void Aggregator_distinct::clear() -{ - endup_done= FALSE; - item_sum->clear(); - if (tree) - tree->reset(); - /* tree and table can be both null only if always_null */ - if (item_sum->sum_func() == Item_sum::COUNT_FUNC || - item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC) - { - if (!tree && table) - { - table->file->extra(HA_EXTRA_NO_CACHE); - table->file->ha_delete_all_rows(); - table->file->extra(HA_EXTRA_WRITE_CACHE); - } - } - else - { - item_sum->null_value= 1; - } -} - - -/** - Process incoming row. - - Add it to Unique/temp hash table if it's unique. Skip the row if - not unique. - Prepare Aggregator_distinct to process the incoming stream. - Create the temporary table and the Unique class if needed. - Called by Item_sum::aggregator_add(). - To actually get the result value in item_sum's buffers - Aggregator_distinct::endup() must be called. - - @return status - @retval FALSE success - @retval TRUE failure -*/ - -bool Aggregator_distinct::add() -{ - if (always_null) - return 0; - - if (item_sum->sum_func() == Item_sum::COUNT_FUNC || - item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC) - { - int error; - copy_fields(tmp_table_param); - if (copy_funcs(tmp_table_param->items_to_copy, table->in_use)) - return TRUE; - - for (Field **field=table->field ; *field ; field++) - if ((*field)->is_real_null(0)) - return 0; // Don't count NULL - - if (tree) - { - /* - The first few bytes of record (at least one) are just markers - for deleted and NULLs. We want to skip them since they will - bloat the tree without providing any valuable info. Besides, - key_length used to initialize the tree didn't include space for them. - */ - return tree->unique_add(table->record[0] + table->s->null_bytes); - } - if ((error= table->file->ha_write_tmp_row(table->record[0])) && - table->file->is_fatal_error(error, HA_CHECK_DUP)) - return TRUE; - return FALSE; - } - else - { - item_sum->get_arg(0)->save_in_field(table->field[0], FALSE); - if (table->field[0]->is_null()) - return 0; - DBUG_ASSERT(tree); - item_sum->null_value= 0; - /* - '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); - } -} - - -/** - Calculate the aggregate function value. - - Since Distinct_aggregator::add() just collects the distinct rows, - we must go over the distinct rows and feed them to the aggregation - function before returning its value. - This is what endup () does. It also sets the result validity flag - endup_done to TRUE so it will not recalculate the aggregate value - again if the Item_sum hasn't been reset. -*/ - -void Aggregator_distinct::endup() -{ - /* prevent consecutive recalculations */ - if (endup_done) - return; - - /* we are going to calculate the aggregate value afresh */ - item_sum->clear(); - - /* The result will definitely be null : no more calculations needed */ - if (always_null) - return; - - if (item_sum->sum_func() == Item_sum::COUNT_FUNC || - item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC) - { - DBUG_ASSERT(item_sum->fixed == 1); - Item_sum_count *sum= (Item_sum_count *)item_sum; - if (tree && tree->elements == 0) - { - /* everything fits in memory */ - sum->count= (longlong) tree->elements_in_tree(); - endup_done= TRUE; - } - if (!tree) - { - /* there were blobs */ - table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); - sum->count= table->file->stats.records; - endup_done= TRUE; - } - } - - /* - We don't have a tree only if 'setup()' hasn't been called; - this is the case of sql_executor.cc:return_zero_rows. - */ - if (tree && !endup_done) - { - /* - All tree's values are not NULL. - Note that value of field is changed as we walk the tree, in - Aggregator_distinct::unique_walk_function, but it's always not NULL. - */ - table->field[0]->set_notnull(); - /* go over the tree of distinct keys and calculate the aggregate value */ - use_distinct_values= TRUE; - tree_walk_action func; - if (item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC) - func= item_sum_distinct_walk_for_count; - else - func= item_sum_distinct_walk; - tree->walk(table, func, (void*) this); - use_distinct_values= FALSE; - } - /* prevent consecutive recalculations */ - endup_done= TRUE; -} - - -String * -Item_sum_num::val_str(String *str) -{ - return val_string_from_real(str); -} - - -my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value) -{ - return val_decimal_from_real(decimal_value); -} - - -String * -Item_sum_int::val_str(String *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); -} - - -bool -Item_sum_num::fix_fields(THD *thd, Item **ref) -{ - DBUG_ASSERT(fixed == 0); - - if (init_sum_func_check(thd)) - return TRUE; - - decimals=0; - maybe_null= sum_func() != COUNT_FUNC; - for (uint i=0 ; i < arg_count ; i++) - { - if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1)) - return TRUE; - set_if_bigger(decimals, args[i]->decimals); - m_with_subquery|= args[i]->with_subquery(); - with_window_func|= args[i]->with_window_func; - } - result_field=0; - max_length=float_length(decimals); - null_value=1; - fix_length_and_dec(); - - if (check_sum_func(thd, ref)) - return TRUE; - - memcpy (orig_args, args, sizeof (Item *) * arg_count); - fixed= 1; - return FALSE; -} - - -bool -Item_sum_hybrid::fix_fields(THD *thd, Item **ref) -{ - DBUG_ENTER("Item_sum_hybrid::fix_fields"); - DBUG_ASSERT(fixed == 0); - - Item *item= args[0]; - - if (init_sum_func_check(thd)) - DBUG_RETURN(TRUE); - - // 'item' can be changed during fix_fields - if ((!item->fixed && item->fix_fields(thd, args)) || - (item= args[0])->check_cols(1)) - DBUG_RETURN(TRUE); - - m_with_subquery= args[0]->with_subquery(); - with_window_func|= args[0]->with_window_func; - - fix_length_and_dec(); - if (!is_window_func_sum_expr()) - setup_hybrid(thd, args[0], NULL); - result_field=0; - - if (check_sum_func(thd, ref)) - DBUG_RETURN(TRUE); - - orig_args[0]= args[0]; - fixed= 1; - DBUG_RETURN(FALSE); -} - - -void Item_sum_hybrid::fix_length_and_dec() -{ - DBUG_ASSERT(args[0]->field_type() == args[0]->real_item()->field_type()); - DBUG_ASSERT(args[0]->result_type() == args[0]->real_item()->result_type()); - (void) args[0]->type_handler()->Item_sum_hybrid_fix_length_and_dec(this); -} - - -/** - MIN/MAX function setup. - - @param item argument of MIN/MAX function - @param value_arg calculated value of MIN/MAX function - - @details - Setup cache/comparator of MIN/MAX functions. When called by the - copy_or_same function value_arg parameter contains calculated value - of the original MIN/MAX object and it is saved in this object's cache. - - We mark the value and arg_cache with 'RAND_TABLE_BIT' to ensure - that Arg_comparator::compare_datetime() doesn't allocate new - item inside of Arg_comparator. This would cause compare_datetime() - and Item_sum_min::add() to use different values! -*/ - -void Item_sum_hybrid::setup_hybrid(THD *thd, Item *item, Item *value_arg) -{ - DBUG_ENTER("Item_sum_hybrid::setup_hybrid"); - if (!(value= item->get_cache(thd))) - DBUG_VOID_RETURN; - value->setup(thd, item); - value->store(value_arg); - /* Don't cache value, as it will change */ - if (!item->const_item()) - value->set_used_tables(RAND_TABLE_BIT); - if (!(arg_cache= item->get_cache(thd))) - DBUG_VOID_RETURN; - arg_cache->setup(thd, item); - /* Don't cache value, as it will change */ - if (!item->const_item()) - arg_cache->set_used_tables(RAND_TABLE_BIT); - cmp= new Arg_comparator(); - if (cmp) - cmp->set_cmp_func(this, (Item**)&arg_cache, (Item**)&value, FALSE); - DBUG_VOID_RETURN; -} - - -Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table) -{ - DBUG_ENTER("Item_sum_hybrid::create_tmp_field"); - - if (args[0]->type() == Item::FIELD_ITEM) - { - Field *field= ((Item_field*) args[0])->field; - if ((field= create_tmp_field_from_field(table->in_use, field, &name, - table, NULL))) - field->flags&= ~NOT_NULL_FLAG; - DBUG_RETURN(field); - } - DBUG_RETURN(tmp_table_field_from_field_type(table)); -} - -/*********************************************************************** -** Item_sum_sp class -***********************************************************************/ - -Item_sum_sp::Item_sum_sp(THD *thd, Name_resolution_context *context_arg, - sp_name *name_arg, sp_head *sp, List<Item> &list) - :Item_sum(thd, list), Item_sp(thd, context_arg, name_arg) -{ - maybe_null= 1; - quick_group= 0; - m_sp= sp; -} - -Item_sum_sp::Item_sum_sp(THD *thd, Name_resolution_context *context_arg, - sp_name *name_arg, sp_head *sp) - :Item_sum(thd), Item_sp(thd, context_arg, name_arg) -{ - maybe_null= 1; - quick_group= 0; - m_sp= sp; -} - - -bool -Item_sum_sp::fix_fields(THD *thd, Item **ref) -{ - DBUG_ASSERT(fixed == 0); - if (init_sum_func_check(thd)) - return TRUE; - decimals= 0; - - m_sp= m_sp ? m_sp : sp_handler_function.sp_find_routine(thd, m_name, true); - - if (!m_sp) - { - my_missing_function_error(m_name->m_name, ErrConvDQName(m_name).ptr()); - context->process_error(thd); - return TRUE; - } - - if (init_result_field(thd, max_length, maybe_null, &null_value, &name)) - return TRUE; - - for (uint i= 0 ; i < arg_count ; i++) - { - if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1)) - return TRUE; - set_if_bigger(decimals, args[i]->decimals); - m_with_subquery|= args[i]->with_subquery(); - with_window_func|= args[i]->with_window_func; - } - result_field= NULL; - max_length= float_length(decimals); - null_value= 1; - fix_length_and_dec(); - - if (check_sum_func(thd, ref)) - return TRUE; - - memcpy(orig_args, args, sizeof(Item *) * arg_count); - fixed= 1; - return FALSE; -} - -/** - Execute function to store value in result field. - This is called when we need the value to be returned for the function. - Here we send a signal in form of the server status that all rows have been - fetched and now we have to exit from the function with the return value. - @return Function returns error status. - @retval FALSE on success. - @retval TRUE if an error occurred. -*/ - -bool -Item_sum_sp::execute() -{ - THD *thd= current_thd; - bool res; - uint old_server_status= thd->server_status; - - /* We set server status so we can send a signal to exit from the - function with the return value. */ - - thd->server_status= SERVER_STATUS_LAST_ROW_SENT; - res= Item_sp::execute(thd, &null_value, args, arg_count); - thd->server_status= old_server_status; - return res; -} - -/** - Handles the aggregation of the values. - @note: See class description for more details on how and why this is done. - @return The error state. - @retval FALSE on success. - @retval TRUE if an error occurred. -*/ - -bool -Item_sum_sp::add() -{ - return execute_impl(current_thd, args, arg_count); -} - - -void -Item_sum_sp::clear() -{ - delete func_ctx; - func_ctx= NULL; - sp_query_arena->free_items(); - free_root(&sp_mem_root, MYF(0)); -} - -const Type_handler *Item_sum_sp::type_handler() const -{ - DBUG_ENTER("Item_sum_sp::type_handler"); - DBUG_PRINT("info", ("m_sp = %p", (void *) m_sp)); - DBUG_ASSERT(sp_result_field); - // This converts ENUM/SET to STRING - const Type_handler *handler= sp_result_field->type_handler(); - DBUG_RETURN(handler->type_handler_for_item_field()); -} - -void -Item_sum_sp::cleanup() -{ - Item_sp::cleanup(); - Item_sum::cleanup(); -} - -/** - Initialize local members with values from the Field interface. - @note called from Item::fix_fields. -*/ - -void -Item_sum_sp::fix_length_and_dec() -{ - DBUG_ENTER("Item_sum_sp::fix_length_and_dec"); - DBUG_ASSERT(sp_result_field); - Type_std_attributes::set(sp_result_field); - Item_sum::fix_length_and_dec(); - DBUG_VOID_RETURN; -} - -const char * -Item_sum_sp::func_name() const -{ - THD *thd= current_thd; - return Item_sp::func_name(thd); -} - -/*********************************************************************** -** reset and add of sum_func -***********************************************************************/ - -/** - @todo - check if the following assignments are really needed -*/ -Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item) - :Item_sum_num(thd, item), - Type_handler_hybrid_field_type(item), - direct_added(FALSE), direct_reseted_field(FALSE), - curr_dec_buff(item->curr_dec_buff), - count(item->count) -{ - /* TODO: check if the following assignments are really needed */ - if (result_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); -} - - -void Item_sum_sum::cleanup() -{ - DBUG_ENTER("Item_sum_sum::cleanup"); - direct_added= direct_reseted_field= FALSE; - Item_sum_num::cleanup(); - DBUG_VOID_RETURN; -} - - -void Item_sum_sum::clear() -{ - DBUG_ENTER("Item_sum_sum::clear"); - null_value=1; - count= 0; - if (result_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_double() -{ - set_handler(&type_handler_double); // Change FLOAT to DOUBLE - decimals= args[0]->decimals; - sum= 0.0; -} - - -void Item_sum_sum::fix_length_and_dec_decimal() -{ - set_handler(&type_handler_newdecimal); // Change temporal to new DECIMAL - decimals= args[0]->decimals; - /* SUM result can't be longer than length(arg) + length(MAX_ROWS) */ - int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS; - max_length= my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag); - curr_dec_buff= 0; - my_decimal_set_zero(dec_buffs); -} - - -void Item_sum_sum::fix_length_and_dec() -{ - DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); - maybe_null=null_value=1; - args[0]->cast_to_int_type_handler()->Item_sum_sum_fix_length_and_dec(this); - DBUG_PRINT("info", ("Type: %s (%d, %d)", type_handler()->name().ptr(), - max_length, (int) decimals)); - DBUG_VOID_RETURN; -} - - -void Item_sum_sum::direct_add(my_decimal *add_sum_decimal) -{ - DBUG_ENTER("Item_sum_sum::direct_add"); - DBUG_PRINT("info", ("add_sum_decimal: %p", add_sum_decimal)); - direct_added= TRUE; - direct_reseted_field= FALSE; - if (add_sum_decimal) - { - direct_sum_is_null= FALSE; - direct_sum_decimal= *add_sum_decimal; - } - else - { - direct_sum_is_null= TRUE; - direct_sum_decimal= decimal_zero; - } - DBUG_VOID_RETURN; -} - - -void Item_sum_sum::direct_add(double add_sum_real, bool add_sum_is_null) -{ - DBUG_ENTER("Item_sum_sum::direct_add"); - DBUG_PRINT("info", ("add_sum_real: %f", add_sum_real)); - direct_added= TRUE; - direct_reseted_field= FALSE; - direct_sum_is_null= add_sum_is_null; - direct_sum_real= add_sum_real; - DBUG_VOID_RETURN; -} - - -bool Item_sum_sum::add() -{ - DBUG_ENTER("Item_sum_sum::add"); - add_helper(false); - DBUG_RETURN(0); -} - -void Item_sum_sum::add_helper(bool perform_removal) -{ - DBUG_ENTER("Item_sum_sum::add_helper"); - - if (result_type() == DECIMAL_RESULT) - { - if (unlikely(direct_added)) - { - /* Add value stored by Item_sum_sum::direct_add */ - DBUG_ASSERT(!perform_removal); - - direct_added= FALSE; - if (likely(!direct_sum_is_null)) - { - my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1), - &direct_sum_decimal, dec_buffs + curr_dec_buff); - curr_dec_buff^= 1; - null_value= 0; - } - } - else - { - direct_reseted_field= FALSE; - my_decimal value; - const my_decimal *val= aggr->arg_val_decimal(&value); - if (!aggr->arg_is_null(true)) - { - if (perform_removal) - { - if (count > 0) - { - my_decimal_sub(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff ^ 1), - dec_buffs + curr_dec_buff, val); - count--; - } - else - DBUG_VOID_RETURN; - } - else - { - count++; - 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= (count > 0) ? 0 : 1; - } - } - } - else - { - if (unlikely(direct_added)) - { - /* Add value stored by Item_sum_sum::direct_add */ - DBUG_ASSERT(!perform_removal); - - direct_added= FALSE; - if (!direct_sum_is_null) - { - sum+= direct_sum_real; - null_value= 0; - } - } - else - { - direct_reseted_field= FALSE; - if (perform_removal && count > 0) - sum-= aggr->arg_val_real(); - else - sum+= aggr->arg_val_real(); - if (!aggr->arg_is_null(true)) - { - if (perform_removal) - { - if (count > 0) - { - count--; - } - } - else - count++; - - null_value= (count > 0) ? 0 : 1; - } - } - } - DBUG_VOID_RETURN; -} - - -longlong Item_sum_sum::val_int() -{ - DBUG_ASSERT(fixed == 1); - if (aggr) - aggr->endup(); - if (result_type() == DECIMAL_RESULT) - { - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag, - &result); - return result; - } - return val_int_from_real(); -} - - -double Item_sum_sum::val_real() -{ - DBUG_ASSERT(fixed == 1); - if (aggr) - aggr->endup(); - if (result_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 (aggr) - aggr->endup(); - if (result_type() == DECIMAL_RESULT) - return val_string_from_decimal(str); - return val_string_from_real(str); -} - - -my_decimal *Item_sum_sum::val_decimal(my_decimal *val) -{ - if (aggr) - aggr->endup(); - if (result_type() == DECIMAL_RESULT) - return null_value ? NULL : (dec_buffs + curr_dec_buff); - return val_decimal_from_real(val); -} - -void Item_sum_sum::remove() -{ - DBUG_ENTER("Item_sum_sum::remove"); - add_helper(true); - DBUG_VOID_RETURN; -} - -/** - Aggregate a distinct row from the distinct hash table. - - Called for each row into the hash table 'Aggregator_distinct::table'. - Includes the current distinct row into the calculation of the - aggregate value. Uses the Field classes to get the value from the row. - This function is used for AVG/SUM(DISTINCT). For COUNT(DISTINCT) - it's called only when there are no blob arguments and the data don't - fit into memory (so Unique makes persisted trees on disk). - - @param element pointer to the row data. - - @return status - @retval FALSE success - @retval TRUE failure -*/ - -bool Aggregator_distinct::unique_walk_function(void *element) -{ - memcpy(table->field[0]->ptr, element, tree_key_length); - item_sum->add(); - return 0; -} - - -/* - A variant of unique_walk_function() that is to be used with Item_sum_count. - - COUNT is a special aggregate function: it doesn't need the values, it only - needs to count them. COUNT needs to know the values are not NULLs, but NULL - values are not put into the Unique, so we don't need to check for NULLs here. -*/ - -bool Aggregator_distinct::unique_walk_function_for_count(void *element) -{ - Item_sum_count *sum= (Item_sum_count *)item_sum; - sum->count++; - return 0; -} - - -Aggregator_distinct::~Aggregator_distinct() -{ - if (tree) - { - delete tree; - tree= NULL; - } - if (table) - { - free_tmp_table(table->in_use, table); - table=NULL; - } - if (tmp_table_param) - { - delete tmp_table_param; - tmp_table_param= NULL; - } -} - - -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(bool use_null_value) -{ - Item **item= item_sum->args; - const uint item_count= item_sum->arg_count; - if (use_null_value) - { - for (uint i= 0; i < item_count; i++) - { - if (item[i]->null_value) - return true; - } - } - else - { - for (uint i= 0; i < item_count; i++) - { - if (item[i]->maybe_null && item[i]->is_null()) - return true; - } - } - return false; -} - - -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(bool use_null_value) -{ - if (use_distinct_values) - { - const bool rc= table->field[0]->is_null(); - DBUG_ASSERT(!rc); // NULLs are never stored in 'tree' - return rc; - } - return use_null_value ? - item_sum->args[0]->null_value : - (item_sum->args[0]->maybe_null && item_sum->args[0]->is_null()); -} - - -Item *Item_sum_count::copy_or_same(THD* thd) -{ - DBUG_ENTER("Item_sum_count::copy_or_same"); - DBUG_RETURN(new (thd->mem_root) Item_sum_count(thd, this)); -} - - -void Item_sum_count::direct_add(longlong add_count) -{ - DBUG_ENTER("Item_sum_count::direct_add"); - DBUG_PRINT("info", ("add_count: %lld", add_count)); - direct_counted= TRUE; - direct_reseted_field= FALSE; - direct_count= add_count; - DBUG_VOID_RETURN; -} - - -void Item_sum_count::clear() -{ - DBUG_ENTER("Item_sum_count::clear"); - count= 0; - DBUG_VOID_RETURN; -} - - -bool Item_sum_count::add() -{ - DBUG_ENTER("Item_sum_count::add"); - if (direct_counted) - { - direct_counted= FALSE; - count+= direct_count; - } - else - { - direct_reseted_field= FALSE; - if (aggr->arg_is_null(false)) - DBUG_RETURN(0); - count++; - } - DBUG_RETURN(0); -} - - -/* - Remove a row. This is used by window functions. -*/ - -void Item_sum_count::remove() -{ - DBUG_ASSERT(aggr->Aggrtype() == Aggregator::SIMPLE_AGGREGATOR); - if (aggr->arg_is_null(false)) - return; - if (count > 0) - count--; -} - -longlong Item_sum_count::val_int() -{ - DBUG_ENTER("Item_sum_count::val_int"); - DBUG_ASSERT(fixed == 1); - if (aggr) - aggr->endup(); - DBUG_RETURN((longlong)count); -} - - -void Item_sum_count::cleanup() -{ - DBUG_ENTER("Item_sum_count::cleanup"); - count= 0; - direct_counted= FALSE; - direct_reseted_field= FALSE; - Item_sum_int::cleanup(); - DBUG_VOID_RETURN; -} - - -/* - Avgerage -*/ - -void Item_sum_avg::fix_length_and_dec_decimal() -{ - Item_sum_sum::fix_length_and_dec_decimal(); - int precision= args[0]->decimal_precision() + prec_increment; - decimals= MY_MIN(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE); - max_length= my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag); - f_precision= MY_MIN(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION); - f_scale= args[0]->decimals; - dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale); -} - - -void Item_sum_avg::fix_length_and_dec_double() -{ - Item_sum_sum::fix_length_and_dec_double(); - decimals= MY_MIN(args[0]->decimals + prec_increment, - FLOATING_POINT_DECIMALS); - max_length= MY_MIN(args[0]->max_length + prec_increment, float_length(decimals)); -} - - -void Item_sum_avg::fix_length_and_dec() -{ - DBUG_ENTER("Item_sum_avg::fix_length_and_dec"); - prec_increment= current_thd->variables.div_precincrement; - maybe_null=null_value=1; - args[0]->cast_to_int_type_handler()->Item_sum_avg_fix_length_and_dec(this); - DBUG_PRINT("info", ("Type: %s (%d, %d)", type_handler()->name().ptr(), - max_length, (int) decimals)); - DBUG_VOID_RETURN; -} - - -Item *Item_sum_avg::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_sum_avg(thd, this); -} - - -Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table) -{ - - if (group) - { - /* - We must store both value and counter in the temporary table in one field. - The easiest way is to do this is to store both value in a string - and unpack on access. - */ - Field *field= new (table->in_use->mem_root) - Field_string(((result_type() == DECIMAL_RESULT) ? - dec_bin_size : sizeof(double)) + sizeof(longlong), - 0, &name, &my_charset_bin); - if (field) - field->init(table); - return field; - } - return tmp_table_field_from_field_type(table); -} - - -void Item_sum_avg::clear() -{ - Item_sum_sum::clear(); - count=0; -} - - -bool Item_sum_avg::add() -{ - if (Item_sum_sum::add()) - return TRUE; - if (!aggr->arg_is_null(true)) - count++; - return FALSE; -} - -void Item_sum_avg::remove() -{ - Item_sum_sum::remove(); - if (!aggr->arg_is_null(true)) - { - if (count > 0) - count--; - } -} - -double Item_sum_avg::val_real() -{ - DBUG_ASSERT(fixed == 1); - if (aggr) - aggr->endup(); - if (!count) - { - null_value=1; - return 0.0; - } - return Item_sum_sum::val_real() / ulonglong2double(count); -} - - -my_decimal *Item_sum_avg::val_decimal(my_decimal *val) -{ - my_decimal cnt; - const my_decimal *sum_dec; - DBUG_ASSERT(fixed == 1); - if (aggr) - aggr->endup(); - if (!count) - { - null_value=1; - return NULL; - } - - /* - For non-DECIMAL result_type() the division will be done in - Item_sum_avg::val_real(). - */ - if (result_type() != DECIMAL_RESULT) - return val_decimal_from_real(val); - - sum_dec= dec_buffs + curr_dec_buff; - int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); - my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, prec_increment); - return val; -} - - -String *Item_sum_avg::val_str(String *str) -{ - if (aggr) - aggr->endup(); - if (result_type() == DECIMAL_RESULT) - return val_string_from_decimal(str); - return val_string_from_real(str); -} - - -/* - Standard deviation -*/ - -double Item_sum_std::val_real() -{ - DBUG_ASSERT(fixed == 1); - double nr= Item_sum_variance::val_real(); - if (my_isinf(nr)) - return DBL_MAX; - DBUG_ASSERT(nr >= 0.0); - return sqrt(nr); -} - -Item *Item_sum_std::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_sum_std(thd, this); -} - - -Item *Item_sum_std::result_item(THD *thd, Field *field) -{ - return new (thd->mem_root) Item_std_field(thd, this); -} - - -/* - Variance -*/ - - -/** - Variance implementation for floating-point implementations, without - catastrophic cancellation, from Knuth's _TAoCP_, 3rd ed, volume 2, pg232. - This alters the value at m, s, and increments count. -*/ - -/* - These two functions are used by the Item_sum_variance and the - Item_variance_field classes, which are unrelated, and each need to calculate - variance. The difference between the two classes is that the first is used - for a mundane SELECT, while the latter is used in a GROUPing SELECT. -*/ -static void variance_fp_recurrence_next(double *m, double *s, ulonglong *count, double nr) -{ - *count += 1; - - if (*count == 1) - { - *m= nr; - *s= 0; - } - else - { - double m_kminusone= *m; - *m= m_kminusone + (nr - m_kminusone) / (double) *count; - *s= *s + (nr - m_kminusone) * (nr - *m); - } -} - - -static double variance_fp_recurrence_result(double s, ulonglong count, bool is_sample_variance) -{ - if (count == 1) - return 0.0; - - if (is_sample_variance) - return s / (count - 1); - - /* else, is a population variance */ - return s / count; -} - - -Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item): - Item_sum_num(thd, item), - count(item->count), sample(item->sample), - prec_increment(item->prec_increment) -{ - recurrence_m= item->recurrence_m; - recurrence_s= item->recurrence_s; -} - - -void Item_sum_variance::fix_length_and_dec_double() -{ - DBUG_ASSERT(Item_sum_variance::type_handler() == &type_handler_double); - decimals= MY_MIN(args[0]->decimals + 4, FLOATING_POINT_DECIMALS); -} - - -void Item_sum_variance::fix_length_and_dec_decimal() -{ - DBUG_ASSERT(Item_sum_variance::type_handler() == &type_handler_double); - int precision= args[0]->decimal_precision() * 2 + prec_increment; - decimals= MY_MIN(args[0]->decimals + prec_increment, - FLOATING_POINT_DECIMALS - 1); - max_length= my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag); -} - - -void Item_sum_variance::fix_length_and_dec() -{ - DBUG_ENTER("Item_sum_variance::fix_length_and_dec"); - maybe_null= null_value= 1; - prec_increment= current_thd->variables.div_precincrement; - - /* - According to the SQL2003 standard (Part 2, Foundations; sec 10.9, - aggregate function; paragraph 7h of Syntax Rules), "the declared - type of the result is an implementation-defined aproximate numeric - type. - */ - - args[0]->type_handler()->Item_sum_variance_fix_length_and_dec(this); - DBUG_PRINT("info", ("Type: %s (%d, %d)", type_handler()->name().ptr(), - 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); -} - - -/** - Create a new field to match the type of value we're expected to yield. - If we're grouping, then we need some space to serialize variables into, to - pass around. -*/ -Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table) -{ - Field *field; - if (group) - { - /* - We must store both value and counter in the temporary table in one field. - The easiest way is to do this is to store both value in a string - and unpack on access. - */ - field= new Field_string(sizeof(double)*2 + sizeof(longlong), 0, - &name, &my_charset_bin); - } - else - field= new Field_double(max_length, maybe_null, &name, decimals, - TRUE); - - if (field != NULL) - field->init(table); - - return field; -} - - -void Item_sum_variance::clear() -{ - count= 0; -} - -bool Item_sum_variance::add() -{ - /* - Why use a temporary variable? We don't know if it is null until we - evaluate it, which has the side-effect of setting null_value . - */ - double nr= args[0]->val_real(); - - if (!args[0]->null_value) - variance_fp_recurrence_next(&recurrence_m, &recurrence_s, &count, nr); - return 0; -} - -double Item_sum_variance::val_real() -{ - DBUG_ASSERT(fixed == 1); - - /* - 'sample' is a 1/0 boolean value. If it is 1/true, id est this is a sample - variance call, then we should set nullness when the count of the items - is one or zero. If it's zero, i.e. a population variance, then we only - set nullness when the count is zero. - - Another way to read it is that 'sample' is the numerical threshhold, at and - below which a 'count' number of items is called NULL. - */ - DBUG_ASSERT((sample == 0) || (sample == 1)); - if (count <= sample) - { - null_value=1; - return 0.0; - } - - null_value=0; - return variance_fp_recurrence_result(recurrence_s, count, sample); -} - - -my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf) -{ - DBUG_ASSERT(fixed == 1); - return val_decimal_from_real(dec_buf); -} - - -void Item_sum_variance::reset_field() -{ - double nr; - uchar *res= result_field->ptr; - - nr= args[0]->val_real(); /* sets null_value as side-effect */ - - if (args[0]->null_value) - bzero(res,sizeof(double)*2+sizeof(longlong)); - else - { - /* Serialize format is (double)m, (double)s, (longlong)count */ - ulonglong tmp_count; - double tmp_s; - float8store(res, nr); /* recurrence variable m */ - tmp_s= 0.0; - float8store(res + sizeof(double), tmp_s); - tmp_count= 1; - int8store(res + sizeof(double)*2, tmp_count); - } -} - - -void Item_sum_variance::update_field() -{ - ulonglong field_count; - uchar *res=result_field->ptr; - - double nr= args[0]->val_real(); /* sets null_value as side-effect */ - - if (args[0]->null_value) - return; - - /* Serialize format is (double)m, (double)s, (longlong)count */ - double field_recurrence_m, field_recurrence_s; - float8get(field_recurrence_m, res); - float8get(field_recurrence_s, res + sizeof(double)); - field_count=sint8korr(res+sizeof(double)*2); - - variance_fp_recurrence_next(&field_recurrence_m, &field_recurrence_s, &field_count, nr); - - float8store(res, field_recurrence_m); - float8store(res + sizeof(double), field_recurrence_s); - res+= sizeof(double)*2; - int8store(res,field_count); -} - - -Item *Item_sum_variance::result_item(THD *thd, Field *field) -{ - return new (thd->mem_root) Item_variance_field(thd, this); -} - -/* min & max */ - -void Item_sum_hybrid::clear() -{ - DBUG_ENTER("Item_sum_hybrid::clear"); - value->clear(); - null_value= 1; - DBUG_VOID_RETURN; -} - - -bool -Item_sum_hybrid::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) -{ - DBUG_ASSERT(fixed == 1); - if (null_value) - return true; - bool retval= value->get_date(ltime, fuzzydate); - if ((null_value= value->null_value)) - DBUG_ASSERT(retval == true); - return retval; -} - - -void Item_sum_hybrid::direct_add(Item *item) -{ - DBUG_ENTER("Item_sum_hybrid::direct_add"); - DBUG_PRINT("info", ("item: %p", item)); - direct_added= TRUE; - direct_item= item; - DBUG_VOID_RETURN; -} - - -double Item_sum_hybrid::val_real() -{ - DBUG_ENTER("Item_sum_hybrid::val_real"); - DBUG_ASSERT(fixed == 1); - if (null_value) - DBUG_RETURN(0.0); - double retval= value->val_real(); - if ((null_value= value->null_value)) - DBUG_ASSERT(retval == 0.0); - DBUG_RETURN(retval); -} - -longlong Item_sum_hybrid::val_int() -{ - DBUG_ENTER("Item_sum_hybrid::val_int"); - DBUG_ASSERT(fixed == 1); - if (null_value) - DBUG_RETURN(0); - longlong retval= value->val_int(); - if ((null_value= value->null_value)) - DBUG_ASSERT(retval == 0); - DBUG_RETURN(retval); -} - - -my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val) -{ - DBUG_ENTER("Item_sum_hybrid::val_decimal"); - DBUG_ASSERT(fixed == 1); - if (null_value) - DBUG_RETURN(0); - my_decimal *retval= value->val_decimal(val); - if ((null_value= value->null_value)) - DBUG_ASSERT(retval == NULL); - DBUG_RETURN(retval); -} - - -String * -Item_sum_hybrid::val_str(String *str) -{ - DBUG_ENTER("Item_sum_hybrid::val_str"); - DBUG_ASSERT(fixed == 1); - if (null_value) - DBUG_RETURN(0); - String *retval= value->val_str(str); - if ((null_value= value->null_value)) - DBUG_ASSERT(retval == NULL); - DBUG_RETURN(retval); -} - - -void Item_sum_hybrid::cleanup() -{ - DBUG_ENTER("Item_sum_hybrid::cleanup"); - Item_sum::cleanup(); - if (cmp) - delete cmp; - cmp= 0; - /* - by default it is TRUE to avoid TRUE reporting by - Item_func_not_all/Item_func_nop_all if this item was never called. - - no_rows_in_result() set it to FALSE if was not results found. - If some results found it will be left unchanged. - */ - was_values= TRUE; - DBUG_VOID_RETURN; -} - -void Item_sum_hybrid::no_rows_in_result() -{ - DBUG_ENTER("Item_sum_hybrid::no_rows_in_result"); - /* We may be called here twice in case of ref field in function */ - if (was_values) - { - was_values= FALSE; - was_null_value= value->null_value; - clear(); - } - DBUG_VOID_RETURN; -} - -void Item_sum_hybrid::restore_to_before_no_rows_in_result() -{ - if (!was_values) - { - was_values= TRUE; - null_value= value->null_value= was_null_value; - } -} - - -Item *Item_sum_min::copy_or_same(THD* thd) -{ - DBUG_ENTER("Item_sum_min::copy_or_same"); - Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this); - item->setup_hybrid(thd, args[0], value); - DBUG_RETURN(item); -} - - -bool Item_sum_min::add() -{ - Item *tmp_item; - DBUG_ENTER("Item_sum_min::add"); - DBUG_PRINT("enter", ("this: %p", this)); - - if (unlikely(direct_added)) - { - /* Change to use direct_item */ - tmp_item= arg_cache->get_item(); - arg_cache->store(direct_item); - } - DBUG_PRINT("info", ("null_value: %s", null_value ? "TRUE" : "FALSE")); - /* args[0] < value */ - arg_cache->cache_value(); - if (!arg_cache->null_value && - (null_value || cmp->compare() < 0)) - { - value->store(arg_cache); - value->cache_value(); - null_value= 0; - } - if (unlikely(direct_added)) - { - /* Restore original item */ - direct_added= FALSE; - arg_cache->store(tmp_item); - } - DBUG_RETURN(0); -} - - -Item *Item_sum_max::copy_or_same(THD* thd) -{ - Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this); - item->setup_hybrid(thd, args[0], value); - return item; -} - - -bool Item_sum_max::add() -{ - Item *tmp_item; - DBUG_ENTER("Item_sum_max::add"); - DBUG_PRINT("enter", ("this: %p", this)); - - if (unlikely(direct_added)) - { - /* Change to use direct_item */ - tmp_item= arg_cache->get_item(); - arg_cache->store(direct_item); - } - /* args[0] > value */ - arg_cache->cache_value(); - DBUG_PRINT("info", ("null_value: %s", null_value ? "TRUE" : "FALSE")); - if (!arg_cache->null_value && - (null_value || cmp->compare() > 0)) - { - value->store(arg_cache); - value->cache_value(); - null_value= 0; - } - if (unlikely(direct_added)) - { - /* Restore original item */ - direct_added= FALSE; - arg_cache->store(tmp_item); - } - DBUG_RETURN(0); -} - - -/* bit_or and bit_and */ - -longlong Item_sum_bit::val_int() -{ - DBUG_ASSERT(fixed == 1); - return (longlong) bits; -} - - -void Item_sum_bit::clear() -{ - bits= reset_bits; - if (as_window_function) - clear_as_window(); -} - -Item *Item_sum_or::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_sum_or(thd, this); -} - -bool Item_sum_bit::clear_as_window() -{ - memset(bit_counters, 0, sizeof(bit_counters)); - num_values_added= 0; - set_bits_from_counters(); - return 0; -} - -bool Item_sum_bit::remove_as_window(ulonglong value) -{ - DBUG_ASSERT(as_window_function); - if (num_values_added == 0) - return 0; // Nothing to remove. - - for (int i= 0; i < NUM_BIT_COUNTERS; i++) - { - if (!bit_counters[i]) - { - // Don't attempt to remove values that were never added. - DBUG_ASSERT((value & (1ULL << i)) == 0); - continue; - } - bit_counters[i]-= (value & (1ULL << i)) ? 1 : 0; - } - - // Prevent overflow; - num_values_added = std::min(num_values_added, num_values_added - 1); - set_bits_from_counters(); - return 0; -} - -bool Item_sum_bit::add_as_window(ulonglong value) -{ - DBUG_ASSERT(as_window_function); - for (int i= 0; i < NUM_BIT_COUNTERS; i++) - { - bit_counters[i]+= (value & (1ULL << i)) ? 1 : 0; - } - // Prevent overflow; - num_values_added = std::max(num_values_added, num_values_added + 1); - set_bits_from_counters(); - return 0; -} - -void Item_sum_or::set_bits_from_counters() -{ - ulonglong value= 0; - for (int i= 0; i < NUM_BIT_COUNTERS; i++) - { - value|= bit_counters[i] > 0 ? (1 << i) : 0; - } - bits= value | reset_bits; -} - -bool Item_sum_or::add() -{ - ulonglong value= (ulonglong) args[0]->val_int(); - if (!args[0]->null_value) - { - if (as_window_function) - return add_as_window(value); - bits|=value; - } - return 0; -} - -void Item_sum_xor::set_bits_from_counters() -{ - ulonglong value= 0; - for (int i= 0; i < NUM_BIT_COUNTERS; i++) - { - value|= (bit_counters[i] % 2) ? (1 << i) : 0; - } - bits= value ^ reset_bits; -} - -Item *Item_sum_xor::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_sum_xor(thd, this); -} - - -bool Item_sum_xor::add() -{ - ulonglong value= (ulonglong) args[0]->val_int(); - if (!args[0]->null_value) - { - if (as_window_function) - return add_as_window(value); - bits^=value; - } - return 0; -} - -void Item_sum_and::set_bits_from_counters() -{ - ulonglong value= 0; - if (!num_values_added) - { - bits= reset_bits; - return; - } - - for (int i= 0; i < NUM_BIT_COUNTERS; i++) - { - // We've only added values of 1 for this bit. - if (bit_counters[i] == num_values_added) - value|= (1ULL << i); - } - bits= value & reset_bits; -} -Item *Item_sum_and::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_sum_and(thd, this); -} - - -bool Item_sum_and::add() -{ - ulonglong value= (ulonglong) args[0]->val_int(); - if (!args[0]->null_value) - { - if (as_window_function) - return add_as_window(value); - bits&=value; - } - return 0; -} - -/************************************************************************ -** reset result of a Item_sum with is saved in a tmp_table -*************************************************************************/ - -void Item_sum_num::reset_field() -{ - double nr= args[0]->val_real(); - uchar *res=result_field->ptr; - - if (maybe_null) - { - if (args[0]->null_value) - { - nr=0.0; - result_field->set_null(); - } - else - result_field->set_notnull(); - } - float8store(res,nr); -} - - -void Item_sum_hybrid::reset_field() -{ - Item *tmp_item, *arg0; - DBUG_ENTER("Item_sum_hybrid::reset_field"); - - arg0= args[0]; - if (unlikely(direct_added)) - { - /* Switch to use direct item */ - tmp_item= value->get_item(); - value->store(direct_item); - arg0= direct_item; - } - - switch(result_type()) { - case STRING_RESULT: - { - char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff),result_field->charset()),*res; - - res= arg0->val_str(&tmp); - if (arg0->null_value) - { - result_field->set_null(); - result_field->reset(); - } - else - { - result_field->set_notnull(); - result_field->store(res->ptr(),res->length(),tmp.charset()); - } - break; - } - case INT_RESULT: - { - longlong nr= arg0->val_int(); - - if (maybe_null) - { - if (arg0->null_value) - { - nr=0; - result_field->set_null(); - } - else - result_field->set_notnull(); - } - DBUG_PRINT("info", ("nr: %lld", nr)); - result_field->store(nr, unsigned_flag); - break; - } - case REAL_RESULT: - { - double nr= arg0->val_real(); - - if (maybe_null) - { - if (arg0->null_value) - { - nr=0.0; - result_field->set_null(); - } - else - result_field->set_notnull(); - } - result_field->store(nr); - break; - } - case DECIMAL_RESULT: - { - my_decimal value_buff, *arg_dec= arg0->val_decimal(&value_buff); - - if (maybe_null) - { - if (arg0->null_value) - result_field->set_null(); - else - result_field->set_notnull(); - } - /* - 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: - case TIME_RESULT: - DBUG_ASSERT(0); - } - - if (unlikely(direct_added)) - { - direct_added= FALSE; - value->store(tmp_item); - } - DBUG_VOID_RETURN; -} - - -void Item_sum_sum::reset_field() -{ - my_bool null_flag; - DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); - if (result_type() == DECIMAL_RESULT) - { - my_decimal value, *arg_val; - if (unlikely(direct_added)) - arg_val= &direct_sum_decimal; - else - { - if (!(arg_val= args[0]->val_decimal(&value))) - arg_val= &decimal_zero; // Null - } - result_field->store_decimal(arg_val); - } - else - { - DBUG_ASSERT(result_type() == REAL_RESULT); - double nr= likely(!direct_added) ? args[0]->val_real() : direct_sum_real; - float8store(result_field->ptr, nr); - } - - if (unlikely(direct_added)) - { - direct_added= FALSE; - direct_reseted_field= TRUE; - null_flag= direct_sum_is_null; - } - else - null_flag= args[0]->null_value; - - if (null_flag) - result_field->set_null(); - else - result_field->set_notnull(); -} - - -void Item_sum_count::reset_field() -{ - DBUG_ENTER("Item_sum_count::reset_field"); - uchar *res=result_field->ptr; - longlong nr=0; - DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); - - if (unlikely(direct_counted)) - { - nr= direct_count; - direct_counted= FALSE; - direct_reseted_field= TRUE; - } - else if (!args[0]->maybe_null || !args[0]->is_null()) - nr= 1; - DBUG_PRINT("info", ("nr: %lld", nr)); - int8store(res,nr); - DBUG_VOID_RETURN; -} - - -void Item_sum_avg::reset_field() -{ - uchar *res=result_field->ptr; - DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); - if (result_type() == DECIMAL_RESULT) - { - longlong tmp; - my_decimal value, *arg_dec= args[0]->val_decimal(&value); - if (args[0]->null_value) - { - arg_dec= &decimal_zero; - tmp= 0; - } - else - tmp= 1; - my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale); - res+= dec_bin_size; - int8store(res, tmp); - } - else - { - double nr= args[0]->val_real(); - - if (args[0]->null_value) - bzero(res,sizeof(double)+sizeof(longlong)); - else - { - longlong tmp= 1; - float8store(res,nr); - res+=sizeof(double); - int8store(res,tmp); - } - } -} - - -void Item_sum_bit::reset_field() -{ - reset_and_add(); - int8store(result_field->ptr, bits); -} - -void Item_sum_bit::update_field() -{ - // We never call update_field when computing the function as a window - // function. Setting bits to a random value invalidates the bits counters and - // the result of the bit function becomes erroneous. - DBUG_ASSERT(!as_window_function); - uchar *res=result_field->ptr; - bits= uint8korr(res); - add(); - int8store(res, bits); -} - - -/** - calc next value and merge it with field_value. -*/ - -void Item_sum_sum::update_field() -{ - DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); - if (result_type() == DECIMAL_RESULT) - { - my_decimal value, *arg_val; - my_bool null_flag; - if (unlikely(direct_added || direct_reseted_field)) - { - direct_added= direct_reseted_field= FALSE; - arg_val= &direct_sum_decimal; - null_flag= direct_sum_is_null; - } - else - { - arg_val= args[0]->val_decimal(&value); - null_flag= args[0]->null_value; - } - - if (!null_flag) - { - if (!result_field->is_null()) - { - my_decimal field_value; - my_decimal *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; - uchar *res= result_field->ptr; - my_bool null_flag; - - float8get(old_nr,res); - if (unlikely(direct_added || direct_reseted_field)) - { - direct_added= direct_reseted_field= FALSE; - null_flag= direct_sum_is_null; - nr= direct_sum_real; - } - else - { - nr= args[0]->val_real(); - null_flag= args[0]->null_value; - } - if (!null_flag) - { - old_nr+=nr; - result_field->set_notnull(); - } - float8store(res,old_nr); - } -} - - -void Item_sum_count::update_field() -{ - DBUG_ENTER("Item_sum_count::update_field"); - longlong nr; - uchar *res=result_field->ptr; - - nr=sint8korr(res); - if (unlikely(direct_counted || direct_reseted_field)) - { - direct_counted= direct_reseted_field= FALSE; - nr+= direct_count; - } - else if (!args[0]->maybe_null || !args[0]->is_null()) - nr++; - DBUG_PRINT("info", ("nr: %lld", nr)); - int8store(res,nr); - DBUG_VOID_RETURN; -} - - -void Item_sum_avg::update_field() -{ - longlong field_count; - uchar *res=result_field->ptr; - - DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); - - if (result_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); - 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; - - 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); - } - } -} - - -Item *Item_sum_avg::result_item(THD *thd, Field *field) -{ - return - result_type() == DECIMAL_RESULT ? - (Item_avg_field*) new (thd->mem_root) Item_avg_field_decimal(thd, this) : - (Item_avg_field*) new (thd->mem_root) Item_avg_field_double(thd, this); -} - - -void Item_sum_hybrid::update_field() -{ - DBUG_ENTER("Item_sum_hybrid::update_field"); - Item *tmp_item; - if (unlikely(direct_added)) - { - tmp_item= args[0]; - args[0]= direct_item; - } - switch (result_type()) { - case STRING_RESULT: - min_max_update_str_field(); - break; - case INT_RESULT: - min_max_update_int_field(); - break; - case DECIMAL_RESULT: - min_max_update_decimal_field(); - break; - default: - min_max_update_real_field(); - } - if (unlikely(direct_added)) - { - direct_added= FALSE; - args[0]= tmp_item; - } - DBUG_VOID_RETURN; -} - - -void -Item_sum_hybrid::min_max_update_str_field() -{ - DBUG_ENTER("Item_sum_hybrid::min_max_update_str_field"); - DBUG_ASSERT(cmp); - String *res_str=args[0]->val_str(&cmp->value1); - - if (!args[0]->null_value) - { - result_field->val_str(&cmp->value2); - - if (result_field->is_null() || - (cmp_sign * sortcmp(res_str,&cmp->value2,collation.collation)) < 0) - result_field->store(res_str->ptr(),res_str->length(),res_str->charset()); - result_field->set_notnull(); - } - DBUG_VOID_RETURN; -} - - -void -Item_sum_hybrid::min_max_update_real_field() -{ - double nr,old_nr; - - DBUG_ENTER("Item_sum_hybrid::min_max_update_real_field"); - old_nr=result_field->val_real(); - nr= args[0]->val_real(); - if (!args[0]->null_value) - { - if (result_field->is_null(0) || - (cmp_sign > 0 ? old_nr > nr : old_nr < nr)) - old_nr=nr; - result_field->set_notnull(); - } - else if (result_field->is_null(0)) - result_field->set_null(); - result_field->store(old_nr); - DBUG_VOID_RETURN; -} - - -void -Item_sum_hybrid::min_max_update_int_field() -{ - longlong nr,old_nr; - - DBUG_ENTER("Item_sum_hybrid::min_max_update_int_field"); - old_nr=result_field->val_int(); - nr=args[0]->val_int(); - if (!args[0]->null_value) - { - if (result_field->is_null(0)) - old_nr=nr; - else - { - bool res=(unsigned_flag ? - (ulonglong) old_nr > (ulonglong) nr : - old_nr > nr); - /* (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(); - DBUG_PRINT("info", ("nr: %lld", old_nr)); - result_field->store(old_nr, unsigned_flag); - DBUG_VOID_RETURN; -} - - -/** - @todo - optimize: do not get result_field in case of args[0] is NULL -*/ -void -Item_sum_hybrid::min_max_update_decimal_field() -{ - DBUG_ENTER("Item_sum_hybrid::min_max_update_decimal_field"); - my_decimal old_val, nr_val; - const my_decimal *old_nr; - 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 - { - old_nr= result_field->val_decimal(&old_val); - 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(); - result_field->store_decimal(old_nr); - } - else if (result_field->is_null(0)) - result_field->set_null(); - DBUG_VOID_RETURN; -} - - -double Item_avg_field_double::val_real() -{ - // fix_fields() never calls for this Item - double nr; - longlong count; - uchar *res; - - float8get(nr,field->ptr); - res= (field->ptr+sizeof(double)); - count= sint8korr(res); - - if ((null_value= !count)) - return 0.0; - return nr/(double) count; -} - - -my_decimal *Item_avg_field_decimal::val_decimal(my_decimal *dec_buf) -{ - // fix_fields() never calls for this Item - longlong count= sint8korr(field->ptr + dec_bin_size); - if ((null_value= !count)) - 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, dec_buf, - &dec_field, &dec_count, prec_increment); - return dec_buf; -} - - -double Item_std_field::val_real() -{ - double nr; - // fix_fields() never calls for this Item - nr= Item_variance_field::val_real(); - DBUG_ASSERT(nr >= 0.0); - return sqrt(nr); -} - - -double Item_variance_field::val_real() -{ - // fix_fields() never calls for this Item - double recurrence_s; - ulonglong count; - float8get(recurrence_s, (field->ptr + sizeof(double))); - count=sint8korr(field->ptr+sizeof(double)*2); - - if ((null_value= (count <= sample))) - return 0.0; - - return variance_fp_recurrence_result(recurrence_s, count, sample); -} - - -/**************************************************************************** -** Functions to handle dynamic loadable aggregates -** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su> -** Adapted for UDAs by: Andreas F. Bobak <bobak@relog.ch>. -** Rewritten by: Monty. -****************************************************************************/ - -#ifdef HAVE_DLOPEN - -void Item_udf_sum::clear() -{ - DBUG_ENTER("Item_udf_sum::clear"); - udf.clear(); - DBUG_VOID_RETURN; -} - -bool Item_udf_sum::add() -{ - my_bool tmp_null_value; - DBUG_ENTER("Item_udf_sum::add"); - udf.add(&tmp_null_value); - null_value= tmp_null_value; - DBUG_RETURN(0); -} - -void Item_udf_sum::cleanup() -{ - /* - udf_handler::cleanup() nicely handles case when we have not - original item but one created by copy_or_same() method. - */ - udf.cleanup(); - Item_sum::cleanup(); -} - - -void Item_udf_sum::print(String *str, enum_query_type query_type) -{ - str->append(func_name()); - str->append('('); - for (uint i=0 ; i < arg_count ; i++) - { - if (i) - str->append(','); - args[i]->print(str, query_type); - } - str->append(')'); -} - - -Item *Item_sum_udf_float::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_sum_udf_float(thd, this); -} - -double Item_sum_udf_float::val_real() -{ - my_bool tmp_null_value; - double res; - DBUG_ASSERT(fixed == 1); - DBUG_ENTER("Item_sum_udf_float::val"); - DBUG_PRINT("enter",("result_type: %d arg_count: %d", - args[0]->result_type(), arg_count)); - res= udf.val(&tmp_null_value); - null_value= tmp_null_value; - DBUG_RETURN(res); -} - - -String *Item_sum_udf_float::val_str(String *str) -{ - return val_string_from_real(str); -} - - -my_decimal *Item_sum_udf_float::val_decimal(my_decimal *dec) -{ - return val_decimal_from_real(dec); -} - - -String *Item_sum_udf_decimal::val_str(String *str) -{ - return val_string_from_decimal(str); -} - - -double Item_sum_udf_decimal::val_real() -{ - return val_real_from_decimal(); -} - - -longlong Item_sum_udf_decimal::val_int() -{ - return val_int_from_decimal(); -} - - -my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf) -{ - my_decimal *res; - my_bool tmp_null_value; - DBUG_ASSERT(fixed == 1); - DBUG_ENTER("Item_func_udf_decimal::val_decimal"); - DBUG_PRINT("enter",("result_type: %d arg_count: %d", - args[0]->result_type(), arg_count)); - - res= udf.val_decimal(&tmp_null_value, dec_buf); - null_value= tmp_null_value; - DBUG_RETURN(res); -} - - -Item *Item_sum_udf_decimal::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_sum_udf_decimal(thd, this); -} - - -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() -{ - my_bool tmp_null_value; - longlong res; - DBUG_ASSERT(fixed == 1); - DBUG_ENTER("Item_sum_udf_int::val_int"); - DBUG_PRINT("enter",("result_type: %d arg_count: %d", - args[0]->result_type(), arg_count)); - res= udf.val_int(&tmp_null_value); - null_value= tmp_null_value; - DBUG_RETURN(res); -} - - -String *Item_sum_udf_int::val_str(String *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() -{ - DBUG_ENTER("Item_sum_udf_str::fix_length_and_dec"); - max_length=0; - for (uint i = 0; i < arg_count; i++) - set_if_bigger(max_length,args[i]->max_length); - DBUG_VOID_RETURN; -} - - -Item *Item_sum_udf_str::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_sum_udf_str(thd, this); -} - - -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); - DBUG_ENTER("Item_sum_udf_str::str"); - String *res=udf.val_str(str,&str_value); - null_value = !res; - DBUG_RETURN(res); -} - -#endif /* HAVE_DLOPEN */ - - -/***************************************************************************** - GROUP_CONCAT function - - SQL SYNTAX: - GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...] - [SEPARATOR str_const]) - - concat of values from "group by" operation - - BUGS - Blobs doesn't work with DISTINCT or ORDER BY -*****************************************************************************/ - - - -/** - Compares the values for fields in expr list of GROUP_CONCAT. - @note - - GROUP_CONCAT([DISTINCT] expr [,expr ...] - [ORDER BY {unsigned_integer | col_name | expr} - [ASC | DESC] [,col_name ...]] - [SEPARATOR str_val]) - - @return - @retval -1 : key1 < key2 - @retval 0 : key1 = key2 - @retval 1 : key1 > key2 -*/ - -extern "C" -int group_concat_key_cmp_with_distinct(void* arg, const void* key1, - const void* key2) -{ - Item_func_group_concat *item_func= (Item_func_group_concat*)arg; - - for (uint i= 0; i < item_func->arg_count_field; i++) - { - Item *item= item_func->args[i]; - /* - If item is a const item then either get_tmp_table_field returns 0 - or it is an item over a const table. - */ - if (item->const_item()) - continue; - /* - We have to use get_tmp_table_field() instead of - real_item()->get_tmp_table_field() because we want the field in - the temporary table, not the original field - */ - Field *field= item->get_tmp_table_field(); - - if (!field) - continue; - - uint offset= (field->offset(field->table->record[0]) - - field->table->s->null_bytes); - int res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset); - if (res) - return res; - } - return 0; -} - - -/** - function of sort for syntax: GROUP_CONCAT(expr,... ORDER BY col,... ) -*/ - -extern "C" -int group_concat_key_cmp_with_order(void* arg, const void* key1, - const void* key2) -{ - Item_func_group_concat* grp_item= (Item_func_group_concat*) arg; - ORDER **order_item, **end; - - for (order_item= grp_item->order, end=order_item+ grp_item->arg_count_order; - order_item < end; - order_item++) - { - Item *item= *(*order_item)->item; - /* - If field_item is a const item then either get_tmp_table_field returns 0 - or it is an item over a const table. - */ - if (item->const_item()) - continue; - /* - If item is a const item then either get_tmp_table_field returns 0 - or it is an item over a const table. - */ - if (item->const_item()) - continue; - /* - We have to use get_tmp_table_field() instead of - real_item()->get_tmp_table_field() because we want the field in - the temporary table, not the original field - - Note that for the case of ROLLUP, field may point to another table - tham grp_item->table. This is however ok as the table definitions are - the same. - */ - Field *field= item->get_tmp_table_field(); - if (!field) - continue; - - uint offset= (field->offset(field->table->record[0]) - - field->table->s->null_bytes); - int res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset); - if (res) - return ((*order_item)->direction == ORDER::ORDER_ASC) ? res : -res; - } - /* - We can't return 0 because in that case the tree class would remove this - item as double value. This would cause problems for case-changes and - if the returned values are not the same we do the sort on. - */ - return 1; -} - - -/** - Append data from current leaf to item->result. -*/ - -extern "C" -int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), - void* item_arg) -{ - Item_func_group_concat *item= (Item_func_group_concat *) item_arg; - TABLE *table= item->table; - uint max_length= (uint)table->in_use->variables.group_concat_max_len; - String tmp((char *)table->record[1], table->s->reclength, - default_charset_info); - String tmp2; - uchar *key= (uchar *) key_arg; - String *result= &item->result; - Item **arg= item->args, **arg_end= item->args + item->arg_count_field; - uint old_length= result->length(); - - if (item->no_appended) - item->no_appended= FALSE; - else - result->append(*item->separator); - - tmp.length(0); - - for (; arg < arg_end; arg++) - { - String *res; - /* - We have to use get_tmp_table_field() instead of - real_item()->get_tmp_table_field() because we want the field in - the temporary table, not the original field - We also can't use table->field array to access the fields - because it contains both order and arg list fields. - */ - if ((*arg)->const_item()) - res= (*arg)->val_str(&tmp); - else - { - Field *field= (*arg)->get_tmp_table_field(); - if (field) - { - uint offset= (field->offset(field->table->record[0]) - - table->s->null_bytes); - DBUG_ASSERT(offset < table->s->reclength); - res= field->val_str(&tmp, key + offset); - } - else - res= (*arg)->val_str(&tmp); - } - if (res) - result->append(*res); - } - - item->row_count++; - - /* stop if length of result more than max_length */ - if (result->length() > max_length) - { - CHARSET_INFO *cs= item->collation.collation; - const char *ptr= result->ptr(); - THD *thd= current_thd; - /* - It's ok to use item->result.length() as the fourth argument - as this is never used to limit the length of the data. - Cut is done with the third argument. - */ - uint add_length= Well_formed_prefix(cs, - ptr + old_length, - ptr + max_length, - result->length()).length(); - result->length(old_length + add_length); - item->warning_for_row= TRUE; - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_CUT_VALUE_GROUP_CONCAT, - ER_THD(thd, ER_CUT_VALUE_GROUP_CONCAT), - item->row_count); - - /** - To avoid duplicated warnings in Item_func_group_concat::val_str() - */ - if (table && table->blob_storage) - table->blob_storage->set_truncated_value(false); - return 1; - } - return 0; -} - - -/** - Constructor of Item_func_group_concat. - - @param distinct_arg distinct - @param select_list list of expression for show values - @param order_list list of sort columns - @param separator_arg string value of separator. -*/ - -Item_func_group_concat:: -Item_func_group_concat(THD *thd, Name_resolution_context *context_arg, - bool distinct_arg, List<Item> *select_list, - const SQL_I_List<ORDER> &order_list, - String *separator_arg) - :Item_sum(thd), tmp_table_param(0), separator(separator_arg), tree(0), - unique_filter(NULL), table(0), - order(0), context(context_arg), - arg_count_order(order_list.elements), - arg_count_field(select_list->elements), - row_count(0), - distinct(distinct_arg), - warning_for_row(FALSE), - force_copy_fields(0), original(0) -{ - Item *item_select; - Item **arg_ptr; - - quick_group= FALSE; - arg_count= arg_count_field + arg_count_order; - - /* - We need to allocate: - args - arg_count_field+arg_count_order - (for possible order items in temporary tables) - order - arg_count_order - */ - if (!(args= (Item**) thd->alloc(sizeof(Item*) * arg_count * 2 + - sizeof(ORDER*)*arg_count_order))) - return; - - order= (ORDER**)(args + arg_count); - - /* fill args items of show and sort */ - List_iterator_fast<Item> li(*select_list); - - for (arg_ptr=args ; (item_select= li++) ; arg_ptr++) - *arg_ptr= item_select; - - if (arg_count_order) - { - ORDER **order_ptr= order; - for (ORDER *order_item= order_list.first; - order_item != NULL; - order_item= order_item->next) - { - (*order_ptr++)= order_item; - *arg_ptr= *order_item->item; - order_item->item= arg_ptr++; - } - } - - /* orig_args is only used for print() */ - orig_args= (Item**) (order + arg_count_order); - memcpy(orig_args, args, sizeof(Item*) * arg_count); -} - - -Item_func_group_concat::Item_func_group_concat(THD *thd, - Item_func_group_concat *item) - :Item_sum(thd, item), - tmp_table_param(item->tmp_table_param), - separator(item->separator), - tree(item->tree), - unique_filter(item->unique_filter), - table(item->table), - context(item->context), - arg_count_order(item->arg_count_order), - arg_count_field(item->arg_count_field), - row_count(item->row_count), - distinct(item->distinct), - warning_for_row(item->warning_for_row), - always_null(item->always_null), - force_copy_fields(item->force_copy_fields), - original(item) -{ - quick_group= item->quick_group; - result.set_charset(collation.collation); - - /* - Since the ORDER structures pointed to by the elements of the 'order' array - may be modified in find_order_in_list() called from - Item_func_group_concat::setup(), create a copy of those structures so that - such modifications done in this object would not have any effect on the - object being copied. - */ - ORDER *tmp; - if (!(tmp= (ORDER *) thd->alloc(sizeof(ORDER *) * arg_count_order + - sizeof(ORDER) * arg_count_order))) - return; - order= (ORDER **)(tmp + arg_count_order); - for (uint i= 0; i < arg_count_order; i++, tmp++) - { - /* - Compiler generated copy constructor is used to - to copy all the members of ORDER struct. - It's also necessary to update ORDER::next pointer - so that it points to new ORDER element. - */ - new (tmp) st_order(*(item->order[i])); - tmp->next= (i + 1 == arg_count_order) ? NULL : (tmp + 1); - order[i]= tmp; - } -} - - -void Item_func_group_concat::cleanup() -{ - DBUG_ENTER("Item_func_group_concat::cleanup"); - Item_sum::cleanup(); - - /* - Free table and tree if they belong to this item (if item have not pointer - to original item from which was made copy => it own its objects ) - */ - if (!original) - { - delete tmp_table_param; - tmp_table_param= 0; - if (table) - { - THD *thd= table->in_use; - if (table->blob_storage) - delete table->blob_storage; - free_tmp_table(thd, table); - table= 0; - if (tree) - { - delete_tree(tree, 0); - tree= 0; - } - if (unique_filter) - { - delete unique_filter; - unique_filter= NULL; - } - } - DBUG_ASSERT(tree == 0); - } - /* - As the ORDER structures pointed to by the elements of the - 'order' array may be modified in find_order_in_list() called - from Item_func_group_concat::setup() to point to runtime - created objects, we need to reset them back to the original - arguments of the function. - */ - ORDER **order_ptr= order; - for (uint i= 0; i < arg_count_order; i++) - { - (*order_ptr)->item= &args[arg_count_field + i]; - order_ptr++; - } - DBUG_VOID_RETURN; -} - - -Item *Item_func_group_concat::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_func_group_concat(thd, this); -} - - -void Item_func_group_concat::clear() -{ - result.length(0); - result.copy(); - null_value= TRUE; - warning_for_row= FALSE; - no_appended= TRUE; - if (tree) - reset_tree(tree); - if (unique_filter) - unique_filter->reset(); - if (table && table->blob_storage) - table->blob_storage->reset(); - /* No need to reset the table as we never call write_row */ -} - - -bool Item_func_group_concat::add() -{ - if (always_null) - return 0; - copy_fields(tmp_table_param); - if (copy_funcs(tmp_table_param->items_to_copy, table->in_use)) - return TRUE; - - for (uint i= 0; i < arg_count_field; i++) - { - Item *show_item= args[i]; - if (show_item->const_item()) - continue; - - Field *field= show_item->get_tmp_table_field(); - if (field && field->is_null_in_record((const uchar*) table->record[0])) - return 0; // Skip row if it contains null - } - - null_value= FALSE; - bool row_eligible= TRUE; - - if (distinct) - { - /* Filter out duplicate rows. */ - uint count= unique_filter->elements_in_tree(); - unique_filter->unique_add(table->record[0] + table->s->null_bytes); - if (count == unique_filter->elements_in_tree()) - row_eligible= FALSE; - } - - TREE_ELEMENT *el= 0; // Only for safety - if (row_eligible && tree) - { - el= tree_insert(tree, table->record[0] + table->s->null_bytes, 0, - tree->custom_arg); - /* check if there was enough memory to insert the row */ - if (!el) - return 1; - } - /* - If the row is not a duplicate (el->count == 1) - we can dump the row here in case of GROUP_CONCAT(DISTINCT...) - instead of doing tree traverse later. - */ - if (row_eligible && !warning_for_row && - (!tree || (el->count == 1 && distinct && !arg_count_order))) - dump_leaf_key(table->record[0] + table->s->null_bytes, 1, this); - - return 0; -} - - -bool -Item_func_group_concat::fix_fields(THD *thd, Item **ref) -{ - uint i; /* for loop variable */ - DBUG_ASSERT(fixed == 0); - - if (init_sum_func_check(thd)) - return TRUE; - - maybe_null= 1; - - /* - Fix fields for select list and ORDER clause - */ - - for (i=0 ; i < arg_count ; i++) - { - if ((!args[i]->fixed && - args[i]->fix_fields(thd, args + i)) || - args[i]->check_cols(1)) - return TRUE; - m_with_subquery|= args[i]->with_subquery(); - with_window_func|= args[i]->with_window_func; - } - - /* skip charset aggregation for order columns */ - if (agg_arg_charsets_for_string_result(collation, - args, arg_count - arg_count_order)) - return 1; - - result.set_charset(collation.collation); - result_field= 0; - null_value= 1; - max_length= (uint32)(thd->variables.group_concat_max_len - / collation.collation->mbminlen - * collation.collation->mbmaxlen); - - uint32 offset; - if (separator->needs_conversion(separator->length(), separator->charset(), - collation.collation, &offset)) - { - uint32 buflen= collation.collation->mbmaxlen * separator->length(); - uint errors, conv_length; - char *buf; - String *new_separator; - - if (!(buf= (char*) thd->stmt_arena->alloc(buflen)) || - !(new_separator= new(thd->stmt_arena->mem_root) - String(buf, buflen, collation.collation))) - return TRUE; - - conv_length= copy_and_convert(buf, buflen, collation.collation, - separator->ptr(), separator->length(), - separator->charset(), &errors); - new_separator->length(conv_length); - separator= new_separator; - } - - if (check_sum_func(thd, ref)) - return TRUE; - - fixed= 1; - return FALSE; -} - - -bool Item_func_group_concat::setup(THD *thd) -{ - List<Item> list; - SELECT_LEX *select_lex= thd->lex->current_select; - const bool order_or_distinct= MY_TEST(arg_count_order > 0 || distinct); - DBUG_ENTER("Item_func_group_concat::setup"); - - /* - Currently setup() can be called twice. Please add - assertion here when this is fixed. - */ - if (table || tree) - DBUG_RETURN(FALSE); - - if (!(tmp_table_param= new TMP_TABLE_PARAM)) - DBUG_RETURN(TRUE); - - /* Push all not constant fields to the list and create a temp table */ - always_null= 0; - for (uint i= 0; i < arg_count_field; i++) - { - Item *item= args[i]; - if (list.push_back(item, thd->mem_root)) - DBUG_RETURN(TRUE); - if (item->const_item()) - { - if (item->is_null()) - { - always_null= 1; - DBUG_RETURN(FALSE); - } - } - } - - List<Item> all_fields(list); - /* - Try to find every ORDER expression in the list of GROUP_CONCAT - arguments. If an expression is not found, prepend it to - "all_fields". The resulting field list is used as input to create - tmp table columns. - */ - if (arg_count_order) - { - uint n_elems= arg_count_order + all_fields.elements; - ref_pointer_array= static_cast<Item**>(thd->alloc(sizeof(Item*) * n_elems)); - if (!ref_pointer_array) - DBUG_RETURN(TRUE); - memcpy(ref_pointer_array, args, arg_count * sizeof(Item*)); - if (setup_order(thd, Ref_ptr_array(ref_pointer_array, n_elems), - context->table_list, list, all_fields, *order)) - DBUG_RETURN(TRUE); - } - - count_field_types(select_lex, tmp_table_param, all_fields, 0); - tmp_table_param->force_copy_fields= force_copy_fields; - DBUG_ASSERT(table == 0); - if (order_or_distinct) - { - /* - Force the create_tmp_table() to convert BIT columns to INT - as we cannot compare two table records containg BIT fields - stored in the the tree used for distinct/order by. - Moreover we don't even save in the tree record null bits - where BIT fields store parts of their data. - */ - List_iterator_fast<Item> li(all_fields); - Item *item; - while ((item= li++)) - { - if (item->type() == Item::FIELD_ITEM && - ((Item_field*) item)->field->type() == FIELD_TYPE_BIT) - item->marker= 4; - } - } - - /* - We have to create a temporary table to get descriptions of fields - (types, sizes and so on). - - Note that in the table, we first have the ORDER BY fields, then the - field list. - */ - if (!(table= create_tmp_table(thd, tmp_table_param, all_fields, - (ORDER*) 0, 0, TRUE, - (select_lex->options | - thd->variables.option_bits), - HA_POS_ERROR, (char*) ""))) - DBUG_RETURN(TRUE); - table->file->extra(HA_EXTRA_NO_ROWS); - table->no_rows= 1; - - /** - Initialize blob_storage if GROUP_CONCAT is used - with ORDER BY | DISTINCT and BLOB field count > 0. - */ - if (order_or_distinct && table->s->blob_fields) - table->blob_storage= new Blob_mem_storage(); - - /* - Need sorting or uniqueness: init tree and choose a function to sort. - Don't reserve space for NULLs: if any of gconcat arguments is NULL, - the row is not added to the result. - */ - uint tree_key_length= table->s->reclength - table->s->null_bytes; - - if (arg_count_order) - { - tree= &tree_base; - /* - Create a tree for sorting. The tree is used to sort (according to the - syntax of this function). If there is no ORDER BY clause, we don't - create this tree. - */ - init_tree(tree, (size_t)MY_MIN(thd->variables.max_heap_table_size, - thd->variables.sortbuff_size/16), 0, - tree_key_length, - group_concat_key_cmp_with_order, NULL, (void*) this, - MYF(MY_THREAD_SPECIFIC)); - } - - if (distinct) - unique_filter= new Unique(group_concat_key_cmp_with_distinct, - (void*)this, - tree_key_length, - ram_limitation(thd)); - - DBUG_RETURN(FALSE); -} - - -/* This is used by rollup to create a separate usable copy of the function */ - -void Item_func_group_concat::make_unique() -{ - tmp_table_param= 0; - table=0; - original= 0; - force_copy_fields= 1; - tree= 0; -} - - -String* Item_func_group_concat::val_str(String* str) -{ - DBUG_ASSERT(fixed == 1); - if (null_value) - return 0; - if (no_appended && tree) - /* Tree is used for sorting as in ORDER BY */ - tree_walk(tree, &dump_leaf_key, this, left_root_right); - - if (table && table->blob_storage && - table->blob_storage->is_truncated_value()) - { - warning_for_row= true; - push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, - ER_CUT_VALUE_GROUP_CONCAT, ER(ER_CUT_VALUE_GROUP_CONCAT), - row_count); - } - - return &result; -} - - -void Item_func_group_concat::print(String *str, enum_query_type query_type) -{ - str->append(STRING_WITH_LEN("group_concat(")); - if (distinct) - str->append(STRING_WITH_LEN("distinct ")); - for (uint i= 0; i < arg_count_field; i++) - { - if (i) - str->append(','); - orig_args[i]->print(str, query_type); - } - if (arg_count_order) - { - str->append(STRING_WITH_LEN(" order by ")); - for (uint i= 0 ; i < arg_count_order ; i++) - { - if (i) - str->append(','); - orig_args[i + arg_count_field]->print(str, query_type); - if (order[i]->direction == ORDER::ORDER_ASC) - str->append(STRING_WITH_LEN(" ASC")); - else - str->append(STRING_WITH_LEN(" DESC")); - } - } - str->append(STRING_WITH_LEN(" separator \'")); - str->append(*separator); - str->append(STRING_WITH_LEN("\')")); -} - - -Item_func_group_concat::~Item_func_group_concat() -{ - if (!original && unique_filter) - delete unique_filter; -} diff --git a/sql/item_sum.h.orig b/sql/item_sum.h.orig deleted file mode 100644 index fd6b20e2b81..00000000000 --- a/sql/item_sum.h.orig +++ /dev/null @@ -1,1821 +0,0 @@ -#ifndef ITEM_SUM_INCLUDED -#define ITEM_SUM_INCLUDED -/* Copyright (c) 2000, 2013 Oracle and/or its affiliates. - Copyright (c) 2008, 2013 Monty Program Ab. - - 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 - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - - -/* classes for sum functions */ - -#ifdef USE_PRAGMA_INTERFACE -#pragma interface /* gcc class implementation */ -#endif - -#include <my_tree.h> -#include "sql_udf.h" /* udf_handler */ - -class Item_sum; -class Aggregator_distinct; -class Aggregator_simple; - -/** - The abstract base class for the Aggregator_* classes. - It implements the data collection functions (setup/add/clear) - as either pass-through to the real functionality or - as collectors into an Unique (for distinct) structure. - - Note that update_field/reset_field are not in that - class, because they're simply not called when - GROUP BY/DISTINCT can be handled with help of index on grouped - fields (quick_group = 0); -*/ - -class Aggregator : public Sql_alloc -{ - friend class Item_sum; - friend class Item_sum_sum; - friend class Item_sum_count; - friend class Item_sum_avg; - - /* - All members are protected as this class is not usable outside of an - Item_sum descendant. - */ -protected: - /* the aggregate function class to act on */ - Item_sum *item_sum; - -public: - Aggregator (Item_sum *arg): item_sum(arg) {} - virtual ~Aggregator () {} /* Keep gcc happy */ - - enum Aggregator_type { SIMPLE_AGGREGATOR, DISTINCT_AGGREGATOR }; - virtual Aggregator_type Aggrtype() = 0; - - /** - Called before adding the first row. - Allocates and sets up the internal aggregation structures used, - e.g. the Unique instance used to calculate distinct. - */ - virtual bool setup(THD *) = 0; - - /** - Called when we need to wipe out all the data from the aggregator : - all the values acumulated and all the state. - Cleans up the internal structures and resets them to their initial state. - */ - virtual void clear() = 0; - - /** - Called when there's a new value to be aggregated. - Updates the internal state of the aggregator to reflect the new value. - */ - virtual bool add() = 0; - - /** - Called when there are no more data and the final value is to be retrieved. - Finalises the state of the aggregator, so the final result can be retrieved. - */ - virtual void endup() = 0; - - /** Decimal value of being-aggregated argument */ - virtual my_decimal *arg_val_decimal(my_decimal * value) = 0; - /** Floating point value of being-aggregated argument */ - virtual double arg_val_real() = 0; - /** - NULLness of being-aggregated argument. - - @param use_null_value Optimization: to determine if the argument is NULL - we must, in the general case, call is_null() on it, which itself might - call val_*() on it, which might be costly. If you just have called - arg_val*(), you can pass use_null_value=true; this way, arg_is_null() - might avoid is_null() and instead do a cheap read of the Item's null_value - (updated by arg_val*()). - */ - virtual bool arg_is_null(bool use_null_value) = 0; -}; - - -class st_select_lex; -class Window_spec; - -/** - Class Item_sum is the base class used for special expressions that SQL calls - 'set functions'. These expressions are formed with the help of aggregate - functions such as SUM, MAX, GROUP_CONCAT etc. - - GENERAL NOTES - - A set function cannot be used in certain positions where expressions are - accepted. There are some quite explicable restrictions for the usage of - set functions. - - In the query: - SELECT AVG(b) FROM t1 WHERE SUM(b) > 20 GROUP by a - the usage of the set function AVG(b) is legal, while the usage of SUM(b) - is illegal. A WHERE condition must contain expressions that can be - evaluated for each row of the table. Yet the expression SUM(b) can be - evaluated only for each group of rows with the same value of column a. - In the query: - SELECT AVG(b) FROM t1 WHERE c > 30 GROUP BY a HAVING SUM(b) > 20 - both set function expressions AVG(b) and SUM(b) are legal. - - We can say that in a query without nested selects an occurrence of a - set function in an expression of the SELECT list or/and in the HAVING - clause is legal, while in the WHERE clause it's illegal. - - The general rule to detect whether a set function is legal in a query with - nested subqueries is much more complicated. - - Consider the the following query: - SELECT t1.a FROM t1 GROUP BY t1.a - HAVING t1.a > ALL (SELECT t2.c FROM t2 WHERE SUM(t1.b) < t2.c). - The set function SUM(b) is used here in the WHERE clause of the subquery. - Nevertheless it is legal since it is under the HAVING clause of the query - to which this function relates. The expression SUM(t1.b) is evaluated - for each group defined in the main query, not for groups of the subquery. - - The problem of finding the query where to aggregate a particular - set function is not so simple as it seems to be. - - In the query: - SELECT t1.a FROM t1 GROUP BY t1.a - HAVING t1.a > ALL(SELECT t2.c FROM t2 GROUP BY t2.c - HAVING SUM(t1.a) < t2.c) - the set function can be evaluated for both outer and inner selects. - If we evaluate SUM(t1.a) for the outer query then we get the value of t1.a - multiplied by the cardinality of a group in table t1. In this case - in each correlated subquery SUM(t1.a) is used as a constant. But we also - can evaluate SUM(t1.a) for the inner query. In this case t1.a will be a - constant for each correlated subquery and summation is performed - for each group of table t2. - (Here it makes sense to remind that the query - SELECT c FROM t GROUP BY a HAVING SUM(1) < a - is quite legal in our SQL). - - So depending on what query we assign the set function to we - can get different result sets. - - The general rule to detect the query where a set function is to be - evaluated can be formulated as follows. - Consider a set function S(E) where E is an expression with occurrences - of column references C1, ..., CN. Resolve these column references against - subqueries that contain the set function S(E). Let Q be the innermost - subquery of those subqueries. (It should be noted here that S(E) - in no way can be evaluated in the subquery embedding the subquery Q, - otherwise S(E) would refer to at least one unbound column reference) - If S(E) is used in a construct of Q where set functions are allowed then - we evaluate S(E) in Q. - Otherwise we look for a innermost subquery containing S(E) of those where - usage of S(E) is allowed. - - Let's demonstrate how this rule is applied to the following queries. - - 1. SELECT t1.a FROM t1 GROUP BY t1.a - HAVING t1.a > ALL(SELECT t2.b FROM t2 GROUP BY t2.b - HAVING t2.b > ALL(SELECT t3.c FROM t3 GROUP BY t3.c - HAVING SUM(t1.a+t2.b) < t3.c)) - For this query the set function SUM(t1.a+t2.b) depends on t1.a and t2.b - with t1.a defined in the outermost query, and t2.b defined for its - subquery. The set function is in the HAVING clause of the subquery and can - be evaluated in this subquery. - - 2. SELECT t1.a FROM t1 GROUP BY t1.a - HAVING t1.a > ALL(SELECT t2.b FROM t2 - WHERE t2.b > ALL (SELECT t3.c FROM t3 GROUP BY t3.c - HAVING SUM(t1.a+t2.b) < t3.c)) - Here the set function SUM(t1.a+t2.b)is in the WHERE clause of the second - subquery - the most upper subquery where t1.a and t2.b are defined. - If we evaluate the function in this subquery we violate the context rules. - So we evaluate the function in the third subquery (over table t3) where it - is used under the HAVING clause. - - 3. SELECT t1.a FROM t1 GROUP BY t1.a - HAVING t1.a > ALL(SELECT t2.b FROM t2 - WHERE t2.b > ALL (SELECT t3.c FROM t3 - WHERE SUM(t1.a+t2.b) < t3.c)) - In this query evaluation of SUM(t1.a+t2.b) is not legal neither in the second - nor in the third subqueries. So this query is invalid. - - Mostly set functions cannot be nested. In the query - SELECT t1.a from t1 GROUP BY t1.a HAVING AVG(SUM(t1.b)) > 20 - the expression SUM(b) is not acceptable, though it is under a HAVING clause. - Yet it is acceptable in the query: - SELECT t.1 FROM t1 GROUP BY t1.a HAVING SUM(t1.b) > 20. - - An argument of a set function does not have to be a reference to a table - column as we saw it in examples above. This can be a more complex expression - SELECT t1.a FROM t1 GROUP BY t1.a HAVING SUM(t1.b+1) > 20. - The expression SUM(t1.b+1) has a very clear semantics in this context: - we sum up the values of t1.b+1 where t1.b varies for all values within a - group of rows that contain the same t1.a value. - - A set function for an outer query yields a constant within a subquery. So - the semantics of the query - SELECT t1.a FROM t1 GROUP BY t1.a - HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c - HAVING AVG(t2.c+SUM(t1.b)) > 20) - is still clear. For a group of the rows with the same t1.a values we - calculate the value of SUM(t1.b). This value 's' is substituted in the - the subquery: - SELECT t2.c FROM t2 GROUP BY t2.c HAVING AVG(t2.c+s) - than returns some result set. - - By the same reason the following query with a subquery - SELECT t1.a FROM t1 GROUP BY t1.a - HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c - HAVING AVG(SUM(t1.b)) > 20) - is also acceptable. - - IMPLEMENTATION NOTES - - Three methods were added to the class to check the constraints specified - in the previous section. These methods utilize several new members. - - The field 'nest_level' contains the number of the level for the subquery - containing the set function. The main SELECT is of level 0, its subqueries - are of levels 1, the subqueries of the latter are of level 2 and so on. - - The field 'aggr_level' is to contain the nest level of the subquery - where the set function is aggregated. - - The field 'max_arg_level' is for the maximun of the nest levels of the - unbound column references occurred in the set function. A column reference - is unbound within a set function if it is not bound by any subquery - used as a subexpression in this function. A column reference is bound by - a subquery if it is a reference to the column by which the aggregation - of some set function that is used in the subquery is calculated. - For the set function used in the query - SELECT t1.a FROM t1 GROUP BY t1.a - HAVING t1.a > ALL(SELECT t2.b FROM t2 GROUP BY t2.b - HAVING t2.b > ALL(SELECT t3.c FROM t3 GROUP BY t3.c - HAVING SUM(t1.a+t2.b) < t3.c)) - the value of max_arg_level is equal to 1 since t1.a is bound in the main - query, and t2.b is bound by the first subquery whose nest level is 1. - Obviously a set function cannot be aggregated in the subquery whose - nest level is less than max_arg_level. (Yet it can be aggregated in the - subqueries whose nest level is greater than max_arg_level.) - In the query - SELECT t.a FROM t1 HAVING AVG(t1.a+(SELECT MIN(t2.c) FROM t2)) - the value of the max_arg_level for the AVG set function is 0 since - the reference t2.c is bound in the subquery. - - The field 'max_sum_func_level' is to contain the maximum of the - nest levels of the set functions that are used as subexpressions of - the arguments of the given set function, but not aggregated in any - subquery within this set function. A nested set function s1 can be - used within set function s0 only if s1.max_sum_func_level < - s0.max_sum_func_level. Set function s1 is considered as nested - for set function s0 if s1 is not calculated in any subquery - within s0. - - A set function that is used as a subexpression in an argument of another - set function refers to the latter via the field 'in_sum_func'. - - The condition imposed on the usage of set functions are checked when - we traverse query subexpressions with the help of the recursive method - fix_fields. When we apply this method to an object of the class - Item_sum, first, on the descent, we call the method init_sum_func_check - that initialize members used at checking. Then, on the ascent, we - call the method check_sum_func that validates the set function usage - and reports an error if it is illegal. - The method register_sum_func serves to link the items for the set functions - that are aggregated in the embedding (sub)queries. Circular chains of such - functions are attached to the corresponding st_select_lex structures - through the field inner_sum_func_list. - - Exploiting the fact that the members mentioned above are used in one - recursive function we could have allocated them on the thread stack. - Yet we don't do it now. - - We assume that the nesting level of subquries does not exceed 127. - TODO: to catch queries where the limit is exceeded to make the - code clean here. - - @note - The implementation takes into account the used strategy: - - Items resolved at optimization phase return 0 from Item_sum::used_tables(). - - Items that depend on the number of join output records, but not columns of - any particular table (like COUNT(*)), returm 0 from Item_sum::used_tables(), - but still return false from Item_sum::const_item(). -*/ - -class Item_sum :public Item_func_or_sum -{ - friend class Aggregator_distinct; - friend class Aggregator_simple; - -protected: - /** - Aggregator class instance. Not set initially. Allocated only after - it is determined if the incoming data are already distinct. - */ - Aggregator *aggr; - -private: - /** - Used in making ROLLUP. Set for the ROLLUP copies of the original - Item_sum and passed to create_tmp_field() to cause it to work - over the temp table buffer that is referenced by - Item_result_field::result_field. - */ - bool force_copy_fields; - - /** - Indicates how the aggregate function was specified by the parser : - 1 if it was written as AGGREGATE(DISTINCT), - 0 if it was AGGREGATE() - */ - bool with_distinct; - - /* TRUE if this is aggregate function of a window function */ - bool window_func_sum_expr_flag; - -public: - - bool has_force_copy_fields() const { return force_copy_fields; } - bool has_with_distinct() const { return with_distinct; } - - enum Sumfunctype - { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC, - AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC, - VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC, - ROW_NUMBER_FUNC, RANK_FUNC, DENSE_RANK_FUNC, PERCENT_RANK_FUNC, - CUME_DIST_FUNC, NTILE_FUNC, FIRST_VALUE_FUNC, LAST_VALUE_FUNC, - NTH_VALUE_FUNC, LEAD_FUNC, LAG_FUNC, PERCENTILE_CONT_FUNC, - PERCENTILE_DISC_FUNC, SP_AGGREGATE_FUNC - }; - - Item **ref_by; /* pointer to a ref to the object used to register it */ - Item_sum *next; /* next in the circular chain of registered objects */ - Item_sum *in_sum_func; /* embedding set function if any */ - st_select_lex * aggr_sel; /* select where the function is aggregated */ - int8 nest_level; /* number of the nesting level of the set function */ - int8 aggr_level; /* nesting level of the aggregating subquery */ - int8 max_arg_level; /* max level of unbound column references */ - int8 max_sum_func_level;/* max level of aggregation for embedded functions */ - bool quick_group; /* If incremental update of fields */ - /* - This list is used by the check for mixing non aggregated fields and - sum functions in the ONLY_FULL_GROUP_BY_MODE. We save all outer fields - directly or indirectly used under this function it as it's unclear - at the moment of fixing outer field whether it's aggregated or not. - */ - List<Item_field> outer_fields; - -protected: - /* - Copy of the arguments list to hold the original set of arguments. - Used in EXPLAIN EXTENDED instead of the current argument list because - the current argument list can be altered by usage of temporary tables. - */ - Item **orig_args, *tmp_orig_args[2]; - - static size_t ram_limitation(THD *thd); - -public: - - void mark_as_sum_func(); - Item_sum(THD *thd): Item_func_or_sum(thd), quick_group(1) - { - mark_as_sum_func(); - init_aggregator(); - } - Item_sum(THD *thd, Item *a): Item_func_or_sum(thd, a), quick_group(1), - orig_args(tmp_orig_args) - { - mark_as_sum_func(); - init_aggregator(); - } - Item_sum(THD *thd, Item *a, Item *b): Item_func_or_sum(thd, a, b), - quick_group(1), orig_args(tmp_orig_args) - { - mark_as_sum_func(); - init_aggregator(); - } - Item_sum(THD *thd, List<Item> &list); - //Copy constructor, need to perform subselects with temporary tables - Item_sum(THD *thd, Item_sum *item); - enum Type type() const { return SUM_FUNC_ITEM; } - virtual enum Sumfunctype sum_func () const=0; - bool is_aggr_sum_func() - { - switch (sum_func()) { - case COUNT_FUNC: - case COUNT_DISTINCT_FUNC: - case SUM_FUNC: - case SUM_DISTINCT_FUNC: - case AVG_FUNC: - case AVG_DISTINCT_FUNC: - case MIN_FUNC: - case MAX_FUNC: - case STD_FUNC: - case VARIANCE_FUNC: - case SUM_BIT_FUNC: - case UDF_SUM_FUNC: - case GROUP_CONCAT_FUNC: - return true; - default: - return false; - } - } - /** - Resets the aggregate value to its default and aggregates the current - value of its attribute(s). - */ - inline bool reset_and_add() - { - aggregator_clear(); - return aggregator_add(); - }; - - /* - Called when new group is started and results are being saved in - a temporary table. Similarly to reset_and_add() it resets the - value to its default and aggregates the value of its - attribute(s), but must also store it in result_field. - This set of methods (result_item(), reset_field, update_field()) of - Item_sum is used only if quick_group is not null. Otherwise - copy_or_same() is used to obtain a copy of this item. - */ - virtual void reset_field()=0; - /* - Called for each new value in the group, when temporary table is in use. - Similar to add(), but uses temporary table field to obtain current value, - Updated value is then saved in the field. - */ - virtual void update_field()=0; - virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } - virtual Item *result_item(THD *thd, Field *field); - - void update_used_tables (); - COND *build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields, - COND_EQUAL **cond_equal_ref) - { - /* - Item_sum (and derivants) of the original WHERE/HAVING clauses - should already be replaced to Item_aggregate_ref by the time when - build_equal_items() is called. See Item::split_sum_func2(). - */ - DBUG_ASSERT(0); - return Item::build_equal_items(thd, inherited, link_item_fields, - cond_equal_ref); - } - bool is_null() { return null_value; } - /** - make_const() - Called if we've managed to calculate the value of this Item in - opt_sum_query(), hence it can be considered constant at all subsequent - steps. - */ - void make_const () - { - used_tables_cache= 0; - const_item_cache= true; - } - void reset_forced_const() { const_item_cache= false; } - virtual bool const_during_execution() const { return false; } - virtual void print(String *str, enum_query_type query_type); - void fix_num_length_and_dec(); - - /** - Mark an aggregate as having no rows. - - This function is called by the execution engine to assign 'NO ROWS - FOUND' value to an aggregate item, when the underlying result set - has no rows. Such value, in a general case, may be different from - the default value of the item after 'clear()': e.g. a numeric item - may be initialized to 0 by clear() and to NULL by - no_rows_in_result(). - */ - virtual void no_rows_in_result() - { - set_aggregator(with_distinct ? - Aggregator::DISTINCT_AGGREGATOR : - Aggregator::SIMPLE_AGGREGATOR); - aggregator_clear(); - } - virtual void make_unique() { force_copy_fields= TRUE; } - Item *get_tmp_table_item(THD *thd); - Field *create_tmp_field(bool group, TABLE *table); - virtual bool collect_outer_ref_processor(void *param); - bool init_sum_func_check(THD *thd); - bool check_sum_func(THD *thd, Item **ref); - bool register_sum_func(THD *thd, Item **ref); - st_select_lex *depended_from() - { return (nest_level == aggr_level ? 0 : aggr_sel); } - - Item *get_arg(uint i) const { return args[i]; } - Item *set_arg(uint i, THD *thd, Item *new_val); - uint get_arg_count() const { return arg_count; } - virtual Item **get_args() { return fixed ? orig_args : args; } - - /* Initialization of distinct related members */ - void init_aggregator() - { - aggr= NULL; - with_distinct= FALSE; - force_copy_fields= FALSE; - } - - /** - Called to initialize the aggregator. - */ - - inline bool aggregator_setup(THD *thd) { return aggr->setup(thd); }; - - /** - Called to cleanup the aggregator. - */ - - inline void aggregator_clear() { aggr->clear(); } - - /** - Called to add value to the aggregator. - */ - - inline bool aggregator_add() { return aggr->add(); }; - - /* stores the declared DISTINCT flag (from the parser) */ - void set_distinct(bool distinct) - { - with_distinct= distinct; - quick_group= with_distinct ? 0 : 1; - } - - /* - Set the type of aggregation : DISTINCT or not. - - May be called multiple times. - */ - - int set_aggregator(Aggregator::Aggregator_type aggregator); - - virtual void clear()= 0; - virtual bool add()= 0; - virtual bool setup(THD *thd) { return false; } - - virtual bool supports_removal() const { return false; } - virtual void remove() { DBUG_ASSERT(0); } - - virtual void cleanup(); - bool check_vcol_func_processor(void *arg); - virtual void setup_window_func(THD *thd, Window_spec *window_spec) {} - void mark_as_window_func_sum_expr() { window_func_sum_expr_flag= true; } - bool is_window_func_sum_expr() { return window_func_sum_expr_flag; } - virtual void setup_caches(THD *thd) {}; -}; - - -class Unique; - - -/** - The distinct aggregator. - Implements AGGFN (DISTINCT ..) - Collects all the data into an Unique (similarly to what Item_sum - does currently when with_distinct=true) and then (if applicable) iterates over - the list of unique values and pumps them back into its object -*/ - -class Aggregator_distinct : public Aggregator -{ - friend class Item_sum_sum; - - /* - flag to prevent consecutive runs of endup(). Normally in endup there are - expensive calculations (like walking the distinct tree for example) - which we must do only once if there are no data changes. - We can re-use the data for the second and subsequent val_xxx() calls. - endup_done set to TRUE also means that the calculated values for - the aggregate functions are correct and don't need recalculation. - */ - bool endup_done; - - /* - Used depending on the type of the aggregate function and the presence of - blob columns in it: - - For COUNT(DISTINCT) and no blob fields this points to a real temporary - table. It's used as a hash table. - - For AVG/SUM(DISTINCT) or COUNT(DISTINCT) with blob fields only the - in-memory data structure of a temporary table is constructed. - It's used by the Field classes to transform data into row format. - */ - TABLE *table; - - /* - An array of field lengths on row allocated and used only for - COUNT(DISTINCT) with multiple columns and no blobs. Used in - Aggregator_distinct::composite_key_cmp (called from Unique to compare - nodes - */ - uint32 *field_lengths; - - /* - Used in conjunction with 'table' to support the access to Field classes - for COUNT(DISTINCT). Needed by copy_fields()/copy_funcs(). - */ - TMP_TABLE_PARAM *tmp_table_param; - - /* - If there are no blobs in the COUNT(DISTINCT) arguments, we can use a tree, - which is faster than heap table. In that case, we still use the table - to help get things set up, but we insert nothing in it. - For AVG/SUM(DISTINCT) we always use this tree (as it takes a single - argument) to get the distinct rows. - */ - Unique *tree; - - /* - The length of the temp table row. Must be a member of the class as it - gets passed down to simple_raw_key_cmp () as a compare function argument - to Unique. simple_raw_key_cmp () is used as a fast comparison function - when the entire row can be binary compared. - */ - uint tree_key_length; - - /* - Set to true if the result is known to be always NULL. - If set deactivates creation and usage of the temporary table (in the - 'table' member) and the Unique instance (in the 'tree' member) as well as - the calculation of the final value on the first call to - Item_[sum|avg|count]::val_xxx(). - */ - bool always_null; - - /** - When feeding back the data in endup() from Unique/temp table back to - Item_sum::add() methods we must read the data from Unique (and not - recalculate the functions that are given as arguments to the aggregate - function. - This flag is to tell the arg_*() methods to take the data from the Unique - instead of calling the relevant val_..() method. - */ - bool use_distinct_values; - -public: - Aggregator_distinct (Item_sum *sum) : - Aggregator(sum), table(NULL), tmp_table_param(NULL), tree(NULL), - always_null(false), use_distinct_values(false) {} - virtual ~Aggregator_distinct (); - Aggregator_type Aggrtype() { return DISTINCT_AGGREGATOR; } - - bool setup(THD *); - void clear(); - bool add(); - void endup(); - virtual my_decimal *arg_val_decimal(my_decimal * value); - virtual double arg_val_real(); - virtual bool arg_is_null(bool use_null_value); - - bool unique_walk_function(void *element); - bool unique_walk_function_for_count(void *element); - static int composite_key_cmp(void* arg, uchar* key1, uchar* key2); -}; - - -/** - The pass-through aggregator. - Implements AGGFN (DISTINCT ..) by knowing it gets distinct data on input. - So it just pumps them back to the Item_sum descendant class. -*/ -class Aggregator_simple : public Aggregator -{ -public: - - Aggregator_simple (Item_sum *sum) : - Aggregator(sum) {} - Aggregator_type Aggrtype() { return Aggregator::SIMPLE_AGGREGATOR; } - - bool setup(THD * thd) { return item_sum->setup(thd); } - void clear() { item_sum->clear(); } - bool add() { return item_sum->add(); } - void endup() {}; - virtual my_decimal *arg_val_decimal(my_decimal * value); - virtual double arg_val_real(); - virtual bool arg_is_null(bool use_null_value); -}; - - -class Item_sum_num :public Item_sum -{ -protected: - /* - val_xxx() functions may be called several times during the execution of a - query. Derived classes that require extensive calculation in val_xxx() - maintain cache of aggregate value. This variable governs the validity of - that cache. - */ - bool is_evaluated; -public: - Item_sum_num(THD *thd): Item_sum(thd), is_evaluated(FALSE) {} - Item_sum_num(THD *thd, Item *item_par): - Item_sum(thd, item_par), is_evaluated(FALSE) {} - Item_sum_num(THD *thd, Item *a, Item* b): - Item_sum(thd, a, b), is_evaluated(FALSE) {} - Item_sum_num(THD *thd, List<Item> &list): - Item_sum(thd, list), is_evaluated(FALSE) {} - Item_sum_num(THD *thd, Item_sum_num *item): - Item_sum(thd, item),is_evaluated(item->is_evaluated) {} - bool fix_fields(THD *, Item **); - longlong val_int() { return val_int_from_real(); /* Real as default */ } - String *val_str(String*str); - my_decimal *val_decimal(my_decimal *); - void reset_field(); -}; - - -class Item_sum_int :public Item_sum_num -{ -public: - Item_sum_int(THD *thd): Item_sum_num(thd) {} - Item_sum_int(THD *thd, Item *item_par): Item_sum_num(thd, item_par) {} - Item_sum_int(THD *thd, List<Item> &list): Item_sum_num(thd, list) {} - Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {} - double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } - String *val_str(String*str); - my_decimal *val_decimal(my_decimal *); - const Type_handler *type_handler() const { return &type_handler_longlong; } - void fix_length_and_dec() - { decimals=0; max_length=21; maybe_null=null_value=0; } -}; - - -class Item_sum_sum :public Item_sum_num, - public Type_handler_hybrid_field_type -{ -protected: - bool direct_added; - bool direct_reseted_field; - bool direct_sum_is_null; - double direct_sum_real; - double sum; - my_decimal direct_sum_decimal; - my_decimal dec_buffs[2]; - uint curr_dec_buff; - void fix_length_and_dec(); - -public: - Item_sum_sum(THD *thd, Item *item_par, bool distinct): - Item_sum_num(thd, item_par), direct_added(FALSE), - direct_reseted_field(FALSE) - { - set_distinct(distinct); - } - Item_sum_sum(THD *thd, Item_sum_sum *item); - enum Sumfunctype sum_func () const - { - return has_with_distinct() ? SUM_DISTINCT_FUNC : SUM_FUNC; - } - void cleanup(); - void direct_add(my_decimal *add_sum_decimal); - void direct_add(double add_sum_real, bool add_sum_is_null); - void clear(); - bool add(); - double val_real(); - longlong val_int(); - String *val_str(String*str); - my_decimal *val_decimal(my_decimal *); - const Type_handler *type_handler() const - { return Type_handler_hybrid_field_type::type_handler(); } - void fix_length_and_dec_double(); - void fix_length_and_dec_decimal(); - void reset_field(); - void update_field(); - void no_rows_in_result() {} - const char *func_name() const - { - return has_with_distinct() ? "sum(distinct " : "sum("; - } - Item *copy_or_same(THD* thd); - void remove(); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_sum>(thd, this); } - - bool supports_removal() const - { - return true; - } - -private: - void add_helper(bool perform_removal); - ulonglong count; -}; - - -class Item_sum_count :public Item_sum_int -{ - bool direct_counted; - bool direct_reseted_field; - longlong direct_count; - longlong count; - - friend class Aggregator_distinct; - - void clear(); - bool add(); - void cleanup(); - void remove(); - -public: - Item_sum_count(THD *thd, Item *item_par): - Item_sum_int(thd, item_par), direct_counted(FALSE), - direct_reseted_field(FALSE), count(0) - {} - - /** - Constructs an instance for COUNT(DISTINCT) - - @param list a list of the arguments to the aggregate function - - This constructor is called by the parser only for COUNT (DISTINCT). - */ - - Item_sum_count(THD *thd, List<Item> &list): - Item_sum_int(thd, list), direct_counted(FALSE), - direct_reseted_field(FALSE), count(0) - { - set_distinct(TRUE); - } - Item_sum_count(THD *thd, Item_sum_count *item): - Item_sum_int(thd, item), direct_counted(FALSE), - direct_reseted_field(FALSE), count(item->count) - {} - enum Sumfunctype sum_func () const - { - return has_with_distinct() ? COUNT_DISTINCT_FUNC : COUNT_FUNC; - } - void no_rows_in_result() { count=0; } - void make_const(longlong count_arg) - { - count=count_arg; - Item_sum::make_const(); - } - longlong val_int(); - void reset_field(); - void update_field(); - void direct_add(longlong add_count); - const char *func_name() const - { - return has_with_distinct() ? "count(distinct " : "count("; - } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_count>(thd, this); } - - bool supports_removal() const - { - return true; - } -}; - - -class Item_sum_avg :public Item_sum_sum -{ -public: - // TODO-cvicentiu given that Item_sum_sum now uses a counter of its own, in - // order to implement remove(), it is possible to remove this member. - ulonglong count; - uint prec_increment; - uint f_precision, f_scale, dec_bin_size; - - Item_sum_avg(THD *thd, Item *item_par, bool distinct): - Item_sum_sum(thd, item_par, distinct), count(0) - {} - Item_sum_avg(THD *thd, Item_sum_avg *item) - :Item_sum_sum(thd, item), count(item->count), - prec_increment(item->prec_increment) {} - - void fix_length_and_dec_double(); - void fix_length_and_dec_decimal(); - void fix_length_and_dec(); - enum Sumfunctype sum_func () const - { - return has_with_distinct() ? AVG_DISTINCT_FUNC : AVG_FUNC; - } - void clear(); - bool add(); - void remove(); - double val_real(); - // In SPs we might force the "wrong" type with select into a declare variable - longlong val_int() { return val_int_from_real(); } - my_decimal *val_decimal(my_decimal *); - String *val_str(String *str); - void reset_field(); - void update_field(); - Item *result_item(THD *thd, Field *field); - void no_rows_in_result() {} - const char *func_name() const - { - return has_with_distinct() ? "avg(distinct " : "avg("; - } - Item *copy_or_same(THD* thd); - Field *create_tmp_field(bool group, TABLE *table); - void cleanup() - { - count= 0; - Item_sum_sum::cleanup(); - } - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_avg>(thd, this); } - - bool supports_removal() const - { - return true; - } -}; - - -/* - variance(a) = - - = sum (ai - avg(a))^2 / count(a) ) - = sum (ai^2 - 2*ai*avg(a) + avg(a)^2) / count(a) - = (sum(ai^2) - sum(2*ai*avg(a)) + sum(avg(a)^2))/count(a) = - = (sum(ai^2) - 2*avg(a)*sum(a) + count(a)*avg(a)^2)/count(a) = - = (sum(ai^2) - 2*sum(a)*sum(a)/count(a) + count(a)*sum(a)^2/count(a)^2 )/count(a) = - = (sum(ai^2) - 2*sum(a)^2/count(a) + sum(a)^2/count(a) )/count(a) = - = (sum(ai^2) - sum(a)^2/count(a))/count(a) - -But, this falls prey to catastrophic cancellation. Instead, use the recurrence formulas - - M_{1} = x_{1}, ~ M_{k} = M_{k-1} + (x_{k} - M_{k-1}) / k newline - S_{1} = 0, ~ S_{k} = S_{k-1} + (x_{k} - M_{k-1}) times (x_{k} - M_{k}) newline - for 2 <= k <= n newline - ital variance = S_{n} / (n-1) - -*/ - -class Item_sum_variance : public Item_sum_num -{ - void fix_length_and_dec(); - -public: - double recurrence_m, recurrence_s; /* Used in recurrence relation. */ - ulonglong count; - uint sample; - uint prec_increment; - - Item_sum_variance(THD *thd, Item *item_par, uint sample_arg): - Item_sum_num(thd, item_par), count(0), - sample(sample_arg) - {} - Item_sum_variance(THD *thd, Item_sum_variance *item); - enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } - void fix_length_and_dec_double(); - void fix_length_and_dec_decimal(); - void clear(); - bool add(); - double val_real(); - my_decimal *val_decimal(my_decimal *); - void reset_field(); - void update_field(); - Item *result_item(THD *thd, Field *field); - void no_rows_in_result() {} - const char *func_name() const - { return sample ? "var_samp(" : "variance("; } - Item *copy_or_same(THD* thd); - Field *create_tmp_field(bool group, TABLE *table); - const Type_handler *type_handler() const { return &type_handler_double; } - void cleanup() - { - count= 0; - Item_sum_num::cleanup(); - } - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_variance>(thd, this); } -}; - -/* - standard_deviation(a) = sqrt(variance(a)) -*/ - -class Item_sum_std :public Item_sum_variance -{ - public: - Item_sum_std(THD *thd, Item *item_par, uint sample_arg): - Item_sum_variance(thd, item_par, sample_arg) {} - Item_sum_std(THD *thd, Item_sum_std *item) - :Item_sum_variance(thd, item) - {} - enum Sumfunctype sum_func () const { return STD_FUNC; } - double val_real(); - Item *result_item(THD *thd, Field *field); - const char *func_name() const { return "std("; } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_std>(thd, this); } -}; - -// This class is a string or number function depending on num_func -class Arg_comparator; -class Item_cache; -class Item_sum_hybrid :public Item_sum, public Type_handler_hybrid_field_type -{ -protected: - bool direct_added; - Item *direct_item; - Item_cache *value, *arg_cache; - Arg_comparator *cmp; - int cmp_sign; - bool was_values; // Set if we have found at least one row (for max/min only) - bool was_null_value; - - public: - Item_sum_hybrid(THD *thd, Item *item_par,int sign): - Item_sum(thd, item_par), - Type_handler_hybrid_field_type(&type_handler_longlong), - direct_added(FALSE), value(0), arg_cache(0), cmp(0), - cmp_sign(sign), was_values(TRUE) - { collation.set(&my_charset_bin); } - Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) - :Item_sum(thd, item), - Type_handler_hybrid_field_type(item), - direct_added(FALSE), value(item->value), arg_cache(0), - cmp_sign(item->cmp_sign), was_values(item->was_values) - { } - bool fix_fields(THD *, Item **); - void fix_length_and_dec(); - void setup_hybrid(THD *thd, Item *item, Item *value_arg); - void clear(); - void direct_add(Item *item); - double val_real(); - longlong val_int(); - my_decimal *val_decimal(my_decimal *); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - void reset_field(); - String *val_str(String *); - const Type_handler *real_type_handler() const - { - return get_arg(0)->real_type_handler(); - } - const Type_handler *type_handler() const - { return Type_handler_hybrid_field_type::type_handler(); } - TYPELIB *get_typelib() const { return args[0]->get_typelib(); } - void update_field(); - void min_max_update_str_field(); - void min_max_update_real_field(); - void min_max_update_int_field(); - void min_max_update_decimal_field(); - void cleanup(); - bool any_value() { return was_values; } - void no_rows_in_result(); - void restore_to_before_no_rows_in_result(); - Field *create_tmp_field(bool group, TABLE *table); - void setup_caches(THD *thd) { setup_hybrid(thd, arguments()[0], NULL); } -}; - - -class Item_sum_min :public Item_sum_hybrid -{ -public: - Item_sum_min(THD *thd, Item *item_par): Item_sum_hybrid(thd, item_par, 1) {} - Item_sum_min(THD *thd, Item_sum_min *item) :Item_sum_hybrid(thd, item) {} - enum Sumfunctype sum_func () const {return MIN_FUNC;} - - bool add(); - const char *func_name() const { return "min("; } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_min>(thd, this); } -}; - - -class Item_sum_max :public Item_sum_hybrid -{ -public: - Item_sum_max(THD *thd, Item *item_par): Item_sum_hybrid(thd, item_par, -1) {} - Item_sum_max(THD *thd, Item_sum_max *item) :Item_sum_hybrid(thd, item) {} - enum Sumfunctype sum_func () const {return MAX_FUNC;} - - bool add(); - const char *func_name() const { return "max("; } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_max>(thd, this); } -}; - - -class Item_sum_bit :public Item_sum_int -{ -public: - Item_sum_bit(THD *thd, Item *item_par, ulonglong reset_arg): - Item_sum_int(thd, item_par), reset_bits(reset_arg), bits(reset_arg), - as_window_function(FALSE), num_values_added(0) {} - Item_sum_bit(THD *thd, Item_sum_bit *item): - Item_sum_int(thd, item), reset_bits(item->reset_bits), bits(item->bits), - as_window_function(item->as_window_function), - num_values_added(item->num_values_added) - { - if (as_window_function) - memcpy(bit_counters, item->bit_counters, sizeof(bit_counters)); - } - enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;} - void clear(); - longlong val_int(); - void reset_field(); - void update_field(); - void fix_length_and_dec() - { decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; } - void cleanup() - { - bits= reset_bits; - if (as_window_function) - clear_as_window(); - Item_sum_int::cleanup(); - } - void setup_window_func(THD *thd __attribute__((unused)), - Window_spec *window_spec __attribute__((unused))) - { - as_window_function= TRUE; - clear_as_window(); - } - void remove() - { - if (as_window_function) - { - remove_as_window(args[0]->val_int()); - return; - } - // Unless we're counting bits, we can not remove anything. - DBUG_ASSERT(0); - } - - bool supports_removal() const - { - return true; - } - -protected: - enum bit_counters { NUM_BIT_COUNTERS= 64 }; - ulonglong reset_bits,bits; - /* - Marks whether the function is to be computed as a window function. - */ - bool as_window_function; - // When used as an aggregate window function, we need to store - // this additional information. - ulonglong num_values_added; - ulonglong bit_counters[NUM_BIT_COUNTERS]; - bool add_as_window(ulonglong value); - bool remove_as_window(ulonglong value); - bool clear_as_window(); - virtual void set_bits_from_counters()= 0; -}; - - -class Item_sum_or :public Item_sum_bit -{ -public: - Item_sum_or(THD *thd, Item *item_par): Item_sum_bit(thd, item_par, 0) {} - Item_sum_or(THD *thd, Item_sum_or *item) :Item_sum_bit(thd, item) {} - bool add(); - const char *func_name() const { return "bit_or("; } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_or>(thd, this); } - -private: - void set_bits_from_counters(); -}; - - -class Item_sum_and :public Item_sum_bit -{ -public: - Item_sum_and(THD *thd, Item *item_par): - Item_sum_bit(thd, item_par, ULONGLONG_MAX) {} - Item_sum_and(THD *thd, Item_sum_and *item) :Item_sum_bit(thd, item) {} - bool add(); - const char *func_name() const { return "bit_and("; } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_and>(thd, this); } - -private: - void set_bits_from_counters(); -}; - -class Item_sum_xor :public Item_sum_bit -{ -public: - Item_sum_xor(THD *thd, Item *item_par): Item_sum_bit(thd, item_par, 0) {} - Item_sum_xor(THD *thd, Item_sum_xor *item) :Item_sum_bit(thd, item) {} - bool add(); - const char *func_name() const { return "bit_xor("; } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_xor>(thd, this); } - -private: - void set_bits_from_counters(); -}; - -class sp_head; -class sp_name; -class Query_arena; -struct st_sp_security_context; - -/* - Item_sum_sp handles STORED AGGREGATE FUNCTIONS - - Each Item_sum_sp represents a custom aggregate function. Inside the - function's body, we require at least one occurence of FETCH GROUP NEXT ROW - instruction. This cursor is what makes custom stored aggregates possible. - - During computation the function's add method is called. This in turn performs - an execution of the function. The function will execute from the current - function context (and instruction), if one exists, or from the start if not. - See Item_sp for more details. - - Upon encounter of FETCH GROUP NEXT ROW instruction, the function will pause - execution. We assume that the user has performed the necessary additions for - a row, between two encounters of FETCH GROUP NEXT ROW. - - Example: - create aggregate function f1(x INT) returns int - begin - declare continue handler for not found return s; - declare s int default 0 - loop - fetch group next row; - set s = s + x; - end loop; - end - - The function will always stop after an encounter of FETCH GROUP NEXT ROW, - except (!) on first encounter, as the value for the first row in the - group is already set in the argument x. This behaviour is done so when - a user writes a function, he should "logically" include FETCH GROUP NEXT ROW - before any "add" instructions in the stored function. This means however that - internally, the first occurence doesn't stop the function. See the - implementation of FETCH GROUP NEXT ROW for details as to how it happens. - - Either way, one should assume that after calling "Item_sum_sp::add()" that - the values for that particular row have been added to the aggregation. - - To produce values for val_xxx methods we need an extra syntactic construct. - We require a continue handler when "no more rows are available". val_xxx - methods force a function return by executing the function again, while - setting a server flag that no more rows have been found. This implies - that val_xxx methods should only be called once per group however. - - Example: - DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN ret_val; -*/ -class Item_sum_sp :public Item_sum, - public Item_sp -{ - private: - bool execute(); - -public: - Item_sum_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name, - sp_head *sp); - - Item_sum_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name, - sp_head *sp, List<Item> &list); - - enum Sumfunctype sum_func () const - { - return SP_AGGREGATE_FUNC; - } - void fix_length_and_dec(); - bool fix_fields(THD *thd, Item **ref); - const char *func_name() const; - const Type_handler *type_handler() const; - bool add(); - - /* val_xx functions */ - longlong val_int() - { - if(execute()) - return 0; - return sp_result_field->val_int(); - } - - double val_real() - { - if(execute()) - return 0.0; - return sp_result_field->val_real(); - } - - my_decimal *val_decimal(my_decimal *dec_buf) - { - if(execute()) - return NULL; - return sp_result_field->val_decimal(dec_buf); - } - - String *val_str(String *str) - { - String buf; - char buff[20]; - buf.set(buff, 20, str->charset()); - buf.length(0); - if (execute()) - return NULL; - /* - result_field will set buf pointing to internal buffer - of the resul_field. Due to this it will change any time - when SP is executed. In order to prevent occasional - corruption of returned value, we make here a copy. - */ - sp_result_field->val_str(&buf); - str->copy(buf); - return str; - } - void reset_field(){DBUG_ASSERT(0);} - void update_field(){DBUG_ASSERT(0);} - void clear(); - void cleanup(); - inline Field *get_sp_result_field() - { - return sp_result_field; - } - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_sp>(thd, this); } -}; - -/* Items to get the value of a stored sum function */ - -class Item_sum_field :public Item -{ -protected: - Field *field; -public: - Item_sum_field(THD *thd, Item_sum *item) - :Item(thd), field(item->result_field) - { - name= item->name; - maybe_null= true; - decimals= item->decimals; - max_length= item->max_length; - unsigned_flag= item->unsigned_flag; - fixed= true; - } - table_map used_tables() const { return (table_map) 1L; } - void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); } - bool check_vcol_func_processor(void *arg) - { - return mark_unsupported_function(name.str, arg, VCOL_IMPOSSIBLE); - } -}; - - -class Item_avg_field :public Item_sum_field -{ -protected: - uint prec_increment; -public: - Item_avg_field(THD *thd, Item_sum_avg *item) - :Item_sum_field(thd, item), prec_increment(item->prec_increment) - { } - enum Type type() const { return FIELD_AVG_ITEM; } - bool is_null() { update_null_value(); return null_value; } -}; - - -class Item_avg_field_double :public Item_avg_field -{ -public: - Item_avg_field_double(THD *thd, Item_sum_avg *item) - :Item_avg_field(thd, item) - { } - const Type_handler *type_handler() const { return &type_handler_double; } - longlong val_int() { return val_int_from_real(); } - my_decimal *val_decimal(my_decimal *dec) { return val_decimal_from_real(dec); } - String *val_str(String *str) { return val_string_from_real(str); } - double val_real(); - Item *get_copy(THD *thd) - { return get_item_copy<Item_avg_field_double>(thd, this); } -}; - - -class Item_avg_field_decimal :public Item_avg_field -{ - uint f_precision, f_scale, dec_bin_size; -public: - Item_avg_field_decimal(THD *thd, Item_sum_avg *item) - :Item_avg_field(thd, item), - f_precision(item->f_precision), - f_scale(item->f_scale), - dec_bin_size(item->dec_bin_size) - { } - const Type_handler *type_handler() const { return &type_handler_newdecimal; } - double val_real() { return val_real_from_decimal(); } - longlong val_int() { return val_int_from_decimal(); } - String *val_str(String *str) { return val_string_from_decimal(str); } - my_decimal *val_decimal(my_decimal *); - Item *get_copy(THD *thd) - { return get_item_copy<Item_avg_field_decimal>(thd, this); } -}; - - -class Item_variance_field :public Item_sum_field -{ - uint sample; -public: - Item_variance_field(THD *thd, Item_sum_variance *item) - :Item_sum_field(thd, item), sample(item->sample) - { } - enum Type type() const {return FIELD_VARIANCE_ITEM; } - double val_real(); - longlong val_int() { return val_int_from_real(); } - String *val_str(String *str) - { return val_string_from_real(str); } - my_decimal *val_decimal(my_decimal *dec_buf) - { return val_decimal_from_real(dec_buf); } - bool is_null() { update_null_value(); return null_value; } - const Type_handler *type_handler() const { return &type_handler_double; } - Item *get_copy(THD *thd) - { return get_item_copy<Item_variance_field>(thd, this); } -}; - - -class Item_std_field :public Item_variance_field -{ -public: - Item_std_field(THD *thd, Item_sum_std *item) - :Item_variance_field(thd, item) - { } - enum Type type() const { return FIELD_STD_ITEM; } - double val_real(); - Item *get_copy(THD *thd) - { return get_item_copy<Item_std_field>(thd, this); } -}; - - -/* - User defined aggregates -*/ - -#ifdef HAVE_DLOPEN - -class Item_udf_sum : public Item_sum -{ -protected: - udf_handler udf; - -public: - Item_udf_sum(THD *thd, udf_func *udf_arg): - Item_sum(thd), udf(udf_arg) - { quick_group=0; } - Item_udf_sum(THD *thd, udf_func *udf_arg, List<Item> &list): - Item_sum(thd, list), udf(udf_arg) - { quick_group=0;} - Item_udf_sum(THD *thd, Item_udf_sum *item) - :Item_sum(thd, item), udf(item->udf) - { udf.not_original= TRUE; } - const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd, Item **ref) - { - DBUG_ASSERT(fixed == 0); - - if (init_sum_func_check(thd)) - return TRUE; - - fixed= 1; - /* - We set const_item_cache to false in constructors. - It can be later changed to "true", in a Item_sum::make_const() call. - No make_const() calls should have happened so far. - */ - DBUG_ASSERT(!const_item_cache); - if (udf.fix_fields(thd, this, this->arg_count, this->args)) - return TRUE; - /** - The above call for udf.fix_fields() updates - the Used_tables_and_const_cache part of "this" as if it was a regular - non-aggregate UDF function and can change both const_item_cache and - used_tables_cache members. - - The used_tables_cache will be re-calculated in update_used_tables() - which is called from check_sum_func() below. So we don't care about - its current value. - - The const_item_cache must stay "false" until a Item_sum::make_const() - call happens, if ever. So we need to reset const_item_cache back to - "false" here. - */ - const_item_cache= false; - memcpy (orig_args, args, sizeof (Item *) * arg_count); - return check_sum_func(thd, ref); - } - enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - virtual bool have_field_update(void) const { return 0; } - - void clear(); - bool add(); - void reset_field() {}; - void update_field() {}; - void cleanup(); - virtual void print(String *str, enum_query_type query_type); -}; - - -class Item_sum_udf_float :public Item_udf_sum -{ - public: - Item_sum_udf_float(THD *thd, udf_func *udf_arg): - Item_udf_sum(thd, udf_arg) {} - Item_sum_udf_float(THD *thd, udf_func *udf_arg, List<Item> &list): - Item_udf_sum(thd, udf_arg, list) {} - Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) - :Item_udf_sum(thd, item) {} - longlong val_int() { return val_int_from_real(); } - double val_real(); - String *val_str(String*str); - my_decimal *val_decimal(my_decimal *); - const Type_handler *type_handler() const { return &type_handler_double; } - void fix_length_and_dec() { fix_num_length_and_dec(); } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_udf_float>(thd, this); } -}; - - -class Item_sum_udf_int :public Item_udf_sum -{ -public: - Item_sum_udf_int(THD *thd, udf_func *udf_arg): - Item_udf_sum(thd, udf_arg) {} - Item_sum_udf_int(THD *thd, udf_func *udf_arg, List<Item> &list): - Item_udf_sum(thd, udf_arg, list) {} - Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) - :Item_udf_sum(thd, item) {} - longlong val_int(); - double val_real() - { DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); } - String *val_str(String*str); - my_decimal *val_decimal(my_decimal *); - const Type_handler *type_handler() const { return &type_handler_longlong; } - void fix_length_and_dec() { decimals=0; max_length=21; } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_udf_int>(thd, this); } -}; - - -class Item_sum_udf_str :public Item_udf_sum -{ -public: - Item_sum_udf_str(THD *thd, udf_func *udf_arg): - Item_udf_sum(thd, udf_arg) {} - Item_sum_udf_str(THD *thd, udf_func *udf_arg, List<Item> &list): - Item_udf_sum(thd, udf_arg, list) {} - Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) - :Item_udf_sum(thd, item) {} - String *val_str(String *); - double val_real() - { - int err_not_used; - char *end_not_used; - String *res; - res=val_str(&str_value); - return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(), - &end_not_used, &err_not_used) : 0.0; - } - longlong val_int() - { - int err_not_used; - char *end; - String *res; - CHARSET_INFO *cs; - - if (!(res= val_str(&str_value))) - return 0; /* Null value */ - cs= res->charset(); - end= (char*) res->ptr()+res->length(); - return cs->cset->strtoll10(cs, res->ptr(), &end, &err_not_used); - } - my_decimal *val_decimal(my_decimal *dec); - const Type_handler *type_handler() const { return string_type_handler(); } - void fix_length_and_dec(); - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_udf_str>(thd, this); } -}; - - -class Item_sum_udf_decimal :public Item_udf_sum -{ -public: - Item_sum_udf_decimal(THD *thd, udf_func *udf_arg): - Item_udf_sum(thd, udf_arg) {} - Item_sum_udf_decimal(THD *thd, udf_func *udf_arg, List<Item> &list): - Item_udf_sum(thd, udf_arg, list) {} - Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) - :Item_udf_sum(thd, item) {} - String *val_str(String *); - double val_real(); - longlong val_int(); - my_decimal *val_decimal(my_decimal *); - const Type_handler *type_handler() const { return &type_handler_newdecimal; } - void fix_length_and_dec() { fix_num_length_and_dec(); } - Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd) - { return get_item_copy<Item_sum_udf_decimal>(thd, this); } -}; - -#else /* Dummy functions to get sql_yacc.cc compiled */ - -class Item_sum_udf_float :public Item_sum_num -{ - public: - Item_sum_udf_float(THD *thd, udf_func *udf_arg): - Item_sum_num(thd) {} - Item_sum_udf_float(THD *thd, udf_func *udf_arg, List<Item> &list): - Item_sum_num(thd) {} - Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) - :Item_sum_num(thd, item) {} - enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } - void clear() {} - bool add() { return 0; } - void update_field() {} -}; - - -class Item_sum_udf_int :public Item_sum_num -{ -public: - Item_sum_udf_int(THD *thd, udf_func *udf_arg): - Item_sum_num(thd) {} - Item_sum_udf_int(THD *thd, udf_func *udf_arg, List<Item> &list): - Item_sum_num(thd) {} - Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) - :Item_sum_num(thd, item) {} - enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; } - double val_real() { DBUG_ASSERT(fixed == 1); return 0; } - void clear() {} - bool add() { return 0; } - void update_field() {} -}; - - -class Item_sum_udf_decimal :public Item_sum_num -{ - public: - Item_sum_udf_decimal(THD *thd, udf_func *udf_arg): - Item_sum_num(thd) {} - Item_sum_udf_decimal(THD *thd, udf_func *udf_arg, List<Item> &list): - Item_sum_num(thd) {} - Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) - :Item_sum_num(thd, item) {} - enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } - my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } - void clear() {} - bool add() { return 0; } - void update_field() {} -}; - - -class Item_sum_udf_str :public Item_sum_num -{ -public: - Item_sum_udf_str(THD *thd, udf_func *udf_arg): - Item_sum_num(thd) {} - Item_sum_udf_str(THD *thd, udf_func *udf_arg, List<Item> &list): - Item_sum_num(thd) {} - Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) - :Item_sum_num(thd, item) {} - String *val_str(String *) - { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } - double val_real() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; } - longlong val_int() { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } - void fix_length_and_dec() { maybe_null=1; max_length=0; } - enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - void clear() {} - bool add() { return 0; } - void update_field() {} -}; - -#endif /* HAVE_DLOPEN */ - -C_MODE_START -int group_concat_key_cmp_with_distinct(void* arg, const void* key1, - const void* key2); -int group_concat_key_cmp_with_order(void* arg, const void* key1, - const void* key2); -int dump_leaf_key(void* key_arg, - element_count count __attribute__((unused)), - void* item_arg); -C_MODE_END - -class Item_func_group_concat : public Item_sum -{ - TMP_TABLE_PARAM *tmp_table_param; - String result; - String *separator; - TREE tree_base; - TREE *tree; - Item **ref_pointer_array; - - /** - If DISTINCT is used with this GROUP_CONCAT, this member is used to filter - out duplicates. - @see Item_func_group_concat::setup - @see Item_func_group_concat::add - @see Item_func_group_concat::clear - */ - Unique *unique_filter; - TABLE *table; - ORDER **order; - Name_resolution_context *context; - /** The number of ORDER BY items. */ - uint arg_count_order; - /** The number of selected items, aka the expr list. */ - uint arg_count_field; - uint row_count; - bool distinct; - bool warning_for_row; - bool always_null; - bool force_copy_fields; - bool no_appended; - /* - Following is 0 normal object and pointer to original one for copy - (to correctly free resources) - */ - Item_func_group_concat *original; - - friend int group_concat_key_cmp_with_distinct(void* arg, const void* key1, - const void* key2); - friend int group_concat_key_cmp_with_order(void* arg, const void* key1, - const void* key2); - friend int dump_leaf_key(void* key_arg, - element_count count __attribute__((unused)), - void* item_arg); -public: - Item_func_group_concat(THD *thd, Name_resolution_context *context_arg, - bool is_distinct, List<Item> *is_select, - const SQL_I_List<ORDER> &is_order, String *is_separator); - - Item_func_group_concat(THD *thd, Item_func_group_concat *item); - ~Item_func_group_concat(); - void cleanup(); - - enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;} - const char *func_name() const { return "group_concat("; } - const Type_handler *type_handler() const - { - if (too_big_for_varchar()) - return &type_handler_blob; - return &type_handler_varchar; - } - void clear(); - bool add(); - void reset_field() { DBUG_ASSERT(0); } // not used - void update_field() { DBUG_ASSERT(0); } // not used - bool fix_fields(THD *,Item **); - bool setup(THD *thd); - void make_unique(); - double val_real() - { - int error; - const char *end; - String *res; - if (!(res= val_str(&str_value))) - return 0.0; - end= res->ptr() + res->length(); - return (my_strtod(res->ptr(), (char**) &end, &error)); - } - longlong val_int() - { - String *res; - char *end_ptr; - int error; - if (!(res= val_str(&str_value))) - return (longlong) 0; - end_ptr= (char*) res->ptr()+ res->length(); - return my_strtoll10(res->ptr(), &end_ptr, &error); - } - my_decimal *val_decimal(my_decimal *decimal_value) - { - return val_decimal_from_string(decimal_value); - } - String* val_str(String* str); - Item *copy_or_same(THD* thd); - void no_rows_in_result() {} - virtual void print(String *str, enum_query_type query_type); - virtual bool change_context_processor(void *cntx) - { context= (Name_resolution_context *)cntx; return FALSE; } - Item *get_copy(THD *thd) - { return get_item_copy<Item_func_group_concat>(thd, this); } -}; - -#endif /* ITEM_SUM_INCLUDED */ |