summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/item_sum.cc.orig4113
-rw-r--r--sql/item_sum.h.orig1821
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 */