2010-03-14 17:01:45 +01:00
|
|
|
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
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
|
2006-12-23 20:17:15 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
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.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
@file
|
|
|
|
|
|
|
|
@brief
|
|
|
|
Sum functions (COUNT, MIN...)
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-05-26 12:09:14 +02:00
|
|
|
#ifdef USE_PRAGMA_IMPLEMENTATION
|
2000-07-31 21:29:14 +02:00
|
|
|
#pragma implementation // gcc: Class implementation
|
|
|
|
#endif
|
|
|
|
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "sql_priv.h"
|
2005-03-01 21:19:19 +01:00
|
|
|
#include "sql_select.h"
|
2003-01-21 20:07:59 +01:00
|
|
|
|
2009-10-01 13:33:30 +02:00
|
|
|
/**
|
|
|
|
Calculate the affordable RAM limit for structures like TREE or Unique
|
|
|
|
used in Item_sum_*
|
|
|
|
*/
|
|
|
|
|
|
|
|
ulonglong Item_sum::ram_limitation(THD *thd)
|
|
|
|
{
|
|
|
|
return min(thd->variables.tmp_table_size,
|
|
|
|
thd->variables.max_heap_table_size);
|
|
|
|
}
|
|
|
|
|
2009-11-17 12:24:23 +01:00
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
Prepare an aggregate function item for checking context conditions.
|
2005-10-15 23:32:37 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
@param thd reference to the thread context info
|
|
|
|
|
|
|
|
@note
|
2005-10-15 23:32:37 +02:00
|
|
|
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.
|
2007-10-11 19:29:09 +02:00
|
|
|
@retval
|
|
|
|
TRUE if an error is reported
|
|
|
|
@retval
|
2005-10-15 23:32:37 +02:00
|
|
|
FALSE otherwise
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool Item_sum::init_sum_func_check(THD *thd)
|
|
|
|
{
|
|
|
|
if (!thd->lex->allow_sum_func)
|
|
|
|
{
|
|
|
|
my_message(ER_INVALID_GROUP_FUNC_USE, ER(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;
|
2007-03-22 22:48:03 +01:00
|
|
|
aggr_sel= NULL;
|
2005-10-15 23:32:37 +02:00
|
|
|
max_arg_level= -1;
|
|
|
|
max_sum_func_level= -1;
|
2008-03-27 17:49:32 +01:00
|
|
|
outer_fields.empty();
|
2005-10-15 23:32:37 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
Check constraints imposed on a usage of a set function.
|
2005-10-15 23:32:37 +02:00
|
|
|
|
|
|
|
The method verifies whether context conditions imposed on a usage
|
|
|
|
of any set function are met for this occurrence.
|
|
|
|
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:
|
2007-10-11 19:29:09 +02:00
|
|
|
@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
|
2005-10-15 23:32:37 +02:00
|
|
|
allow_sum_func will contain:
|
2007-10-11 19:29:09 +02:00
|
|
|
- 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.
|
2005-10-15 23:32:37 +02:00
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
@retval
|
|
|
|
TRUE if an error is reported
|
|
|
|
@retval
|
2005-10-15 23:32:37 +02:00
|
|
|
FALSE otherwise
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool Item_sum::check_sum_func(THD *thd, Item **ref)
|
|
|
|
{
|
|
|
|
bool invalid= FALSE;
|
|
|
|
nesting_map allow_sum_func= thd->lex->allow_sum_func;
|
|
|
|
/*
|
|
|
|
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 & (1 << max_arg_level));
|
|
|
|
}
|
|
|
|
else if (max_arg_level >= 0 || !(allow_sum_func & (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 & (1 << nest_level));
|
2007-03-27 18:48:10 +02:00
|
|
|
if (!invalid && thd->variables.sql_mode & MODE_ANSI)
|
|
|
|
invalid= aggr_level < 0 && max_arg_level < nest_level;
|
2005-10-15 23:32:37 +02:00
|
|
|
}
|
|
|
|
if (!invalid && aggr_level < 0)
|
2007-03-22 22:48:03 +01:00
|
|
|
{
|
2005-10-15 23:32:37 +02:00
|
|
|
aggr_level= nest_level;
|
2007-03-22 22:48:03 +01:00
|
|
|
aggr_sel= thd->lex->current_select;
|
|
|
|
}
|
2005-10-15 23:32:37 +02:00
|
|
|
/*
|
|
|
|
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.
|
2007-03-27 18:48:10 +02:00
|
|
|
*/
|
|
|
|
if (!invalid)
|
|
|
|
invalid= aggr_level <= max_sum_func_level;
|
2005-10-15 23:32:37 +02:00
|
|
|
if (invalid)
|
|
|
|
{
|
|
|
|
my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
|
|
|
|
MYF(0));
|
|
|
|
return TRUE;
|
|
|
|
}
|
2008-03-27 17:49:32 +01:00
|
|
|
|
2007-04-26 10:12:17 +02:00
|
|
|
if (in_sum_func)
|
2005-10-15 23:32:37 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
If the set function is nested adjust the value of
|
|
|
|
max_sum_func_level for the nesting set function.
|
2007-04-26 10:12:17 +02:00
|
|
|
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.
|
2005-10-15 23:32:37 +02:00
|
|
|
*/
|
2007-04-26 10:12:17 +02:00
|
|
|
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);
|
2005-10-15 23:32:37 +02:00
|
|
|
}
|
2008-03-27 17:49:32 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
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->cached_table->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);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sel->full_group_by_flag|= NON_AGG_FIELD_USED;
|
|
|
|
}
|
|
|
|
if (sel->nest_level > aggr_level &&
|
|
|
|
(sel->full_group_by_flag & SUM_FUNC_USED) &&
|
|
|
|
!sel->group_list.elements)
|
|
|
|
{
|
|
|
|
my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,
|
|
|
|
ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
aggr_sel->full_group_by_flag|= SUM_FUNC_USED;
|
2007-03-20 18:46:02 +01:00
|
|
|
update_used_tables();
|
2005-10-15 23:32:37 +02:00
|
|
|
thd->lex->in_sum_func= in_sum_func;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
Attach a set function to the subquery where it must be aggregated.
|
2005-10-15 23:32:37 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
@note
|
2005-10-15 23:32:37 +02:00
|
|
|
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.
|
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
@param thd reference to the thread context info
|
|
|
|
@param ref location of the pointer to this item in the embedding expression
|
|
|
|
|
|
|
|
@retval
|
2005-10-15 23:32:37 +02:00
|
|
|
FALSE if the executes without failures (currently always)
|
2007-10-11 19:29:09 +02:00
|
|
|
@retval
|
2005-10-15 23:32:37 +02:00
|
|
|
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->master_unit()->outer_select() ;
|
|
|
|
sl && sl->nest_level > max_arg_level;
|
|
|
|
sl= sl->master_unit()->outer_select() )
|
|
|
|
{
|
|
|
|
if (aggr_level < 0 && (allow_sum_func & (1 << sl->nest_level)))
|
|
|
|
{
|
|
|
|
/* Found the most nested subquery where the function can be aggregated */
|
|
|
|
aggr_level= sl->nest_level;
|
2007-03-22 22:48:03 +01:00
|
|
|
aggr_sel= sl;
|
2005-10-15 23:32:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sl && (allow_sum_func & (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;
|
2007-03-22 22:48:03 +01:00
|
|
|
aggr_sel= sl;
|
|
|
|
|
2005-10-15 23:32:37 +02:00
|
|
|
}
|
|
|
|
if (aggr_level >= 0)
|
|
|
|
{
|
|
|
|
ref_by= ref;
|
2007-03-22 22:48:03 +01:00
|
|
|
/* Add the object to the list of registered objects assigned to aggr_sel */
|
|
|
|
if (!aggr_sel->inner_sum_func_list)
|
2005-10-15 23:32:37 +02:00
|
|
|
next= this;
|
|
|
|
else
|
|
|
|
{
|
2007-03-22 22:48:03 +01:00
|
|
|
next= aggr_sel->inner_sum_func_list->next;
|
|
|
|
aggr_sel->inner_sum_func_list->next= this;
|
2005-10-15 23:32:37 +02:00
|
|
|
}
|
2007-03-22 22:48:03 +01:00
|
|
|
aggr_sel->inner_sum_func_list= this;
|
|
|
|
aggr_sel->with_sum_func= 1;
|
2006-09-08 18:04:46 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
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;
|
2007-03-22 22:48:03 +01:00
|
|
|
sl && sl != aggr_sel && sl->master_unit()->item;
|
2006-09-08 18:04:46 +02:00
|
|
|
sl= sl->master_unit()->outer_select() )
|
|
|
|
sl->master_unit()->item->with_sum_func= 1;
|
2005-10-15 23:32:37 +02:00
|
|
|
}
|
2007-03-22 22:48:03 +01:00
|
|
|
thd->lex->current_select->mark_as_dependent(aggr_sel);
|
2005-10-15 23:32:37 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-20 18:46:02 +01:00
|
|
|
Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
|
|
|
|
forced_const(FALSE)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
|
|
|
|
{
|
|
|
|
uint i=0;
|
2001-08-02 05:29:50 +02:00
|
|
|
List_iterator_fast<Item> li(list);
|
2000-07-31 21:29:14 +02:00
|
|
|
Item *item;
|
|
|
|
|
|
|
|
while ((item=li++))
|
|
|
|
{
|
|
|
|
args[i++]= item;
|
|
|
|
}
|
|
|
|
}
|
2008-10-06 16:17:25 +02:00
|
|
|
if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count)))
|
|
|
|
{
|
|
|
|
args= NULL;
|
|
|
|
}
|
2002-10-31 01:11:59 +01:00
|
|
|
mark_as_sum_func();
|
2009-09-28 09:21:25 +02:00
|
|
|
init_aggregator();
|
2000-07-31 21:29:14 +02:00
|
|
|
list.empty(); // Fields are used
|
|
|
|
}
|
|
|
|
|
2004-04-05 12:56:05 +02:00
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
Constructor used in processing select with temporary tebles.
|
2004-04-05 12:56:05 +02:00
|
|
|
*/
|
|
|
|
|
2004-01-19 16:53:25 +01:00
|
|
|
Item_sum::Item_sum(THD *thd, Item_sum *item):
|
2008-10-06 16:17:25 +02:00
|
|
|
Item_result_field(thd, item),
|
2007-03-22 22:48:03 +01:00
|
|
|
aggr_sel(item->aggr_sel),
|
2007-03-20 18:46:02 +01:00
|
|
|
nest_level(item->nest_level), aggr_level(item->aggr_level),
|
2008-10-06 16:17:25 +02:00
|
|
|
quick_group(item->quick_group),
|
|
|
|
arg_count(item->arg_count), orig_args(NULL),
|
|
|
|
used_tables_cache(item->used_tables_cache),
|
2007-03-22 22:48:03 +01:00
|
|
|
forced_const(item->forced_const)
|
2003-01-25 01:25:52 +01:00
|
|
|
{
|
|
|
|
if (arg_count <= 2)
|
2008-10-06 16:17:25 +02:00
|
|
|
{
|
2003-01-25 01:25:52 +01:00
|
|
|
args=tmp_args;
|
2008-10-06 16:17:25 +02:00
|
|
|
orig_args=tmp_orig_args;
|
|
|
|
}
|
2003-01-25 01:25:52 +01:00
|
|
|
else
|
2008-10-06 16:17:25 +02:00
|
|
|
{
|
2004-04-03 10:13:51 +02:00
|
|
|
if (!(args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
|
2003-01-25 01:25:52 +01:00
|
|
|
return;
|
2008-10-06 16:17:25 +02:00
|
|
|
if (!(orig_args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
|
|
|
|
return;
|
|
|
|
}
|
2004-04-03 10:13:51 +02:00
|
|
|
memcpy(args, item->args, sizeof(Item*)*arg_count);
|
2008-10-06 16:17:25 +02:00
|
|
|
memcpy(orig_args, item->orig_args, sizeof(Item*)*arg_count);
|
2009-09-28 09:21:25 +02:00
|
|
|
init_aggregator();
|
|
|
|
with_distinct= item->with_distinct;
|
|
|
|
if (item->aggr)
|
|
|
|
set_aggregator(item->aggr->Aggrtype());
|
2004-04-03 10:13:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-02 16:52:22 +01:00
|
|
|
void Item_sum::mark_as_sum_func()
|
2002-10-31 01:11:59 +01:00
|
|
|
{
|
2006-09-01 11:23:43 +02:00
|
|
|
SELECT_LEX *cur_select= current_thd->lex->current_select;
|
|
|
|
cur_select->n_sum_items++;
|
|
|
|
cur_select->with_sum_func= 1;
|
2003-06-24 11:10:35 +02:00
|
|
|
with_sum_func= 1;
|
2002-10-31 01:11:59 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-12-11 08:17:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void Item_sum::make_field(Send_field *tmp_field)
|
|
|
|
{
|
|
|
|
if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
|
|
|
|
{
|
2002-12-11 08:17:51 +01:00
|
|
|
((Item_field*) args[0])->field->make_field(tmp_field);
|
2006-11-22 11:58:00 +01:00
|
|
|
/* For expressions only col_name should be non-empty string. */
|
|
|
|
char *empty_string= (char*)"";
|
|
|
|
tmp_field->db_name= empty_string;
|
|
|
|
tmp_field->org_table_name= empty_string;
|
|
|
|
tmp_field->table_name= empty_string;
|
|
|
|
tmp_field->org_col_name= empty_string;
|
|
|
|
tmp_field->col_name= name;
|
2003-08-27 09:26:03 +02:00
|
|
|
if (maybe_null)
|
|
|
|
tmp_field->flags&= ~NOT_NULL_FLAG;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-12-11 08:17:51 +01:00
|
|
|
else
|
|
|
|
init_make_field(tmp_field, field_type());
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-12-11 08:17:51 +01:00
|
|
|
|
2008-02-22 11:30:33 +01:00
|
|
|
void Item_sum::print(String *str, enum_query_type query_type)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-03-11 13:10:44 +01:00
|
|
|
/* orig_args is not filled with valid values until fix_fields() */
|
|
|
|
Item **pargs= fixed ? orig_args : args;
|
2000-07-31 21:29:14 +02:00
|
|
|
str->append(func_name());
|
|
|
|
for (uint i=0 ; i < arg_count ; i++)
|
|
|
|
{
|
|
|
|
if (i)
|
|
|
|
str->append(',');
|
2008-10-06 16:17:25 +02:00
|
|
|
pargs[i]->print(str, query_type);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2003-01-30 17:07:39 +01:00
|
|
|
Item *Item_sum::get_tmp_table_item(THD *thd)
|
2003-01-25 01:25:52 +01:00
|
|
|
{
|
2003-01-30 17:07:39 +01:00
|
|
|
Item_sum* sum_item= (Item_sum *) copy_or_same(thd);
|
2003-01-25 01:25:52 +01:00
|
|
|
if (sum_item && sum_item->result_field) // If not a const sum func
|
|
|
|
{
|
2003-11-28 11:18:13 +01:00
|
|
|
Field *result_field_tmp= sum_item->result_field;
|
2003-01-25 01:25:52 +01:00
|
|
|
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)
|
2003-11-28 11:18:13 +01:00
|
|
|
((Item_field*) arg)->field= result_field_tmp++;
|
2003-01-25 01:25:52 +01:00
|
|
|
else
|
2003-11-28 11:18:13 +01:00
|
|
|
sum_item->args[i]= new Item_field(result_field_tmp++);
|
2003-01-25 01:25:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sum_item;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
bool Item_sum::walk (Item_processor processor, bool walk_subquery,
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *argument)
|
2003-08-23 12:29:38 +02:00
|
|
|
{
|
|
|
|
if (arg_count)
|
|
|
|
{
|
|
|
|
Item **arg,**arg_end;
|
|
|
|
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
|
|
|
|
{
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
if ((*arg)->walk(processor, walk_subquery, argument))
|
2003-08-23 12:29:38 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (this->*processor)(argument);
|
|
|
|
}
|
|
|
|
|
2004-08-27 15:37:13 +02:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
Field *Item_sum::create_tmp_field(bool group, TABLE *table,
|
|
|
|
uint convert_blob_length)
|
|
|
|
{
|
2005-11-23 21:45:02 +01:00
|
|
|
Field *field;
|
2005-02-08 23:50:45 +01:00
|
|
|
switch (result_type()) {
|
|
|
|
case REAL_RESULT:
|
2007-01-31 09:53:36 +01:00
|
|
|
field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
|
2005-11-23 21:45:02 +01:00
|
|
|
break;
|
2005-02-08 23:50:45 +01:00
|
|
|
case INT_RESULT:
|
2005-11-23 21:45:02 +01:00
|
|
|
field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
|
|
|
|
break;
|
2005-02-08 23:50:45 +01:00
|
|
|
case STRING_RESULT:
|
2006-07-29 22:33:24 +02:00
|
|
|
if (max_length/collation.collation->mbmaxlen <= 255 ||
|
2007-05-21 14:28:31 +02:00
|
|
|
convert_blob_length > Field_varstring::MAX_SIZE ||
|
2006-07-29 22:33:24 +02:00
|
|
|
!convert_blob_length)
|
2005-11-23 21:45:02 +01:00
|
|
|
return make_string_field(table);
|
|
|
|
field= new Field_varstring(convert_blob_length, maybe_null,
|
|
|
|
name, table->s, collation.collation);
|
|
|
|
break;
|
2005-02-08 23:50:45 +01:00
|
|
|
case DECIMAL_RESULT:
|
2009-11-20 11:10:47 +01:00
|
|
|
field= Field_new_decimal::create_from_item(this);
|
2005-11-23 21:45:02 +01:00
|
|
|
break;
|
2005-02-08 23:50:45 +01:00
|
|
|
case ROW_RESULT:
|
|
|
|
default:
|
|
|
|
// This case should never be choosen
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-11-23 21:45:02 +01:00
|
|
|
if (field)
|
|
|
|
field->init(table);
|
|
|
|
return field;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-20 18:46:02 +01:00
|
|
|
void Item_sum::update_used_tables ()
|
|
|
|
{
|
|
|
|
if (!forced_const)
|
|
|
|
{
|
|
|
|
used_tables_cache= 0;
|
|
|
|
for (uint i=0 ; i < arg_count ; i++)
|
|
|
|
{
|
|
|
|
args[i]->update_used_tables();
|
|
|
|
used_tables_cache|= args[i]->used_tables();
|
|
|
|
}
|
|
|
|
|
|
|
|
used_tables_cache&= PSEUDO_TABLE_BITS;
|
|
|
|
|
|
|
|
/* the aggregate function is aggregated into its local context */
|
2007-03-26 08:44:06 +02:00
|
|
|
used_tables_cache |= (1 << aggr_sel->join->tables) - 1;
|
2007-03-20 18:46:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-28 09:21:25 +02:00
|
|
|
Item *Item_sum::set_arg(uint i, THD *thd, Item *new_val)
|
2008-10-06 16:17:25 +02:00
|
|
|
{
|
|
|
|
thd->change_item_tree(args + i, new_val);
|
|
|
|
return new_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-28 09:21:25 +02:00
|
|
|
int Item_sum::set_aggregator(Aggregator::Aggregator_type aggregator)
|
|
|
|
{
|
2009-10-28 11:07:30 +01:00
|
|
|
if (aggr)
|
|
|
|
{
|
2010-01-04 10:39:42 +01:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
2009-10-28 11:07:30 +01:00
|
|
|
DBUG_ASSERT(aggregator == aggr->Aggrtype());
|
2010-01-04 10:39:42 +01:00
|
|
|
aggr->clear();
|
2009-10-28 11:07:30 +01:00
|
|
|
return FALSE;
|
|
|
|
}
|
2009-09-28 09:21:25 +02:00
|
|
|
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();
|
|
|
|
forced_const= FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2)
|
|
|
|
{
|
|
|
|
Field *f= (Field*) arg;
|
|
|
|
return f->cmp(key1, key2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum enum_field_types
|
|
|
|
calc_tmp_field_type(enum enum_field_types table_field_type,
|
|
|
|
Item_result result_type)
|
|
|
|
{
|
|
|
|
/* Adjust tmp table type according to the chosen aggregation type */
|
|
|
|
switch (result_type) {
|
|
|
|
case STRING_RESULT:
|
|
|
|
case REAL_RESULT:
|
|
|
|
if (table_field_type != MYSQL_TYPE_FLOAT)
|
|
|
|
table_field_type= MYSQL_TYPE_DOUBLE;
|
|
|
|
break;
|
|
|
|
case INT_RESULT:
|
|
|
|
table_field_type= MYSQL_TYPE_LONGLONG;
|
|
|
|
/* fallthrough */
|
|
|
|
case DECIMAL_RESULT:
|
|
|
|
if (table_field_type != MYSQL_TYPE_LONGLONG)
|
|
|
|
table_field_type= MYSQL_TYPE_NEWDECIMAL;
|
|
|
|
break;
|
|
|
|
case ROW_RESULT:
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
}
|
|
|
|
return table_field_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
C_MODE_START
|
|
|
|
|
|
|
|
/* Declarations for auxilary C-callbacks */
|
|
|
|
|
|
|
|
static 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(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))
|
|
|
|
return TRUE; // End of memory
|
|
|
|
if (item->const_item() && item->is_null())
|
2009-10-28 11:07:30 +01:00
|
|
|
always_null= true;
|
2009-09-28 09:21:25 +02:00
|
|
|
}
|
|
|
|
if (always_null)
|
|
|
|
return FALSE;
|
2009-10-28 11:07:30 +01:00
|
|
|
count_field_types(select_lex, tmp_table_param, list, 0);
|
|
|
|
tmp_table_param->force_copy_fields= item_sum->has_force_copy_fields();
|
2009-09-28 09:21:25 +02:00
|
|
|
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,
|
2009-12-22 10:35:56 +01:00
|
|
|
(select_lex->options | thd->variables.option_bits),
|
|
|
|
HA_POS_ERROR, "")))
|
2009-09-28 09:21:25 +02:00
|
|
|
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,
|
2009-11-17 12:24:23 +01:00
|
|
|
item_sum->ram_limitation(thd));
|
2009-09-28 09:21:25 +02:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
{
|
|
|
|
List<Create_field> field_list;
|
|
|
|
Create_field field_def; /* field definition */
|
|
|
|
Item *arg;
|
2009-10-28 11:07:30 +01:00
|
|
|
DBUG_ENTER("Aggregator_distinct::setup");
|
2009-09-28 09:21:25 +02:00
|
|
|
/* It's legal to call setup() more than once when in a subquery */
|
|
|
|
if (tree)
|
2009-10-28 11:07:30 +01:00
|
|
|
DBUG_RETURN(FALSE);
|
2009-09-28 09:21:25 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
if (field_list.push_back(&field_def))
|
2009-10-28 11:07:30 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
2009-09-28 09:21:25 +02:00
|
|
|
|
|
|
|
item_sum->null_value= item_sum->maybe_null= 1;
|
|
|
|
item_sum->quick_group= 0;
|
|
|
|
|
|
|
|
DBUG_ASSERT(item_sum->get_arg(0)->fixed);
|
|
|
|
|
2009-10-28 11:07:30 +01:00
|
|
|
arg= item_sum->get_arg(0);
|
2009-09-28 09:21:25 +02:00
|
|
|
if (arg->const_item())
|
|
|
|
{
|
|
|
|
(void) arg->val_int();
|
|
|
|
if (arg->null_value)
|
2009-10-28 11:07:30 +01:00
|
|
|
always_null= true;
|
2009-09-28 09:21:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (always_null)
|
2009-10-28 11:07:30 +01:00
|
|
|
DBUG_RETURN(FALSE);
|
2009-09-28 09:21:25 +02:00
|
|
|
|
|
|
|
enum enum_field_types field_type;
|
|
|
|
|
|
|
|
field_type= calc_tmp_field_type(arg->field_type(),
|
|
|
|
arg->result_type());
|
|
|
|
field_def.init_for_tmp_table(field_type,
|
|
|
|
arg->max_length,
|
|
|
|
arg->decimals,
|
|
|
|
arg->maybe_null,
|
|
|
|
arg->unsigned_flag);
|
|
|
|
|
|
|
|
if (! (table= create_virtual_tmp_table(thd, field_list)))
|
2009-10-28 11:07:30 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
2009-09-28 09:21:25 +02:00
|
|
|
|
|
|
|
/* 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,
|
2009-11-17 12:24:23 +01:00
|
|
|
item_sum->ram_limitation(thd));
|
2009-09-28 09:21:25 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
copy_funcs(tmp_table_param->items_to_copy);
|
|
|
|
|
|
|
|
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_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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We don't have a tree only if 'setup()' hasn't been called;
|
|
|
|
this is the case of sql_select.cc:return_zero_rows.
|
|
|
|
*/
|
|
|
|
if (tree)
|
|
|
|
table->field[0]->set_notnull();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tree && !endup_done)
|
|
|
|
{
|
|
|
|
/* go over the tree of distinct keys and calculate the aggregate value */
|
|
|
|
use_distinct_values= TRUE;
|
|
|
|
tree->walk(item_sum_distinct_walk, (void*) this);
|
|
|
|
use_distinct_values= FALSE;
|
|
|
|
}
|
|
|
|
/* prevent consecutive recalculations */
|
|
|
|
endup_done= TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
String *
|
|
|
|
Item_sum_num::val_str(String *str)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_string_from_real(str);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_decimal_from_real(decimal_value);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
String *
|
|
|
|
Item_sum_int::val_str(String *str)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_string_from_int(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value)
|
|
|
|
{
|
|
|
|
return val_decimal_from_int(decimal_value);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2005-07-01 06:05:42 +02:00
|
|
|
Item_sum_num::fix_fields(THD *thd, Item **ref)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
DBUG_ASSERT(fixed == 0);
|
2004-04-03 10:13:51 +02:00
|
|
|
|
2005-10-15 23:32:37 +02:00
|
|
|
if (init_sum_func_check(thd))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2005-10-15 23:32:37 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
decimals=0;
|
|
|
|
maybe_null=0;
|
|
|
|
for (uint i=0 ; i < arg_count ; i++)
|
|
|
|
{
|
2005-07-01 06:05:42 +02:00
|
|
|
if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2005-02-08 23:50:45 +01:00
|
|
|
set_if_bigger(decimals, args[i]->decimals);
|
2000-07-31 21:29:14 +02:00
|
|
|
maybe_null |= args[i]->maybe_null;
|
|
|
|
}
|
|
|
|
result_field=0;
|
|
|
|
max_length=float_length(decimals);
|
|
|
|
null_value=1;
|
|
|
|
fix_length_and_dec();
|
2005-10-15 23:32:37 +02:00
|
|
|
|
|
|
|
if (check_sum_func(thd, ref))
|
|
|
|
return TRUE;
|
|
|
|
|
2008-10-06 16:17:25 +02:00
|
|
|
memcpy (orig_args, args, sizeof (Item *) * arg_count);
|
2002-11-21 10:01:33 +01:00
|
|
|
fixed= 1;
|
2004-10-20 03:04:37 +02:00
|
|
|
return FALSE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2005-07-01 06:05:42 +02:00
|
|
|
Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-17 13:26:26 +01:00
|
|
|
DBUG_ASSERT(fixed == 0);
|
2004-04-03 10:13:51 +02:00
|
|
|
|
2004-02-18 00:08:52 +01:00
|
|
|
Item *item= args[0];
|
2005-10-15 23:32:37 +02:00
|
|
|
|
|
|
|
if (init_sum_func_check(thd))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2004-02-18 00:08:52 +01:00
|
|
|
|
|
|
|
// 'item' can be changed during fix_fields
|
2008-12-16 13:12:22 +01:00
|
|
|
if ((!item->fixed && item->fix_fields(thd, args)) ||
|
2004-02-18 00:08:52 +01:00
|
|
|
(item= args[0])->check_cols(1))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2005-02-08 23:50:45 +01:00
|
|
|
decimals=item->decimals;
|
2004-02-18 00:08:52 +01:00
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
switch (hybrid_type= item->result_type()) {
|
2005-02-08 23:50:45 +01:00
|
|
|
case INT_RESULT:
|
|
|
|
max_length= 20;
|
|
|
|
break;
|
|
|
|
case DECIMAL_RESULT:
|
|
|
|
max_length= item->max_length;
|
|
|
|
break;
|
|
|
|
case REAL_RESULT:
|
|
|
|
max_length= float_length(decimals);
|
|
|
|
break;
|
|
|
|
case STRING_RESULT:
|
|
|
|
max_length= item->max_length;
|
|
|
|
break;
|
|
|
|
case ROW_RESULT:
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
};
|
2010-03-14 17:01:45 +01:00
|
|
|
setup_hybrid(args[0], NULL);
|
2003-08-27 09:26:03 +02:00
|
|
|
/* MIN/MAX can return NULL for empty set indepedent of the used column */
|
|
|
|
maybe_null= 1;
|
2001-09-27 20:45:48 +02:00
|
|
|
unsigned_flag=item->unsigned_flag;
|
2000-07-31 21:29:14 +02:00
|
|
|
result_field=0;
|
|
|
|
null_value=1;
|
|
|
|
fix_length_and_dec();
|
2008-02-22 09:34:18 +01:00
|
|
|
item= item->real_item();
|
2002-12-11 08:17:51 +01:00
|
|
|
if (item->type() == Item::FIELD_ITEM)
|
|
|
|
hybrid_field_type= ((Item_field*) item)->field->type();
|
|
|
|
else
|
|
|
|
hybrid_field_type= Item::field_type();
|
2005-10-15 23:32:37 +02:00
|
|
|
|
|
|
|
if (check_sum_func(thd, ref))
|
|
|
|
return TRUE;
|
|
|
|
|
2008-10-06 16:17:25 +02:00
|
|
|
orig_args[0]= args[0];
|
2002-11-21 10:01:33 +01:00
|
|
|
fixed= 1;
|
2004-10-20 03:04:37 +02:00
|
|
|
return FALSE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2009-11-17 15:06:46 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2010-03-14 17:01:45 +01:00
|
|
|
void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg)
|
2009-11-17 15:06:46 +01:00
|
|
|
{
|
|
|
|
value= Item_cache::get_cache(item);
|
|
|
|
value->setup(item);
|
2009-12-14 15:17:41 +01:00
|
|
|
if (value_arg)
|
|
|
|
value->store(value_arg);
|
2009-11-17 15:06:46 +01:00
|
|
|
cmp= new Arg_comparator();
|
|
|
|
cmp->set_cmp_func(this, args, (Item**)&value, FALSE);
|
|
|
|
collation.set(item->collation);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-01 21:19:19 +01:00
|
|
|
Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
|
|
|
|
uint convert_blob_length)
|
|
|
|
{
|
2005-11-23 21:45:02 +01:00
|
|
|
Field *field;
|
2005-03-01 21:19:19 +01:00
|
|
|
if (args[0]->type() == Item::FIELD_ITEM)
|
|
|
|
{
|
2005-11-23 21:45:02 +01:00
|
|
|
field= ((Item_field*) args[0])->field;
|
2005-03-01 21:19:19 +01:00
|
|
|
|
2005-03-30 15:57:56 +02:00
|
|
|
if ((field= create_tmp_field_from_field(current_thd, field, name, table,
|
|
|
|
NULL, convert_blob_length)))
|
2005-03-01 21:19:19 +01:00
|
|
|
field->flags&= ~NOT_NULL_FLAG;
|
|
|
|
return field;
|
|
|
|
}
|
2005-07-30 03:53:35 +02:00
|
|
|
/*
|
|
|
|
DATE/TIME fields have STRING_RESULT result types.
|
|
|
|
In order to preserve field type, it's needed to handle DATE/TIME
|
|
|
|
fields creations separately.
|
|
|
|
*/
|
|
|
|
switch (args[0]->field_type()) {
|
|
|
|
case MYSQL_TYPE_DATE:
|
2008-01-08 10:49:40 +01:00
|
|
|
field= new Field_newdate(maybe_null, name, collation.collation);
|
2005-11-23 21:45:02 +01:00
|
|
|
break;
|
2005-07-30 03:53:35 +02:00
|
|
|
case MYSQL_TYPE_TIME:
|
2005-11-23 21:45:02 +01:00
|
|
|
field= new Field_time(maybe_null, name, collation.collation);
|
|
|
|
break;
|
2005-07-30 03:53:35 +02:00
|
|
|
case MYSQL_TYPE_TIMESTAMP:
|
|
|
|
case MYSQL_TYPE_DATETIME:
|
2005-11-23 21:45:02 +01:00
|
|
|
field= new Field_datetime(maybe_null, name, collation.collation);
|
2005-07-30 03:53:35 +02:00
|
|
|
break;
|
2005-11-23 21:45:02 +01:00
|
|
|
default:
|
|
|
|
return Item_sum::create_tmp_field(group, table, convert_blob_length);
|
2005-07-30 03:53:35 +02:00
|
|
|
}
|
2005-11-23 21:45:02 +01:00
|
|
|
if (field)
|
|
|
|
field->init(table);
|
|
|
|
return field;
|
2005-03-01 21:19:19 +01:00
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
** reset and add of sum_func
|
|
|
|
***********************************************************************/
|
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
@todo
|
|
|
|
check if the following assignments are really needed
|
|
|
|
*/
|
2005-02-08 23:50:45 +01:00
|
|
|
Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item)
|
|
|
|
:Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
|
|
|
|
curr_dec_buff(item->curr_dec_buff)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
/* TODO: check if the following assignments are really needed */
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
{
|
|
|
|
my_decimal2decimal(item->dec_buffs, dec_buffs);
|
|
|
|
my_decimal2decimal(item->dec_buffs + 1, dec_buffs + 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sum= item->sum;
|
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_sum_sum::copy_or_same(THD* thd)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_sum(thd, this);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
|
2003-08-28 02:10:14 +02:00
|
|
|
void Item_sum_sum::clear()
|
2003-06-04 17:28:51 +02:00
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
DBUG_ENTER("Item_sum_sum::clear");
|
|
|
|
null_value=1;
|
|
|
|
if (hybrid_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()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
|
|
|
|
maybe_null=null_value=1;
|
|
|
|
decimals= args[0]->decimals;
|
2005-02-19 17:58:27 +01:00
|
|
|
switch (args[0]->result_type()) {
|
2005-02-08 23:50:45 +01:00
|
|
|
case REAL_RESULT:
|
|
|
|
case STRING_RESULT:
|
|
|
|
hybrid_type= REAL_RESULT;
|
|
|
|
sum= 0.0;
|
|
|
|
break;
|
|
|
|
case INT_RESULT:
|
|
|
|
case DECIMAL_RESULT:
|
2005-05-05 17:06:49 +02:00
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
/* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
|
2005-05-05 17:06:49 +02:00
|
|
|
int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS;
|
2009-07-03 09:41:19 +02:00
|
|
|
max_length= my_decimal_precision_to_length_no_truncation(precision,
|
|
|
|
decimals,
|
|
|
|
unsigned_flag);
|
2005-02-08 23:50:45 +01:00
|
|
|
curr_dec_buff= 0;
|
|
|
|
hybrid_type= DECIMAL_RESULT;
|
|
|
|
my_decimal_set_zero(dec_buffs);
|
|
|
|
break;
|
2005-05-05 17:06:49 +02:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
case ROW_RESULT:
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
}
|
|
|
|
DBUG_PRINT("info", ("Type: %s (%d, %d)",
|
|
|
|
(hybrid_type == REAL_RESULT ? "REAL_RESULT" :
|
|
|
|
hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
|
|
|
|
hybrid_type == INT_RESULT ? "INT_RESULT" :
|
|
|
|
"--ILLEGAL!!!--"),
|
|
|
|
max_length,
|
|
|
|
(int)decimals));
|
|
|
|
DBUG_VOID_RETURN;
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
bool Item_sum_sum::add()
|
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
DBUG_ENTER("Item_sum_sum::add");
|
2009-09-28 09:21:25 +02:00
|
|
|
bool arg_is_null;
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
my_decimal value, *val;
|
|
|
|
if (aggr->use_distinct_values)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
/*
|
|
|
|
We are aggregating distinct rows. Get the value from the distinct
|
|
|
|
table pointer
|
|
|
|
*/
|
|
|
|
Aggregator_distinct *daggr= (Aggregator_distinct *)aggr;
|
|
|
|
val= daggr->table->field[0]->val_decimal (&value);
|
|
|
|
arg_is_null= daggr->table->field[0]->is_null();
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
2009-09-28 09:21:25 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* non-distinct aggregation */
|
|
|
|
val= args[0]->val_decimal(&value);
|
|
|
|
arg_is_null= args[0]->null_value;
|
2006-10-31 10:01:27 +01:00
|
|
|
}
|
2009-09-28 09:21:25 +02:00
|
|
|
if (!arg_is_null)
|
|
|
|
{
|
|
|
|
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= 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
double val;
|
|
|
|
if (aggr->use_distinct_values)
|
2006-10-31 10:01:27 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
/*
|
|
|
|
We are aggregating distinct rows. Get the value from the distinct
|
|
|
|
table pointer
|
|
|
|
*/
|
|
|
|
Aggregator_distinct *daggr= (Aggregator_distinct *)aggr;
|
|
|
|
val= daggr->table->field[0]->val_real ();
|
|
|
|
arg_is_null= daggr->table->field[0]->is_null();
|
2006-10-31 10:01:27 +01:00
|
|
|
}
|
2009-09-28 09:21:25 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* non-distinct aggregation */
|
|
|
|
val= args[0]->val_real();
|
|
|
|
arg_is_null= args[0]->null_value;
|
|
|
|
}
|
|
|
|
sum+= val;
|
|
|
|
if (!arg_is_null)
|
|
|
|
null_value= 0;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
2009-09-28 09:21:25 +02:00
|
|
|
DBUG_RETURN(0);
|
2003-12-19 17:04:03 +01:00
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
|
2009-09-28 09:21:25 +02:00
|
|
|
longlong Item_sum_sum::val_int()
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
if (aggr)
|
|
|
|
aggr->endup();
|
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
{
|
|
|
|
longlong result;
|
|
|
|
my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag,
|
|
|
|
&result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return (longlong) rint(val_real());
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-28 09:21:25 +02:00
|
|
|
double Item_sum_sum::val_real()
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
if (aggr)
|
|
|
|
aggr->endup();
|
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum);
|
|
|
|
return sum;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-28 09:21:25 +02:00
|
|
|
String *Item_sum_sum::val_str(String *str)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
if (aggr)
|
|
|
|
aggr->endup();
|
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
return val_string_from_decimal(str);
|
|
|
|
return val_string_from_real(str);
|
2005-03-13 21:50:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-28 09:21:25 +02:00
|
|
|
my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
|
2005-03-13 21:50:43 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
if (aggr)
|
|
|
|
aggr->endup();
|
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
return (dec_buffs + curr_dec_buff);
|
|
|
|
return val_decimal_from_real(val);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
2009-09-28 09:21:25 +02:00
|
|
|
/**
|
|
|
|
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)
|
2005-03-15 01:46:19 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
memcpy(table->field[0]->ptr, element, tree_key_length);
|
|
|
|
item_sum->add();
|
|
|
|
return 0;
|
2005-03-15 01:46:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-28 09:21:25 +02:00
|
|
|
Aggregator_distinct::~Aggregator_distinct()
|
2005-03-13 21:50:43 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
if (tree)
|
|
|
|
{
|
|
|
|
delete tree;
|
|
|
|
tree= NULL;
|
|
|
|
}
|
|
|
|
if (table)
|
|
|
|
{
|
|
|
|
free_tmp_table(table->in_use, table);
|
|
|
|
table=NULL;
|
|
|
|
}
|
|
|
|
if (tmp_table_param)
|
2006-10-31 10:01:27 +01:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
delete tmp_table_param;
|
|
|
|
tmp_table_param= NULL;
|
2006-10-31 10:01:27 +01:00
|
|
|
}
|
2005-03-13 21:50:43 +01:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
|
2003-12-19 17:04:03 +01:00
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_sum_count::copy_or_same(THD* thd)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_count(thd, this);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
|
2003-08-28 02:10:14 +02:00
|
|
|
void Item_sum_count::clear()
|
2003-06-04 17:28:51 +02:00
|
|
|
{
|
2003-08-28 02:10:14 +02:00
|
|
|
count= 0;
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
bool Item_sum_count::add()
|
|
|
|
{
|
2006-12-22 06:29:28 +01:00
|
|
|
if (!args[0]->maybe_null || !args[0]->is_null())
|
2000-07-31 21:29:14 +02:00
|
|
|
count++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
longlong Item_sum_count::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2009-09-28 09:21:25 +02:00
|
|
|
if (aggr)
|
|
|
|
aggr->endup();
|
2000-07-31 21:29:14 +02:00
|
|
|
return (longlong) count;
|
|
|
|
}
|
|
|
|
|
2004-06-10 09:59:55 +02:00
|
|
|
|
|
|
|
void Item_sum_count::cleanup()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("Item_sum_count::cleanup");
|
2006-10-18 13:20:34 +02:00
|
|
|
count= 0;
|
2004-06-10 09:59:55 +02:00
|
|
|
Item_sum_int::cleanup();
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
2003-06-04 17:28:51 +02:00
|
|
|
Avgerage
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
2005-02-08 23:50:45 +01:00
|
|
|
void Item_sum_avg::fix_length_and_dec()
|
|
|
|
{
|
|
|
|
Item_sum_sum::fix_length_and_dec();
|
|
|
|
maybe_null=null_value=1;
|
2005-05-05 17:06:49 +02:00
|
|
|
prec_increment= current_thd->variables.div_precincrement;
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
{
|
2005-05-05 17:06:49 +02:00
|
|
|
int precision= args[0]->decimal_precision() + prec_increment;
|
|
|
|
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
|
2009-07-03 09:41:19 +02:00
|
|
|
max_length= my_decimal_precision_to_length_no_truncation(precision,
|
|
|
|
decimals,
|
|
|
|
unsigned_flag);
|
2005-05-05 17:06:49 +02:00
|
|
|
f_precision= min(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION);
|
|
|
|
f_scale= args[0]->decimals;
|
2005-02-08 23:50:45 +01:00
|
|
|
dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
|
|
|
|
}
|
Bug #24791: Union with AVG-groups generates wrong results
The problem in this bug is when we create temporary tables. When
temporary tables are created for unions, there is some
inferrence being carried out regarding the type of the column.
Whenever this column type is inferred to be REAL (i.e. FLOAT or
DOUBLE), MySQL will always try to maintain exact precision, and
if that is not possible (there are hardware limits, since FLOAT
and DOUBLE are stored as approximate values) will switch to
using approximate values. The problem here is that at this point
the information about number of significant digits is not
available. Furthermore, the number of significant digits should
be increased for the AVG function, however, this was not properly
handled. There are 4 parts to the problem:
#1: DOUBLE and FLOAT fields don't display their proper display
lengths in max_display_length(). This is hard-coded as 53 for
DOUBLE and 24 for FLOAT. Now changed to instead return the
field_length.
#2: Type holders for temporary tables do not preserve the
max_length of the Item's from which they are created, and is
instead reverted to the 53 and 24 from above. This causes
*all* fields to get non-fixed significant digits.
#3: AVG function does not update max_length (display length)
when updating number of decimals.
#4: The function that switches to non-fixed number of
significant digits should use DBL_DIG + 2 or FLT_DIG + 2 as
cut-off values (Since fixed precision does not use the 'e'
notation)
Of these points, #1 is the controversial one, but this
change is preferred and has been cleared with Monty. The
function causes quite a few unit tests to blow up and they had
to b changed, but each one is annotated and motivated. We
frequently see the magical 53 and 24 give way to more relevant
numbers.
2007-03-22 10:56:47 +01:00
|
|
|
else {
|
2005-05-05 17:06:49 +02:00
|
|
|
decimals= min(args[0]->decimals + prec_increment, NOT_FIXED_DEC);
|
Bug #24791: Union with AVG-groups generates wrong results
The problem in this bug is when we create temporary tables. When
temporary tables are created for unions, there is some
inferrence being carried out regarding the type of the column.
Whenever this column type is inferred to be REAL (i.e. FLOAT or
DOUBLE), MySQL will always try to maintain exact precision, and
if that is not possible (there are hardware limits, since FLOAT
and DOUBLE are stored as approximate values) will switch to
using approximate values. The problem here is that at this point
the information about number of significant digits is not
available. Furthermore, the number of significant digits should
be increased for the AVG function, however, this was not properly
handled. There are 4 parts to the problem:
#1: DOUBLE and FLOAT fields don't display their proper display
lengths in max_display_length(). This is hard-coded as 53 for
DOUBLE and 24 for FLOAT. Now changed to instead return the
field_length.
#2: Type holders for temporary tables do not preserve the
max_length of the Item's from which they are created, and is
instead reverted to the 53 and 24 from above. This causes
*all* fields to get non-fixed significant digits.
#3: AVG function does not update max_length (display length)
when updating number of decimals.
#4: The function that switches to non-fixed number of
significant digits should use DBL_DIG + 2 or FLT_DIG + 2 as
cut-off values (Since fixed precision does not use the 'e'
notation)
Of these points, #1 is the controversial one, but this
change is preferred and has been cleared with Monty. The
function causes quite a few unit tests to blow up and they had
to b changed, but each one is annotated and motivated. We
frequently see the magical 53 and 24 give way to more relevant
numbers.
2007-03-22 10:56:47 +01:00
|
|
|
max_length= args[0]->max_length + prec_increment;
|
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_sum_avg::copy_or_same(THD* thd)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_avg(thd, this);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
|
|
|
|
uint convert_blob_len)
|
|
|
|
{
|
2005-11-23 21:45:02 +01:00
|
|
|
Field *field;
|
2005-02-19 17:58:27 +01:00
|
|
|
if (group)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
/*
|
|
|
|
We must store both value and counter in the temporary table in one field.
|
2006-12-22 21:37:37 +01:00
|
|
|
The easiest way is to do this is to store both value in a string
|
2005-02-19 17:58:27 +01:00
|
|
|
and unpack on access.
|
|
|
|
*/
|
2005-11-23 21:45:02 +01:00
|
|
|
field= new Field_string(((hybrid_type == DECIMAL_RESULT) ?
|
2005-02-19 17:58:27 +01:00
|
|
|
dec_bin_size : sizeof(double)) + sizeof(longlong),
|
2005-11-23 21:45:02 +01:00
|
|
|
0, name, &my_charset_bin);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
2005-11-23 21:45:02 +01:00
|
|
|
else if (hybrid_type == DECIMAL_RESULT)
|
2009-11-20 11:10:47 +01:00
|
|
|
field= Field_new_decimal::create_from_item(this);
|
2005-11-23 21:45:02 +01:00
|
|
|
else
|
2007-01-31 09:53:36 +01:00
|
|
|
field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
|
2005-11-23 21:45:02 +01:00
|
|
|
if (field)
|
|
|
|
field->init(table);
|
|
|
|
return field;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-28 02:10:14 +02:00
|
|
|
void Item_sum_avg::clear()
|
2003-06-04 17:28:51 +02:00
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
Item_sum_sum::clear();
|
|
|
|
count=0;
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
bool Item_sum_avg::add()
|
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
if (Item_sum_sum::add())
|
|
|
|
return TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!args[0]->null_value)
|
|
|
|
count++;
|
2005-02-08 23:50:45 +01:00
|
|
|
return FALSE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2004-11-11 19:39:35 +01:00
|
|
|
double Item_sum_avg::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2009-09-28 09:21:25 +02:00
|
|
|
if (aggr)
|
|
|
|
aggr->endup();
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!count)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0.0;
|
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
return Item_sum_sum::val_real() / ulonglong2double(count);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
my_decimal sum_buff, cnt;
|
2005-02-19 17:58:27 +01:00
|
|
|
const my_decimal *sum_dec;
|
2005-02-08 23:50:45 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2009-09-28 09:21:25 +02:00
|
|
|
if (aggr)
|
|
|
|
aggr->endup();
|
2005-02-08 23:50:45 +01:00
|
|
|
if (!count)
|
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-03-06 16:19:47 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
For non-DECIMAL hybrid_type the division will be done in
|
|
|
|
Item_sum_avg::val_real().
|
|
|
|
*/
|
|
|
|
if (hybrid_type != DECIMAL_RESULT)
|
|
|
|
return val_decimal_from_real(val);
|
|
|
|
|
|
|
|
sum_dec= dec_buffs + curr_dec_buff;
|
2005-02-08 23:50:45 +01:00
|
|
|
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt);
|
2005-05-05 17:06:49 +02:00
|
|
|
my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, prec_increment);
|
2005-02-08 23:50:45 +01:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String *Item_sum_avg::val_str(String *str)
|
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
if (aggr)
|
|
|
|
aggr->endup();
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_string_from_decimal(str);
|
|
|
|
return val_string_from_real(str);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2003-06-04 17:28:51 +02:00
|
|
|
Standard deviation
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
2004-11-11 19:39:35 +01:00
|
|
|
double Item_sum_std::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2006-12-22 21:37:37 +01:00
|
|
|
double nr= Item_sum_variance::val_real();
|
|
|
|
DBUG_ASSERT(nr >= 0.0);
|
|
|
|
return sqrt(nr);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_sum_std::copy_or_same(THD* thd)
|
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_std(thd, this);
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-14 00:36:59 +01:00
|
|
|
/*
|
2003-06-04 17:28:51 +02:00
|
|
|
Variance
|
2002-12-14 00:36:59 +01:00
|
|
|
*/
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
|
2006-12-22 21:37:37 +01:00
|
|
|
/**
|
|
|
|
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)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2006-12-22 21:37:37 +01:00
|
|
|
*count += 1;
|
|
|
|
|
|
|
|
if (*count == 1)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2006-12-22 21:37:37 +01:00
|
|
|
*m= nr;
|
|
|
|
*s= 0;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-12-22 21:37:37 +01:00
|
|
|
double m_kminusone= *m;
|
|
|
|
*m= m_kminusone + (nr - m_kminusone) / (double) *count;
|
|
|
|
*s= *s + (nr - m_kminusone) * (nr - *m);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-22 21:37:37 +01:00
|
|
|
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), hybrid_type(item->hybrid_type),
|
|
|
|
count(item->count), sample(item->sample),
|
|
|
|
prec_increment(item->prec_increment)
|
|
|
|
{
|
|
|
|
recurrence_m= item->recurrence_m;
|
|
|
|
recurrence_s= item->recurrence_s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
void Item_sum_variance::fix_length_and_dec()
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
DBUG_ENTER("Item_sum_variance::fix_length_and_dec");
|
|
|
|
maybe_null= null_value= 1;
|
2005-05-05 17:06:49 +02:00
|
|
|
prec_increment= current_thd->variables.div_precincrement;
|
2006-12-22 21:37:37 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
hybrid_type= REAL_RESULT;
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
switch (args[0]->result_type()) {
|
2005-02-08 23:50:45 +01:00
|
|
|
case REAL_RESULT:
|
|
|
|
case STRING_RESULT:
|
2005-05-05 17:06:49 +02:00
|
|
|
decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC);
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
case INT_RESULT:
|
|
|
|
case DECIMAL_RESULT:
|
2005-05-05 17:06:49 +02:00
|
|
|
{
|
|
|
|
int precision= args[0]->decimal_precision()*2 + prec_increment;
|
|
|
|
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
|
2009-07-03 09:41:19 +02:00
|
|
|
max_length= my_decimal_precision_to_length_no_truncation(precision,
|
|
|
|
decimals,
|
|
|
|
unsigned_flag);
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
2005-05-05 17:06:49 +02:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
case ROW_RESULT:
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
}
|
2006-12-22 21:37:37 +01:00
|
|
|
DBUG_PRINT("info", ("Type: REAL_RESULT (%d, %d)", max_length, (int)decimals));
|
2005-02-08 23:50:45 +01:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_sum_variance::copy_or_same(THD* thd)
|
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_variance(thd, this);
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-22 21:37:37 +01:00
|
|
|
/**
|
|
|
|
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.
|
|
|
|
*/
|
2005-02-08 23:50:45 +01:00
|
|
|
Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
|
|
|
|
uint convert_blob_len)
|
|
|
|
{
|
2005-11-23 21:45:02 +01:00
|
|
|
Field *field;
|
2005-02-19 17:58:27 +01:00
|
|
|
if (group)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
/*
|
|
|
|
We must store both value and counter in the temporary table in one field.
|
2006-12-22 21:37:37 +01:00
|
|
|
The easiest way is to do this is to store both value in a string
|
2005-02-19 17:58:27 +01:00
|
|
|
and unpack on access.
|
|
|
|
*/
|
2006-12-22 21:59:10 +01:00
|
|
|
field= new Field_string(sizeof(double)*2 + sizeof(longlong), 0, name, &my_charset_bin);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
2005-11-23 21:45:02 +01:00
|
|
|
else
|
2007-01-31 09:53:36 +01:00
|
|
|
field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
|
2006-12-22 21:59:10 +01:00
|
|
|
|
|
|
|
if (field != NULL)
|
2005-11-23 21:45:02 +01:00
|
|
|
field->init(table);
|
2006-12-22 21:59:10 +01:00
|
|
|
|
2005-11-23 21:45:02 +01:00
|
|
|
return field;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-28 02:10:14 +02:00
|
|
|
void Item_sum_variance::clear()
|
2002-12-14 00:36:59 +01:00
|
|
|
{
|
2006-12-22 21:37:37 +01:00
|
|
|
count= 0;
|
2002-12-14 00:36:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Item_sum_variance::add()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-12-22 21:37:37 +01:00
|
|
|
/*
|
|
|
|
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);
|
2000-07-31 21:29:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-11-11 19:39:35 +01:00
|
|
|
double Item_sum_variance::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2006-12-22 21:37:37 +01:00
|
|
|
/*
|
|
|
|
'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));
|
2005-02-25 19:19:04 +01:00
|
|
|
if (count <= sample)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
null_value=1;
|
|
|
|
return 0.0;
|
|
|
|
}
|
2006-12-22 21:37:37 +01:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
null_value=0;
|
2006-12-22 21:37:37 +01:00
|
|
|
return variance_fp_recurrence_result(recurrence_s, count, sample);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf)
|
|
|
|
{
|
2006-12-22 21:37:37 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
return val_decimal_from_real(dec_buf);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
void Item_sum_variance::reset_field()
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
double nr;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res= result_field->ptr;
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2006-12-22 21:37:37 +01:00
|
|
|
nr= args[0]->val_real(); /* sets null_value as side-effect */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
if (args[0]->null_value)
|
|
|
|
bzero(res,sizeof(double)*2+sizeof(longlong));
|
|
|
|
else
|
|
|
|
{
|
2006-12-22 21:37:37 +01:00
|
|
|
/* 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);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2003-08-29 12:44:35 +02:00
|
|
|
void Item_sum_variance::update_field()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-12-22 21:37:37 +01:00
|
|
|
ulonglong field_count;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res=result_field->ptr;
|
2006-12-22 21:37:37 +01:00
|
|
|
|
|
|
|
double nr= args[0]->val_real(); /* sets null_value as side-effect */
|
|
|
|
|
|
|
|
if (args[0]->null_value)
|
2005-02-08 23:50:45 +01:00
|
|
|
return;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2006-12-22 21:37:37 +01:00
|
|
|
/* 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));
|
2003-08-20 15:25:44 +02:00
|
|
|
field_count=sint8korr(res+sizeof(double)*2);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2006-12-22 21:37:37 +01:00
|
|
|
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);
|
2005-02-19 17:58:27 +01:00
|
|
|
res+= sizeof(double)*2;
|
|
|
|
int8store(res,field_count);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* min & max */
|
|
|
|
|
2004-05-07 22:06:11 +02:00
|
|
|
void Item_sum_hybrid::clear()
|
|
|
|
{
|
2009-11-17 15:06:46 +01:00
|
|
|
value->null_value= 1;
|
2004-05-07 22:06:11 +02:00
|
|
|
null_value= 1;
|
|
|
|
}
|
|
|
|
|
2004-11-11 19:39:35 +01:00
|
|
|
double Item_sum_hybrid::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (null_value)
|
|
|
|
return 0.0;
|
2009-11-17 15:06:46 +01:00
|
|
|
return value->val_real();
|
2001-09-27 20:45:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
longlong Item_sum_hybrid::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2001-09-27 20:45:48 +02:00
|
|
|
if (null_value)
|
|
|
|
return 0;
|
2009-11-17 15:06:46 +01:00
|
|
|
return value->val_int();
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
if (null_value)
|
|
|
|
return 0;
|
2009-11-17 15:06:46 +01:00
|
|
|
return value->val_decimal(val);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String *
|
|
|
|
Item_sum_hybrid::val_str(String *str)
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (null_value)
|
|
|
|
return 0;
|
2009-11-17 15:06:46 +01:00
|
|
|
return value->val_str(str);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
|
2004-06-10 09:59:55 +02:00
|
|
|
void Item_sum_hybrid::cleanup()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("Item_sum_hybrid::cleanup");
|
|
|
|
Item_sum::cleanup();
|
2007-03-20 18:46:02 +01:00
|
|
|
forced_const= FALSE;
|
2009-11-17 15:06:46 +01:00
|
|
|
if (cmp)
|
|
|
|
delete cmp;
|
|
|
|
cmp= 0;
|
2004-11-18 17:10:07 +01:00
|
|
|
/*
|
2004-12-07 20:18:15 +01:00
|
|
|
by default it is TRUE to avoid TRUE reporting by
|
2004-11-18 17:10:07 +01:00
|
|
|
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.
|
2004-12-07 20:18:15 +01:00
|
|
|
If some results found it will be left unchanged.
|
2004-11-18 17:10:07 +01:00
|
|
|
*/
|
|
|
|
was_values= TRUE;
|
2004-06-10 09:59:55 +02:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
2004-11-18 17:10:07 +01:00
|
|
|
void Item_sum_hybrid::no_rows_in_result()
|
|
|
|
{
|
|
|
|
was_values= FALSE;
|
2005-09-21 08:49:19 +02:00
|
|
|
clear();
|
2004-11-18 17:10:07 +01:00
|
|
|
}
|
|
|
|
|
2004-06-10 09:59:55 +02:00
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_sum_min::copy_or_same(THD* thd)
|
|
|
|
{
|
2009-11-17 15:06:46 +01:00
|
|
|
Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this);
|
2010-03-14 17:01:45 +01:00
|
|
|
item->setup_hybrid(args[0], value);
|
2009-11-17 15:06:46 +01:00
|
|
|
return item;
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
bool Item_sum_min::add()
|
|
|
|
{
|
2009-11-17 15:06:46 +01:00
|
|
|
/* args[0] < value */
|
|
|
|
int res= cmp->compare();
|
|
|
|
if (!args[0]->null_value &&
|
|
|
|
(null_value || res < 0))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-11-17 15:06:46 +01:00
|
|
|
value->store(args[0]);
|
2009-11-24 16:26:13 +01:00
|
|
|
value->cache_value();
|
2009-11-17 15:06:46 +01:00
|
|
|
null_value= 0;
|
2001-09-27 20:45:48 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_sum_max::copy_or_same(THD* thd)
|
|
|
|
{
|
2009-11-17 15:06:46 +01:00
|
|
|
Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this);
|
2010-03-14 17:01:45 +01:00
|
|
|
item->setup_hybrid(args[0], value);
|
2009-11-17 15:06:46 +01:00
|
|
|
return item;
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-09-27 20:45:48 +02:00
|
|
|
bool Item_sum_max::add()
|
|
|
|
{
|
2009-11-17 15:06:46 +01:00
|
|
|
/* args[0] > value */
|
|
|
|
int res= cmp->compare();
|
|
|
|
if (!args[0]->null_value &&
|
|
|
|
(null_value || res > 0))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-11-17 15:06:46 +01:00
|
|
|
value->store(args[0]);
|
2009-11-24 16:26:13 +01:00
|
|
|
value->cache_value();
|
2009-11-17 15:06:46 +01:00
|
|
|
null_value= 0;
|
2001-09-27 20:45:48 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* bit_or and bit_and */
|
|
|
|
|
|
|
|
longlong Item_sum_bit::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
return (longlong) bits;
|
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
|
2003-08-28 02:10:14 +02:00
|
|
|
void Item_sum_bit::clear()
|
2003-06-04 17:28:51 +02:00
|
|
|
{
|
2003-08-28 02:10:14 +02:00
|
|
|
bits= reset_bits;
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Item *Item_sum_or::copy_or_same(THD* thd)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_or(thd, this);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
bool Item_sum_or::add()
|
|
|
|
{
|
|
|
|
ulonglong value= (ulonglong) args[0]->val_int();
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
bits|=value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-10-15 08:11:03 +02:00
|
|
|
Item *Item_sum_xor::copy_or_same(THD* thd)
|
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_xor(thd, this);
|
2003-10-15 08:11:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Item_sum_xor::add()
|
|
|
|
{
|
|
|
|
ulonglong value= (ulonglong) args[0]->val_int();
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
bits^=value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_sum_and::copy_or_same(THD* thd)
|
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_and(thd, this);
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
bool Item_sum_and::add()
|
|
|
|
{
|
|
|
|
ulonglong value= (ulonglong) args[0]->val_int();
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
bits&=value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
** reset result of a Item_sum with is saved in a tmp_table
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
void Item_sum_num::reset_field()
|
|
|
|
{
|
2004-11-11 19:39:35 +01:00
|
|
|
double nr= args[0]->val_real();
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res=result_field->ptr;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
switch(hybrid_type) {
|
2005-02-08 23:50:45 +01:00
|
|
|
case STRING_RESULT:
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
char buff[MAX_FIELD_WIDTH];
|
2002-12-19 13:42:35 +01:00
|
|
|
String tmp(buff,sizeof(buff),result_field->charset()),*res;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
res=args[0]->val_str(&tmp);
|
|
|
|
if (args[0]->null_value)
|
|
|
|
{
|
|
|
|
result_field->set_null();
|
|
|
|
result_field->reset();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result_field->set_notnull();
|
2002-05-17 13:29:52 +02:00
|
|
|
result_field->store(res->ptr(),res->length(),tmp.charset());
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
case INT_RESULT:
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
longlong nr=args[0]->val_int();
|
|
|
|
|
|
|
|
if (maybe_null)
|
|
|
|
{
|
|
|
|
if (args[0]->null_value)
|
|
|
|
{
|
|
|
|
nr=0;
|
|
|
|
result_field->set_null();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result_field->set_notnull();
|
|
|
|
}
|
2005-09-14 00:41:44 +02:00
|
|
|
result_field->store(nr, unsigned_flag);
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-02-08 23:50:45 +01:00
|
|
|
case REAL_RESULT:
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-11 19:39:35 +01:00
|
|
|
double nr= args[0]->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
if (maybe_null)
|
|
|
|
{
|
|
|
|
if (args[0]->null_value)
|
|
|
|
{
|
|
|
|
nr=0.0;
|
|
|
|
result_field->set_null();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result_field->set_notnull();
|
|
|
|
}
|
|
|
|
result_field->store(nr);
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DECIMAL_RESULT:
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
my_decimal value_buff, *arg_dec= args[0]->val_decimal(&value_buff);
|
2005-02-08 23:50:45 +01:00
|
|
|
|
|
|
|
if (maybe_null)
|
|
|
|
{
|
|
|
|
if (args[0]->null_value)
|
|
|
|
result_field->set_null();
|
|
|
|
else
|
|
|
|
result_field->set_notnull();
|
|
|
|
}
|
2005-02-19 17:58:27 +01:00
|
|
|
/*
|
|
|
|
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);
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ROW_RESULT:
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Item_sum_sum::reset_field()
|
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
{
|
|
|
|
my_decimal value, *arg_val= args[0]->val_decimal(&value);
|
2005-02-19 17:58:27 +01:00
|
|
|
if (!arg_val) // Null
|
|
|
|
arg_val= &decimal_zero;
|
|
|
|
result_field->store_decimal(arg_val);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(hybrid_type == REAL_RESULT);
|
|
|
|
double nr= args[0]->val_real(); // Nulls also return 0
|
|
|
|
float8store(result_field->ptr, nr);
|
|
|
|
}
|
2003-04-15 21:04:16 +02:00
|
|
|
if (args[0]->null_value)
|
|
|
|
result_field->set_null();
|
|
|
|
else
|
|
|
|
result_field->set_notnull();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Item_sum_count::reset_field()
|
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res=result_field->ptr;
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong nr=0;
|
2009-09-28 09:21:25 +02:00
|
|
|
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2006-12-22 06:29:28 +01:00
|
|
|
if (!args[0]->maybe_null || !args[0]->is_null())
|
2000-07-31 21:29:14 +02:00
|
|
|
nr=1;
|
|
|
|
int8store(res,nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Item_sum_avg::reset_field()
|
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res=result_field->ptr;
|
2009-09-28 09:21:25 +02:00
|
|
|
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
longlong tmp;
|
2005-02-08 23:50:45 +01:00
|
|
|
my_decimal value, *arg_dec= args[0]->val_decimal(&value);
|
|
|
|
if (args[0]->null_value)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
arg_dec= &decimal_zero;
|
|
|
|
tmp= 0;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
else
|
2005-02-19 17:58:27 +01:00
|
|
|
tmp= 1;
|
|
|
|
my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale);
|
|
|
|
res+= dec_bin_size;
|
|
|
|
int8store(res, tmp);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
double nr= args[0]->val_real();
|
|
|
|
|
|
|
|
if (args[0]->null_value)
|
|
|
|
bzero(res,sizeof(double)+sizeof(longlong));
|
|
|
|
else
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
longlong tmp= 1;
|
2005-02-08 23:50:45 +01:00
|
|
|
float8store(res,nr);
|
|
|
|
res+=sizeof(double);
|
|
|
|
int8store(res,tmp);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void Item_sum_bit::reset_field()
|
2003-11-20 22:03:04 +01:00
|
|
|
{
|
2003-12-02 17:39:51 +01:00
|
|
|
reset();
|
|
|
|
int8store(result_field->ptr, bits);
|
2003-11-20 22:03:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Item_sum_bit::update_field()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res=result_field->ptr;
|
2003-11-20 22:03:04 +01:00
|
|
|
bits= uint8korr(res);
|
|
|
|
add();
|
|
|
|
int8store(res, bits);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
calc next value and merge it with field_value.
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
2003-08-20 15:25:44 +02:00
|
|
|
void Item_sum_sum::update_field()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-09-28 09:21:25 +02:00
|
|
|
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
2003-04-15 21:04:16 +02:00
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
my_decimal value, *arg_val= args[0]->val_decimal(&value);
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
{
|
|
|
|
if (!result_field->is_null())
|
|
|
|
{
|
|
|
|
my_decimal field_value,
|
|
|
|
*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;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res=result_field->ptr;
|
2005-02-08 23:50:45 +01:00
|
|
|
|
|
|
|
float8get(old_nr,res);
|
|
|
|
nr= args[0]->val_real();
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
{
|
|
|
|
old_nr+=nr;
|
|
|
|
result_field->set_notnull();
|
|
|
|
}
|
|
|
|
float8store(res,old_nr);
|
2003-04-15 21:04:16 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-20 15:25:44 +02:00
|
|
|
void Item_sum_count::update_field()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
longlong nr;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res=result_field->ptr;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-08-20 15:25:44 +02:00
|
|
|
nr=sint8korr(res);
|
2006-12-22 06:29:28 +01:00
|
|
|
if (!args[0]->maybe_null || !args[0]->is_null())
|
2000-07-31 21:29:14 +02:00
|
|
|
nr++;
|
|
|
|
int8store(res,nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-20 15:25:44 +02:00
|
|
|
void Item_sum_avg::update_field()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
longlong field_count;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res=result_field->ptr;
|
2009-09-28 09:21:25 +02:00
|
|
|
|
|
|
|
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_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;
|
2005-02-19 17:58:27 +01:00
|
|
|
field_count++;
|
2005-02-08 23:50:45 +01:00
|
|
|
int8store(res, field_count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
double nr;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
nr= args[0]->val_real();
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
double old_nr;
|
|
|
|
float8get(old_nr, res);
|
|
|
|
field_count= sint8korr(res + sizeof(double));
|
2005-02-08 23:50:45 +01:00
|
|
|
old_nr+= nr;
|
2005-02-19 17:58:27 +01:00
|
|
|
float8store(res,old_nr);
|
|
|
|
res+= sizeof(double);
|
2005-02-08 23:50:45 +01:00
|
|
|
field_count++;
|
2005-02-19 17:58:27 +01:00
|
|
|
int8store(res, field_count);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2003-08-20 15:25:44 +02:00
|
|
|
void Item_sum_hybrid::update_field()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
switch (hybrid_type) {
|
2005-02-08 23:50:45 +01:00
|
|
|
case STRING_RESULT:
|
2003-08-20 15:25:44 +02:00
|
|
|
min_max_update_str_field();
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
case INT_RESULT:
|
2003-08-20 15:25:44 +02:00
|
|
|
min_max_update_int_field();
|
2005-02-08 23:50:45 +01:00
|
|
|
break;
|
|
|
|
case DECIMAL_RESULT:
|
|
|
|
min_max_update_decimal_field();
|
|
|
|
break;
|
|
|
|
default:
|
2003-08-20 15:25:44 +02:00
|
|
|
min_max_update_real_field();
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2003-08-20 15:25:44 +02:00
|
|
|
Item_sum_hybrid::min_max_update_str_field()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-11-17 15:06:46 +01:00
|
|
|
DBUG_ASSERT(cmp);
|
|
|
|
String *res_str=args[0]->val_str(&cmp->value1);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-08-20 15:25:44 +02:00
|
|
|
if (!args[0]->null_value)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-11-17 15:06:46 +01:00
|
|
|
result_field->val_str(&cmp->value2);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
if (result_field->is_null() ||
|
2009-11-17 15:06:46 +01:00
|
|
|
(cmp_sign * sortcmp(res_str,&cmp->value2,collation.collation)) < 0)
|
2002-05-17 13:29:52 +02:00
|
|
|
result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
|
2000-07-31 21:29:14 +02:00
|
|
|
result_field->set_notnull();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2003-08-20 15:25:44 +02:00
|
|
|
Item_sum_hybrid::min_max_update_real_field()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
double nr,old_nr;
|
|
|
|
|
|
|
|
old_nr=result_field->val_real();
|
2004-11-11 19:39:35 +01:00
|
|
|
nr= args[0]->val_real();
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!args[0]->null_value)
|
|
|
|
{
|
2003-08-20 15:25:44 +02:00
|
|
|
if (result_field->is_null(0) ||
|
2000-07-31 21:29:14 +02:00
|
|
|
(cmp_sign > 0 ? old_nr > nr : old_nr < nr))
|
|
|
|
old_nr=nr;
|
|
|
|
result_field->set_notnull();
|
|
|
|
}
|
2003-08-20 15:25:44 +02:00
|
|
|
else if (result_field->is_null(0))
|
2000-07-31 21:29:14 +02:00
|
|
|
result_field->set_null();
|
|
|
|
result_field->store(old_nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2003-08-20 15:25:44 +02:00
|
|
|
Item_sum_hybrid::min_max_update_int_field()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
longlong nr,old_nr;
|
|
|
|
|
|
|
|
old_nr=result_field->val_int();
|
|
|
|
nr=args[0]->val_int();
|
|
|
|
if (!args[0]->null_value)
|
|
|
|
{
|
2003-08-20 15:25:44 +02:00
|
|
|
if (result_field->is_null(0))
|
2000-07-31 21:29:14 +02:00
|
|
|
old_nr=nr;
|
2001-09-27 20:45:48 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
bool res=(unsigned_flag ?
|
|
|
|
(ulonglong) old_nr > (ulonglong) nr :
|
|
|
|
old_nr > nr);
|
|
|
|
/* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */
|
2001-10-03 16:02:14 +02:00
|
|
|
if ((cmp_sign > 0) ^ (!res))
|
2001-09-27 20:45:48 +02:00
|
|
|
old_nr=nr;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
result_field->set_notnull();
|
|
|
|
}
|
2003-08-20 15:25:44 +02:00
|
|
|
else if (result_field->is_null(0))
|
2000-07-31 21:29:14 +02:00
|
|
|
result_field->set_null();
|
2005-09-14 00:41:44 +02:00
|
|
|
result_field->store(old_nr, unsigned_flag);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
@todo
|
|
|
|
optimize: do not get result_field in case of args[0] is NULL
|
|
|
|
*/
|
2005-02-08 23:50:45 +01:00
|
|
|
void
|
|
|
|
Item_sum_hybrid::min_max_update_decimal_field()
|
|
|
|
{
|
|
|
|
/* TODO: optimize: do not get result_field in case of args[0] is NULL */
|
|
|
|
my_decimal old_val, nr_val;
|
|
|
|
const my_decimal *old_nr= result_field->val_decimal(&old_val);
|
|
|
|
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
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
else if (result_field->is_null(0))
|
|
|
|
result_field->set_null();
|
|
|
|
result_field->store_decimal(old_nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
name=item->name;
|
|
|
|
decimals=item->decimals;
|
2005-05-05 17:06:49 +02:00
|
|
|
max_length= item->max_length;
|
|
|
|
unsigned_flag= item->unsigned_flag;
|
2000-07-31 21:29:14 +02:00
|
|
|
field=item->result_field;
|
|
|
|
maybe_null=1;
|
2005-02-08 23:50:45 +01:00
|
|
|
hybrid_type= res_type;
|
2005-05-05 17:06:49 +02:00
|
|
|
prec_increment= item->prec_increment;
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
|
|
|
{
|
|
|
|
f_scale= item->f_scale;
|
|
|
|
f_precision= item->f_precision;
|
|
|
|
dec_bin_size= item->dec_bin_size;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2004-11-11 19:39:35 +01:00
|
|
|
double Item_avg_field::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
// fix_fields() never calls for this Item
|
2005-02-19 17:58:27 +01:00
|
|
|
double nr;
|
|
|
|
longlong count;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *res;
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_real_from_decimal();
|
2005-02-08 23:50:45 +01:00
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
float8get(nr,field->ptr);
|
|
|
|
res= (field->ptr+sizeof(double));
|
|
|
|
count= sint8korr(res);
|
|
|
|
|
|
|
|
if ((null_value= !count))
|
|
|
|
return 0.0;
|
|
|
|
return nr/(double) count;
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
longlong Item_avg_field::val_int()
|
|
|
|
{
|
2005-11-30 08:17:25 +01:00
|
|
|
return (longlong) rint(val_real());
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
my_decimal *Item_avg_field::val_decimal(my_decimal *dec_buf)
|
2005-02-08 23:50:45 +01:00
|
|
|
{
|
|
|
|
// fix_fields() never calls for this Item
|
2005-02-19 17:58:27 +01:00
|
|
|
if (hybrid_type == REAL_RESULT)
|
|
|
|
return val_decimal_from_real(dec_buf);
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
longlong count= sint8korr(field->ptr + dec_bin_size);
|
|
|
|
if ((null_value= !count))
|
2005-02-19 17:58:27 +01:00
|
|
|
return 0;
|
2005-02-08 23:50:45 +01:00
|
|
|
|
|
|
|
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);
|
2005-05-05 17:06:49 +02:00
|
|
|
my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
|
|
|
|
&dec_field, &dec_count, prec_increment);
|
2005-02-19 17:58:27 +01:00
|
|
|
return dec_buf;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
String *Item_avg_field::val_str(String *str)
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
// fix_fields() never calls for this Item
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_string_from_decimal(str);
|
|
|
|
return val_string_from_real(str);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
Item_std_field::Item_std_field(Item_sum_std *item)
|
2002-12-14 00:36:59 +01:00
|
|
|
: Item_variance_field(item)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2004-11-11 19:39:35 +01:00
|
|
|
double Item_std_field::val_real()
|
2002-12-14 00:36:59 +01:00
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
double nr;
|
2004-03-18 14:14:36 +01:00
|
|
|
// fix_fields() never calls for this Item
|
2006-12-22 21:37:37 +01:00
|
|
|
nr= Item_variance_field::val_real();
|
|
|
|
DBUG_ASSERT(nr >= 0.0);
|
|
|
|
return sqrt(nr);
|
2002-12-14 00:36:59 +01:00
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
|
|
|
my_decimal *Item_std_field::val_decimal(my_decimal *dec_buf)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We can't call val_decimal_from_real() for DECIMAL_RESULT as
|
|
|
|
Item_variance_field::val_real() would cause an infinite loop
|
|
|
|
*/
|
|
|
|
my_decimal tmp_dec, *dec;
|
|
|
|
double nr;
|
|
|
|
if (hybrid_type == REAL_RESULT)
|
|
|
|
return val_decimal_from_real(dec_buf);
|
2006-12-22 21:37:37 +01:00
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
dec= Item_variance_field::val_decimal(dec_buf);
|
|
|
|
if (!dec)
|
|
|
|
return 0;
|
|
|
|
my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr);
|
2006-12-22 21:37:37 +01:00
|
|
|
DBUG_ASSERT(nr >= 0.0);
|
|
|
|
nr= sqrt(nr);
|
2005-02-19 17:58:27 +01:00
|
|
|
double2my_decimal(E_DEC_FATAL_ERROR, nr, &tmp_dec);
|
|
|
|
my_decimal_round(E_DEC_FATAL_ERROR, &tmp_dec, decimals, FALSE, dec_buf);
|
|
|
|
return dec_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-14 00:36:59 +01:00
|
|
|
Item_variance_field::Item_variance_field(Item_sum_variance *item)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
name=item->name;
|
|
|
|
decimals=item->decimals;
|
|
|
|
max_length=item->max_length;
|
2005-05-05 17:06:49 +02:00
|
|
|
unsigned_flag= item->unsigned_flag;
|
2000-07-31 21:29:14 +02:00
|
|
|
field=item->result_field;
|
|
|
|
maybe_null=1;
|
2005-02-25 19:19:04 +01:00
|
|
|
sample= item->sample;
|
2005-05-05 17:06:49 +02:00
|
|
|
prec_increment= item->prec_increment;
|
2005-02-08 23:50:45 +01:00
|
|
|
if ((hybrid_type= item->hybrid_type) == DECIMAL_RESULT)
|
|
|
|
{
|
|
|
|
f_scale0= item->f_scale0;
|
|
|
|
f_precision0= item->f_precision0;
|
|
|
|
dec_bin_size0= item->dec_bin_size0;
|
|
|
|
f_scale1= item->f_scale1;
|
|
|
|
f_precision1= item->f_precision1;
|
|
|
|
dec_bin_size1= item->dec_bin_size1;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2004-11-11 19:39:35 +01:00
|
|
|
double Item_variance_field::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
// fix_fields() never calls for this Item
|
2005-02-08 23:50:45 +01:00
|
|
|
if (hybrid_type == DECIMAL_RESULT)
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_real_from_decimal();
|
|
|
|
|
2006-12-22 21:37:37 +01:00
|
|
|
double recurrence_s;
|
|
|
|
ulonglong count;
|
|
|
|
float8get(recurrence_s, (field->ptr + sizeof(double)));
|
2000-07-31 21:29:14 +02:00
|
|
|
count=sint8korr(field->ptr+sizeof(double)*2);
|
|
|
|
|
2005-02-25 19:19:04 +01:00
|
|
|
if ((null_value= (count <= sample)))
|
2000-07-31 21:29:14 +02:00
|
|
|
return 0.0;
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2006-12-22 21:37:37 +01:00
|
|
|
return variance_fp_recurrence_result(recurrence_s, count, sample);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/****************************************************************************
|
|
|
|
** 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
|
|
|
|
|
2003-08-28 02:10:14 +02:00
|
|
|
void Item_udf_sum::clear()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-08-28 02:10:14 +02:00
|
|
|
DBUG_ENTER("Item_udf_sum::clear");
|
2003-08-27 21:30:50 +02:00
|
|
|
udf.clear();
|
2003-08-28 02:10:14 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Item_udf_sum::add()
|
|
|
|
{
|
2001-09-27 20:45:48 +02:00
|
|
|
DBUG_ENTER("Item_udf_sum::add");
|
2000-07-31 21:29:14 +02:00
|
|
|
udf.add(&null_value);
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
2005-04-30 18:23:40 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-22 11:30:33 +01:00
|
|
|
void Item_udf_sum::print(String *str, enum_query_type query_type)
|
2005-06-17 16:27:47 +02:00
|
|
|
{
|
|
|
|
str->append(func_name());
|
|
|
|
str->append('(');
|
|
|
|
for (uint i=0 ; i < arg_count ; i++)
|
|
|
|
{
|
|
|
|
if (i)
|
|
|
|
str->append(',');
|
2008-02-22 11:30:33 +01:00
|
|
|
args[i]->print(str, query_type);
|
2005-06-17 16:27:47 +02:00
|
|
|
}
|
|
|
|
str->append(')');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_sum_udf_float::copy_or_same(THD* thd)
|
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_udf_float(thd, this);
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
2004-11-11 19:39:35 +01:00
|
|
|
double Item_sum_udf_float::val_real()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("Item_sum_udf_float::val");
|
|
|
|
DBUG_PRINT("info",("result_type: %d arg_count: %d",
|
|
|
|
args[0]->result_type(), arg_count));
|
|
|
|
DBUG_RETURN(udf.val(&null_value));
|
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
String *Item_sum_udf_float::val_str(String *str)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_string_from_real(str);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
my_decimal *Item_sum_udf_float::val_decimal(my_decimal *dec)
|
2003-06-04 17:28:51 +02:00
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_decimal_from_real(dec);
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
String *Item_sum_udf_decimal::val_str(String *str)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_string_from_decimal(str);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double Item_sum_udf_decimal::val_real()
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_real_from_decimal();
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
longlong Item_sum_udf_decimal::val_int()
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_int_from_decimal();
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(fixed == 1);
|
|
|
|
DBUG_ENTER("Item_func_udf_decimal::val_decimal");
|
|
|
|
DBUG_PRINT("info",("result_type: %d arg_count: %d",
|
|
|
|
args[0]->result_type(), arg_count));
|
|
|
|
|
|
|
|
DBUG_RETURN(udf.val_decimal(&null_value, dec_buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Item *Item_sum_udf_decimal::copy_or_same(THD* thd)
|
|
|
|
{
|
|
|
|
return new (thd->mem_root) Item_sum_udf_decimal(thd, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
Item *Item_sum_udf_int::copy_or_same(THD* thd)
|
|
|
|
{
|
|
|
|
return new (thd->mem_root) Item_sum_udf_int(thd, this);
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
longlong Item_sum_udf_int::val_int()
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("Item_sum_udf_int::val_int");
|
|
|
|
DBUG_PRINT("info",("result_type: %d arg_count: %d",
|
|
|
|
args[0]->result_type(), arg_count));
|
|
|
|
DBUG_RETURN(udf.val_int(&null_value));
|
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
String *Item_sum_udf_int::val_str(String *str)
|
|
|
|
{
|
2005-02-19 17:58:27 +01:00
|
|
|
return val_string_from_int(str);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
my_decimal *Item_sum_udf_int::val_decimal(my_decimal *dec)
|
|
|
|
{
|
|
|
|
return val_decimal_from_int(dec);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/** Default max_length is max argument length. */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
|
|
|
|
Item *Item_sum_udf_str::copy_or_same(THD* thd)
|
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_sum_udf_str(thd, this);
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-19 17:58:27 +01:00
|
|
|
my_decimal *Item_sum_udf_str::val_decimal(my_decimal *dec)
|
|
|
|
{
|
|
|
|
return val_decimal_from_string(dec);
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
String *Item_sum_udf_str::val_str(String *str)
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("Item_sum_udf_str::str");
|
|
|
|
String *res=udf.val_str(str,&str_value);
|
|
|
|
null_value = !res;
|
|
|
|
DBUG_RETURN(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_DLOPEN */
|
2003-03-18 00:07:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
GROUP_CONCAT function
|
2004-04-05 12:56:05 +02:00
|
|
|
|
|
|
|
SQL SYNTAX:
|
2005-03-17 22:41:03 +01:00
|
|
|
GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...]
|
2004-04-05 12:56:05 +02:00
|
|
|
[SEPARATOR str_const])
|
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
concat of values from "group by" operation
|
2004-04-05 12:56:05 +02:00
|
|
|
|
|
|
|
BUGS
|
|
|
|
Blobs doesn't work with DISTINCT or ORDER BY
|
2003-03-18 00:07:40 +01:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2007-12-14 12:24:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
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
|
2003-03-18 00:07:40 +01:00
|
|
|
*/
|
|
|
|
|
2010-05-31 17:29:54 +02:00
|
|
|
extern "C"
|
2007-12-14 12:24:20 +01:00
|
|
|
int group_concat_key_cmp_with_distinct(void* arg, const void* key1,
|
|
|
|
const void* key2)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2007-12-14 12:24:20 +01:00
|
|
|
Item_func_group_concat *item_func= (Item_func_group_concat*)arg;
|
|
|
|
TABLE *table= item_func->table;
|
2003-05-31 11:44:19 +02:00
|
|
|
|
2007-12-14 12:24:20 +01:00
|
|
|
for (uint i= 0; i < item_func->arg_count_field; i++)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2007-12-14 12:24:20 +01:00
|
|
|
Item *item= item_func->args[i];
|
|
|
|
/*
|
|
|
|
If field_item is a const item then either get_tp_table_field returns 0
|
|
|
|
or it is an item over a const table.
|
|
|
|
*/
|
|
|
|
if (item->const_item())
|
|
|
|
continue;
|
2004-04-07 03:33:58 +02:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
*/
|
2007-12-14 12:24:20 +01:00
|
|
|
Field *field= item->get_tmp_table_field();
|
|
|
|
int res;
|
2007-12-14 12:40:39 +01:00
|
|
|
uint offset= field->offset(field->table->record[0])-table->s->null_bytes;
|
|
|
|
if((res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset)))
|
2007-12-14 12:24:20 +01:00
|
|
|
return res;
|
2004-04-05 12:56:05 +02:00
|
|
|
}
|
2003-03-18 00:07:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-04-03 20:19:14 +02:00
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
function of sort for syntax: GROUP_CONCAT(expr,... ORDER BY col,... )
|
2003-03-18 00:07:40 +01:00
|
|
|
*/
|
|
|
|
|
2010-05-31 17:29:54 +02:00
|
|
|
extern "C"
|
2007-12-14 12:24:20 +01:00
|
|
|
int group_concat_key_cmp_with_order(void* arg, const void* key1,
|
|
|
|
const void* key2)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2004-04-07 03:33:58 +02:00
|
|
|
Item_func_group_concat* grp_item= (Item_func_group_concat*) arg;
|
2004-04-05 12:56:05 +02:00
|
|
|
ORDER **order_item, **end;
|
2005-03-17 22:41:03 +01:00
|
|
|
TABLE *table= grp_item->table;
|
2003-05-31 11:44:19 +02:00
|
|
|
|
2004-04-07 03:33:58 +02:00
|
|
|
for (order_item= grp_item->order, end=order_item+ grp_item->arg_count_order;
|
2004-04-05 12:56:05 +02:00
|
|
|
order_item < end;
|
|
|
|
order_item++)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2004-04-05 12:56:05 +02:00
|
|
|
Item *item= *(*order_item)->item;
|
2004-04-07 03:33:58 +02:00
|
|
|
/*
|
|
|
|
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();
|
2005-08-02 22:12:41 +02:00
|
|
|
/*
|
|
|
|
If item is a const item then either get_tp_table_field returns 0
|
|
|
|
or it is an item over a const table.
|
|
|
|
*/
|
|
|
|
if (field && !item->const_item())
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2004-04-07 03:33:58 +02:00
|
|
|
int res;
|
2006-11-21 21:32:58 +01:00
|
|
|
uint offset= (field->offset(field->table->record[0]) -
|
|
|
|
table->s->null_bytes);
|
2007-12-14 13:35:52 +01:00
|
|
|
if ((res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset)))
|
2004-04-05 12:56:05 +02:00
|
|
|
return (*order_item)->asc ? res : -res;
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
2004-04-05 12:56:05 +02:00
|
|
|
}
|
2003-04-02 13:55:53 +02:00
|
|
|
/*
|
2004-04-07 03:33:58 +02:00
|
|
|
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
|
2005-03-17 22:41:03 +01:00
|
|
|
if the returned values are not the same we do the sort on.
|
2004-04-07 03:33:58 +02:00
|
|
|
*/
|
2003-03-18 00:07:40 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2003-04-03 20:19:14 +02:00
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
Append data from current leaf to item->result.
|
2003-03-18 00:07:40 +01:00
|
|
|
*/
|
2003-04-02 13:55:53 +02:00
|
|
|
|
2010-05-31 17:29:54 +02:00
|
|
|
extern "C"
|
|
|
|
int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)),
|
|
|
|
void* item_arg)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2010-05-31 17:29:54 +02:00
|
|
|
Item_func_group_concat *item= (Item_func_group_concat *) item_arg;
|
2005-03-17 22:41:03 +01:00
|
|
|
TABLE *table= item->table;
|
2005-06-07 04:43:59 +02:00
|
|
|
String tmp((char *)table->record[1], table->s->reclength,
|
|
|
|
default_charset_info);
|
|
|
|
String tmp2;
|
2010-05-31 17:29:54 +02:00
|
|
|
uchar *key= (uchar *) key_arg;
|
2005-03-21 22:41:28 +01:00
|
|
|
String *result= &item->result;
|
2005-03-17 22:41:03 +01:00
|
|
|
Item **arg= item->args, **arg_end= item->args + item->arg_count_field;
|
2006-11-08 14:03:37 +01:00
|
|
|
uint old_length= result->length();
|
2004-04-07 03:33:58 +02:00
|
|
|
|
2005-09-07 07:20:11 +02:00
|
|
|
if (item->no_appended)
|
|
|
|
item->no_appended= FALSE;
|
|
|
|
else
|
2005-03-21 22:41:28 +01:00
|
|
|
result->append(*item->separator);
|
2004-06-08 15:01:15 +02:00
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
tmp.length(0);
|
2005-03-17 22:41:03 +01:00
|
|
|
|
|
|
|
for (; arg < arg_end; arg++)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2005-03-17 22:41:03 +01:00
|
|
|
String *res;
|
|
|
|
if (! (*arg)->const_item())
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2004-04-07 03:33:58 +02:00
|
|
|
/*
|
|
|
|
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
|
2005-03-17 22:41:03 +01:00
|
|
|
We also can't use table->field array to access the fields
|
|
|
|
because it contains both order and arg list fields.
|
2004-04-07 03:33:58 +02:00
|
|
|
*/
|
2005-03-17 22:41:03 +01:00
|
|
|
Field *field= (*arg)->get_tmp_table_field();
|
2006-11-21 21:32:58 +01:00
|
|
|
uint offset= (field->offset(field->table->record[0]) -
|
|
|
|
table->s->null_bytes);
|
2005-03-17 22:41:03 +01:00
|
|
|
DBUG_ASSERT(offset < table->s->reclength);
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
res= field->val_str(&tmp, key + offset);
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
2005-03-17 22:41:03 +01:00
|
|
|
else
|
|
|
|
res= (*arg)->val_str(&tmp);
|
|
|
|
if (res)
|
2005-03-21 22:41:28 +01:00
|
|
|
result->append(*res);
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
2004-04-05 12:56:05 +02:00
|
|
|
|
2009-09-10 11:18:29 +02:00
|
|
|
item->row_count++;
|
|
|
|
|
2005-03-17 22:41:03 +01:00
|
|
|
/* stop if length of result more than max_length */
|
2005-03-21 22:41:28 +01:00
|
|
|
if (result->length() > item->max_length)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2006-11-07 09:45:48 +01:00
|
|
|
int well_formed_error;
|
|
|
|
CHARSET_INFO *cs= item->collation.collation;
|
2006-11-08 19:08:50 +01:00
|
|
|
const char *ptr= result->ptr();
|
2006-11-07 09:45:48 +01:00
|
|
|
uint add_length;
|
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
add_length= cs->cset->well_formed_len(cs,
|
|
|
|
ptr + old_length,
|
2006-11-08 19:08:50 +01:00
|
|
|
ptr + item->max_length,
|
|
|
|
result->length(),
|
2006-11-07 09:45:48 +01:00
|
|
|
&well_formed_error);
|
2006-11-08 19:08:50 +01:00
|
|
|
result->length(old_length + add_length);
|
2004-04-05 12:56:05 +02:00
|
|
|
item->warning_for_row= TRUE;
|
2009-09-10 11:18:29 +02:00
|
|
|
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
ER_CUT_VALUE_GROUP_CONCAT, ER(ER_CUT_VALUE_GROUP_CONCAT),
|
|
|
|
item->row_count);
|
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-04-03 20:19:14 +02:00
|
|
|
|
2007-10-11 19:29:09 +02:00
|
|
|
/**
|
|
|
|
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.
|
2003-03-18 00:07:40 +01:00
|
|
|
*/
|
2003-04-02 13:55:53 +02:00
|
|
|
|
2005-03-17 22:41:03 +01:00
|
|
|
Item_func_group_concat::
|
2005-07-01 06:05:42 +02:00
|
|
|
Item_func_group_concat(Name_resolution_context *context_arg,
|
|
|
|
bool distinct_arg, List<Item> *select_list,
|
2010-06-10 22:45:22 +02:00
|
|
|
SQL_I_List<ORDER> *order_list, String *separator_arg)
|
2009-09-10 11:18:29 +02:00
|
|
|
:tmp_table_param(0), separator(separator_arg), tree(0),
|
|
|
|
unique_filter(NULL), table(0),
|
2005-07-01 06:05:42 +02:00
|
|
|
order(0), context(context_arg),
|
2005-03-17 22:41:03 +01:00
|
|
|
arg_count_order(order_list ? order_list->elements : 0),
|
|
|
|
arg_count_field(select_list->elements),
|
2009-09-10 11:18:29 +02:00
|
|
|
row_count(0),
|
2005-03-17 22:41:03 +01:00
|
|
|
distinct(distinct_arg),
|
|
|
|
warning_for_row(FALSE),
|
2006-03-30 17:04:21 +02:00
|
|
|
force_copy_fields(0), original(0)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2004-04-05 12:56:05 +02:00
|
|
|
Item *item_select;
|
|
|
|
Item **arg_ptr;
|
|
|
|
|
2005-03-17 22:41:03 +01:00
|
|
|
quick_group= FALSE;
|
2004-04-05 12:56:05 +02:00
|
|
|
arg_count= arg_count_field + arg_count_order;
|
2005-03-17 22:41:03 +01:00
|
|
|
|
2003-04-02 13:55:53 +02:00
|
|
|
/*
|
|
|
|
We need to allocate:
|
2004-04-05 12:56:05 +02:00
|
|
|
args - arg_count_field+arg_count_order
|
|
|
|
(for possible order items in temporare tables)
|
2003-04-02 13:55:53 +02:00
|
|
|
order - arg_count_order
|
|
|
|
*/
|
2004-04-07 03:33:58 +02:00
|
|
|
if (!(args= (Item**) sql_alloc(sizeof(Item*) * arg_count +
|
2005-03-17 22:41:03 +01:00
|
|
|
sizeof(ORDER*)*arg_count_order)))
|
2003-05-31 11:44:19 +02:00
|
|
|
return;
|
2003-05-06 00:38:38 +02:00
|
|
|
|
2008-10-06 16:17:25 +02:00
|
|
|
if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count)))
|
|
|
|
{
|
|
|
|
args= NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-04-05 12:56:05 +02:00
|
|
|
order= (ORDER**)(args + arg_count);
|
|
|
|
|
2003-05-06 00:38:38 +02:00
|
|
|
/* fill args items of show and sort */
|
2005-03-17 22:41:03 +01:00
|
|
|
List_iterator_fast<Item> li(*select_list);
|
2003-03-18 00:07:40 +01:00
|
|
|
|
2004-04-05 12:56:05 +02:00
|
|
|
for (arg_ptr=args ; (item_select= li++) ; arg_ptr++)
|
|
|
|
*arg_ptr= item_select;
|
2003-05-06 00:38:38 +02:00
|
|
|
|
2005-03-17 22:41:03 +01:00
|
|
|
if (arg_count_order)
|
2003-04-02 13:55:53 +02:00
|
|
|
{
|
2004-04-05 12:56:05 +02:00
|
|
|
ORDER **order_ptr= order;
|
2010-06-10 22:45:22 +02:00
|
|
|
for (ORDER *order_item= order_list->first;
|
2005-03-17 22:41:03 +01:00
|
|
|
order_item != NULL;
|
|
|
|
order_item= order_item->next)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2004-04-05 12:56:05 +02:00
|
|
|
(*order_ptr++)= order_item;
|
|
|
|
*arg_ptr= *order_item->item;
|
|
|
|
order_item->item= arg_ptr++;
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-03-17 22:41:03 +01:00
|
|
|
|
2004-04-05 12:56:05 +02:00
|
|
|
|
|
|
|
Item_func_group_concat::Item_func_group_concat(THD *thd,
|
2005-03-17 22:41:03 +01:00
|
|
|
Item_func_group_concat *item)
|
|
|
|
:Item_sum(thd, item),
|
2004-04-05 12:56:05 +02:00
|
|
|
tmp_table_param(item->tmp_table_param),
|
|
|
|
separator(item->separator),
|
|
|
|
tree(item->tree),
|
2007-12-14 12:24:20 +01:00
|
|
|
unique_filter(item->unique_filter),
|
2004-04-05 12:56:05 +02:00
|
|
|
table(item->table),
|
|
|
|
order(item->order),
|
2005-07-01 06:05:42 +02:00
|
|
|
context(item->context),
|
2004-04-05 12:56:05 +02:00
|
|
|
arg_count_order(item->arg_count_order),
|
|
|
|
arg_count_field(item->arg_count_field),
|
2009-09-10 11:18:29 +02:00
|
|
|
row_count(item->row_count),
|
2005-03-17 22:41:03 +01:00
|
|
|
distinct(item->distinct),
|
|
|
|
warning_for_row(item->warning_for_row),
|
|
|
|
always_null(item->always_null),
|
2006-03-30 17:04:21 +02:00
|
|
|
force_copy_fields(item->force_copy_fields),
|
2004-04-05 12:56:05 +02:00
|
|
|
original(item)
|
|
|
|
{
|
|
|
|
quick_group= item->quick_group;
|
2007-07-19 18:21:23 +02:00
|
|
|
result.set_charset(collation.collation);
|
2004-04-05 12:56:05 +02:00
|
|
|
}
|
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
|
2003-04-02 13:55:53 +02:00
|
|
|
|
2003-12-30 11:08:19 +01:00
|
|
|
void Item_func_group_concat::cleanup()
|
|
|
|
{
|
2004-02-08 19:14:13 +01:00
|
|
|
DBUG_ENTER("Item_func_group_concat::cleanup");
|
2004-03-17 13:26:26 +01:00
|
|
|
Item_sum::cleanup();
|
2004-04-03 10:13:51 +02:00
|
|
|
|
2003-12-30 11:08:19 +01:00
|
|
|
/*
|
|
|
|
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)
|
|
|
|
{
|
2005-03-17 22:41:03 +01:00
|
|
|
delete tmp_table_param;
|
|
|
|
tmp_table_param= 0;
|
2003-12-30 11:08:19 +01:00
|
|
|
if (table)
|
2004-02-09 12:31:03 +01:00
|
|
|
{
|
2005-03-17 22:41:03 +01:00
|
|
|
THD *thd= table->in_use;
|
2003-12-30 11:08:19 +01:00
|
|
|
free_tmp_table(thd, table);
|
2004-02-09 12:31:03 +01:00
|
|
|
table= 0;
|
2005-03-17 22:41:03 +01:00
|
|
|
if (tree)
|
|
|
|
{
|
|
|
|
delete_tree(tree);
|
|
|
|
tree= 0;
|
|
|
|
}
|
2007-12-14 12:24:20 +01:00
|
|
|
if (unique_filter)
|
|
|
|
{
|
|
|
|
delete unique_filter;
|
|
|
|
unique_filter= NULL;
|
|
|
|
}
|
2004-02-09 12:31:03 +01:00
|
|
|
}
|
2009-09-10 11:18:29 +02:00
|
|
|
DBUG_ASSERT(tree == 0);
|
2003-12-30 11:08:19 +01:00
|
|
|
}
|
2004-02-08 19:14:13 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2003-12-30 11:08:19 +01:00
|
|
|
}
|
|
|
|
|
2004-02-09 12:31:03 +01:00
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
Item *Item_func_group_concat::copy_or_same(THD* thd)
|
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
return new (thd->mem_root) Item_func_group_concat(thd, this);
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-28 02:10:14 +02:00
|
|
|
void Item_func_group_concat::clear()
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
|
|
|
result.length(0);
|
|
|
|
result.copy();
|
2003-04-02 13:55:53 +02:00
|
|
|
null_value= TRUE;
|
2004-03-30 01:32:41 +02:00
|
|
|
warning_for_row= FALSE;
|
2005-09-07 07:20:11 +02:00
|
|
|
no_appended= TRUE;
|
2005-03-17 22:41:03 +01:00
|
|
|
if (tree)
|
2003-03-18 00:07:40 +01:00
|
|
|
reset_tree(tree);
|
2008-05-01 12:49:26 +02:00
|
|
|
if (unique_filter)
|
2007-12-14 12:24:20 +01:00
|
|
|
unique_filter->reset();
|
2005-03-17 22:41:03 +01:00
|
|
|
/* No need to reset the table as we never call write_row */
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
|
|
|
|
2003-04-02 13:55:53 +02:00
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
bool Item_func_group_concat::add()
|
|
|
|
{
|
2003-06-03 13:02:51 +02:00
|
|
|
if (always_null)
|
|
|
|
return 0;
|
2003-03-18 00:07:40 +01:00
|
|
|
copy_fields(tmp_table_param);
|
|
|
|
copy_funcs(tmp_table_param->items_to_copy);
|
|
|
|
|
2004-04-05 12:56:05 +02:00
|
|
|
for (uint i= 0; i < arg_count_field; i++)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2003-05-31 11:44:19 +02:00
|
|
|
Item *show_item= args[i];
|
2003-04-02 13:55:53 +02:00
|
|
|
if (!show_item->const_item())
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2005-06-07 04:43:59 +02:00
|
|
|
Field *f= show_item->get_tmp_table_field();
|
|
|
|
if (f->is_null_in_record((const uchar*) table->record[0]))
|
2005-03-17 22:41:03 +01:00
|
|
|
return 0; // Skip row if it contains null
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
|
|
|
}
|
2004-04-07 03:33:58 +02:00
|
|
|
|
2003-04-02 13:55:53 +02:00
|
|
|
null_value= FALSE;
|
2007-12-14 12:24:20 +01:00
|
|
|
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;
|
|
|
|
}
|
2004-10-10 09:10:53 +02:00
|
|
|
|
|
|
|
TREE_ELEMENT *el= 0; // Only for safety
|
2007-12-14 12:24:20 +01:00
|
|
|
if (row_eligible && tree)
|
2009-07-10 14:00:34 +02:00
|
|
|
{
|
2005-03-17 22:41:03 +01:00
|
|
|
el= tree_insert(tree, table->record[0] + table->s->null_bytes, 0,
|
|
|
|
tree->custom_arg);
|
2009-07-10 14:00:34 +02:00
|
|
|
/* check if there was enough memory to insert the row */
|
|
|
|
if (!el)
|
|
|
|
return 1;
|
|
|
|
}
|
2004-10-10 09:10:53 +02:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
2007-12-14 12:24:20 +01:00
|
|
|
if (row_eligible && !warning_for_row &&
|
2005-03-17 22:41:03 +01:00
|
|
|
(!tree || (el->count == 1 && distinct && !arg_count_order)))
|
|
|
|
dump_leaf_key(table->record[0] + table->s->null_bytes, 1, this);
|
2004-10-10 09:10:53 +02:00
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-04-02 13:55:53 +02:00
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
bool
|
2005-07-01 06:05:42 +02:00
|
|
|
Item_func_group_concat::fix_fields(THD *thd, Item **ref)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2005-03-17 22:41:03 +01:00
|
|
|
uint i; /* for loop variable */
|
2004-03-17 13:26:26 +01:00
|
|
|
DBUG_ASSERT(fixed == 0);
|
2004-04-03 10:13:51 +02:00
|
|
|
|
2005-10-15 23:32:37 +02:00
|
|
|
if (init_sum_func_check(thd))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2005-03-17 22:41:03 +01:00
|
|
|
|
2005-08-31 16:26:50 +02:00
|
|
|
maybe_null= 1;
|
2004-04-05 12:56:05 +02:00
|
|
|
|
2003-04-02 13:55:53 +02:00
|
|
|
/*
|
2004-04-05 12:56:05 +02:00
|
|
|
Fix fields for select list and ORDER clause
|
2003-04-02 13:55:53 +02:00
|
|
|
*/
|
2004-04-05 12:56:05 +02:00
|
|
|
|
2005-03-17 22:41:03 +01:00
|
|
|
for (i=0 ; i < arg_count ; i++)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2005-02-08 23:50:45 +01:00
|
|
|
if ((!args[i]->fixed &&
|
2005-07-01 06:05:42 +02:00
|
|
|
args[i]->fix_fields(thd, args + i)) ||
|
2004-12-14 01:36:19 +01:00
|
|
|
args[i]->check_cols(1))
|
2004-10-20 03:04:37 +02:00
|
|
|
return TRUE;
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
2004-04-05 12:56:05 +02:00
|
|
|
|
WL#2649 Number-to-string conversions
added:
include/ctype_numconv.inc
mysql-test/include/ctype_numconv.inc
mysql-test/r/ctype_binary.result
mysql-test/t/ctype_binary.test
Adding tests
modified:
mysql-test/r/bigint.result
mysql-test/r/case.result
mysql-test/r/create.result
mysql-test/r/ctype_cp1251.result
mysql-test/r/ctype_latin1.result
mysql-test/r/ctype_ucs.result
mysql-test/r/func_gconcat.result
mysql-test/r/func_str.result
mysql-test/r/metadata.result
mysql-test/r/ps_1general.result
mysql-test/r/ps_2myisam.result
mysql-test/r/ps_3innodb.result
mysql-test/r/ps_4heap.result
mysql-test/r/ps_5merge.result
mysql-test/r/show_check.result
mysql-test/r/type_datetime.result
mysql-test/r/type_ranges.result
mysql-test/r/union.result
mysql-test/suite/ndb/r/ps_7ndb.result
mysql-test/t/ctype_cp1251.test
mysql-test/t/ctype_latin1.test
mysql-test/t/ctype_ucs.test
mysql-test/t/func_str.test
Fixing tests
@ sql/field.cc
- Return str result using my_charset_numeric.
- Using real multi-byte aware str_to_XXX functions
to handle tricky charset values propely (e.g. UCS2)
@ sql/field.h
- Changing derivation of non-string field types to DERIVATION_NUMERIC.
- Changing binary() for numeric/datetime fields to always
return TRUE even if charset is not my_charset_bin. We need
this to keep ha_base_keytype() return HA_KEYTYPE_BINARY.
- Adding BINARY_FLAG into some fields, because it's not
being set automatically anymore with
"my_charset_bin to my_charset_numeric" change.
- Changing derivation for numeric/datetime datatypes to a weaker
value, to make "SELECT concat('string', field)" use character
set of the string literal for the result of the function.
@ sql/item.cc
- Implementing generic val_str_ascii().
- Using max_char_length() instead of direct read of max_length
to make "tricky" charsets like UCS2 work.
NOTE: in the future we'll possibly remove all direct reads of max_length
- Fixing Item_num::safe_charset_converter().
Previously it alligned binary string to
character string (for example by adding leading 0x00
when doing binary->UCS2 conversion). Now it just
converts from my_charset_numbner to "tocs".
- Using val_str_ascii() in Item::get_time() to make UCS2 arguments work.
- Other misc changes
@ sql/item.h
- Changing MY_COLL_CMP_CONV and MY_COLL_ALLOW_CONV to
bit operations instead of hard-coded bit masks.
- Addding new method DTCollation.set_numeric().
- Adding new methods to Item.
- Adding helper functions to make code look nicer:
agg_item_charsets_for_string_result()
agg_item_charsets_for_comparison()
- Changing charset for Item_num-derived items
from my_charset_bin to my_charset_numeric
(which is an alias for latin1).
@ sql/item_cmpfunc.cc
- Using new helper functions
- Other misc changes
@ sql/item_cmpfunc.h
- Fixing strcmp() to return max_length=2.
Previously it returned 1, which was wrong,
because it did not fit '-1'.
@ sql/item_func.cc
- Using new helper functions
- Other minor changes
@ sql/item_func.h
- Removing unused functions
- Adding helper functions
agg_arg_charsets_for_string_result()
agg_arg_charsets_for_comparison()
- Adding set_numeric() into constructors of numeric items.
- Using fix_length_and_charset() and fix_char_length()
instead of direct write to max_length.
@ sql/item_geofunc.cc
- Changing class for Item_func_geometry_type and
Item_func_as_wkt from Item_str_func to
Item_str_ascii_func, to make them return UCS2 result
properly (when character_set_connection=ucs2).
@ sql/item_geofunc.h
- Changing class for Item_func_geometry_type and
Item_func_as_wkt from Item_str_func to
Item_str_ascii_func, to make them return UCS2 result
properly (when @@character_set_connection=ucs2).
@ sql/item_strfunc.cc
- Implementing Item_str_func::val_str().
- Renaming val_str to val_str_ascii for some items,
to make them work with UCS2 properly.
- Using new helper functions
- All single-argument functions that expect string
result now call this method:
agg_arg_charsets_for_string_result(collation, args, 1);
This enables character set conversion to @@character_set_connection
in case of pure numeric input.
@ sql/item_strfunc.h
- Introducing Item_str_ascii_func - for functions
which return pure ASCII data, for performance purposes,
as well as for the cases when the old implementation
of val_str() was heavily 8-bit oriented and implementing
a UCS2-aware version is tricky.
@ sql/item_sum.cc
- Using new helper functions.
@ sql/item_timefunc.cc
- Using my_charset_numeric instead of my_charset_bin.
- Using fix_char_length(), fix_length_and_charset()
and fix_length_and_charset_datetime()
instead of direct write to max_length.
- Using tricky-charset aware function str_to_time_with_warn()
@ sql/item_timefunc.h
- Using new helper functions for charset and length initialization.
- Changing base class for Item_func_get_format() to make
it return UCS2 properly (when character_set_connection=ucs2).
@ sql/item_xmlfunc.cc
- Using new helper function
@ sql/my_decimal.cc
- Adding a new DECIMAL to CHAR converter
with real multibyte support (e.g. UCS2)
@ sql/mysql_priv.h
- Introducing a new derivation level for numeric/datetime data types.
- Adding macros for my_charset_numeric and MY_REPERTOIRE_NUMERIC.
- Adding prototypes for str_set_decimal()
- Adding prototypes for character-set aware str_to_xxx() functions.
@ sql/protocol.cc
- Changing charsetnr to "binary" client-side metadata for
numeric/datetime data types.
@ sql/time.cc
- Adding to_ascii() helper function, to convert a string
in any character set to ascii representation. In the
future can be extended to understand digits written
in various non-Latin word scripts.
- Adding real multy-byte character set aware versions for str_to_XXXX,
to make these these type of queries work correct:
INSERT INTO t1 SET datetime_column=ucs2_expression;
@ strings/ctype-ucs2.c
- endptr was not calculated correctly. INSERTing of UCS2
values into numeric columns returned warnings about
truncated wrong data.
2010-02-11 05:17:25 +01:00
|
|
|
/* skip charset aggregation for order columns */
|
|
|
|
if (agg_item_charsets_for_string_result(collation, func_name(),
|
|
|
|
args, arg_count - arg_count_order))
|
2005-07-26 09:52:02 +02:00
|
|
|
return 1;
|
|
|
|
|
2005-08-30 12:36:47 +02:00
|
|
|
result.set_charset(collation.collation);
|
2003-04-02 13:55:53 +02:00
|
|
|
result_field= 0;
|
|
|
|
null_value= 1;
|
2005-03-17 22:41:03 +01:00
|
|
|
max_length= thd->variables.group_concat_max_len;
|
2005-10-15 23:32:37 +02:00
|
|
|
|
2007-06-22 14:18:40 +02:00
|
|
|
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;
|
|
|
|
|
2007-06-22 15:32:06 +02:00
|
|
|
if (!(buf= (char*) thd->stmt_arena->alloc(buflen)) ||
|
2007-06-22 14:18:40 +02:00
|
|
|
!(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;
|
|
|
|
}
|
|
|
|
|
2005-10-15 23:32:37 +02:00
|
|
|
if (check_sum_func(thd, ref))
|
|
|
|
return TRUE;
|
|
|
|
|
2008-10-06 16:17:25 +02:00
|
|
|
memcpy (orig_args, args, sizeof (Item *) * arg_count);
|
2003-03-18 00:07:40 +01:00
|
|
|
fixed= 1;
|
2004-10-20 03:04:37 +02:00
|
|
|
return FALSE;
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
|
|
|
|
2003-04-02 13:55:53 +02:00
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
bool Item_func_group_concat::setup(THD *thd)
|
|
|
|
{
|
|
|
|
List<Item> list;
|
2003-08-26 11:51:09 +02:00
|
|
|
SELECT_LEX *select_lex= thd->lex->current_select;
|
2004-04-05 12:56:05 +02:00
|
|
|
DBUG_ENTER("Item_func_group_concat::setup");
|
2003-03-18 00:07:40 +01:00
|
|
|
|
2003-04-02 13:55:53 +02:00
|
|
|
/*
|
2005-03-17 22:41:03 +01:00
|
|
|
Currently setup() can be called twice. Please add
|
|
|
|
assertion here when this is fixed.
|
2004-07-21 00:45:08 +02:00
|
|
|
*/
|
2005-03-17 22:41:03 +01:00
|
|
|
if (table || tree)
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
|
|
|
|
if (!(tmp_table_param= new TMP_TABLE_PARAM))
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
/* We'll convert all blobs to varchar fields in the temporary table */
|
2006-11-08 19:08:50 +01:00
|
|
|
tmp_table_param->convert_blob_length= max_length *
|
|
|
|
collation.collation->mbmaxlen;
|
2005-03-17 22:41:03 +01:00
|
|
|
/* Push all not constant fields to the list and create a temp table */
|
2003-06-03 13:02:51 +02:00
|
|
|
always_null= 0;
|
2004-04-05 12:56:05 +02:00
|
|
|
for (uint i= 0; i < arg_count_field; i++)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2003-04-02 13:55:53 +02:00
|
|
|
Item *item= args[i];
|
2003-03-18 00:07:40 +01:00
|
|
|
if (list.push_back(item))
|
2005-03-17 22:41:03 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
2003-03-18 00:07:40 +01:00
|
|
|
if (item->const_item())
|
|
|
|
{
|
2005-04-01 14:04:50 +02:00
|
|
|
if (item->is_null())
|
2005-03-17 22:41:03 +01:00
|
|
|
{
|
|
|
|
always_null= 1;
|
2005-03-21 22:41:28 +01:00
|
|
|
DBUG_RETURN(FALSE);
|
2005-03-17 22:41:03 +01:00
|
|
|
}
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
|
|
|
}
|
2004-07-21 00:45:08 +02:00
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
List<Item> all_fields(list);
|
2005-03-17 22:41:03 +01:00
|
|
|
/*
|
|
|
|
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 &&
|
2005-07-01 06:05:42 +02:00
|
|
|
setup_order(thd, args, context->table_list, list, all_fields, *order))
|
2005-03-17 22:41:03 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
2004-07-21 00:45:08 +02:00
|
|
|
|
2007-06-29 09:39:17 +02:00
|
|
|
count_field_types(select_lex, tmp_table_param, all_fields, 0);
|
2006-03-29 21:30:34 +02:00
|
|
|
tmp_table_param->force_copy_fields= force_copy_fields;
|
2005-03-17 22:41:03 +01:00
|
|
|
DBUG_ASSERT(table == 0);
|
2007-05-21 10:27:33 +02:00
|
|
|
if (arg_count_order > 0 || distinct)
|
2007-10-11 14:20:34 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Currently we have to force conversion of BLOB values to VARCHAR's
|
|
|
|
if we are to store them in TREE objects used for ORDER BY and
|
|
|
|
DISTINCT. This leads to truncation if the BLOB's size exceeds
|
|
|
|
Field_varstring::MAX_SIZE.
|
|
|
|
*/
|
2007-05-21 10:27:33 +02:00
|
|
|
set_if_smaller(tmp_table_param->convert_blob_length,
|
|
|
|
Field_varstring::MAX_SIZE);
|
2007-10-11 14:20:34 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-02 13:55:53 +02:00
|
|
|
/*
|
2005-03-17 22:41:03 +01:00
|
|
|
We have to create a temporary table to get descriptions of fields
|
2003-04-02 13:55:53 +02:00
|
|
|
(types, sizes and so on).
|
2004-04-05 12:56:05 +02:00
|
|
|
|
|
|
|
Note that in the table, we first have the ORDER BY fields, then the
|
|
|
|
field list.
|
2003-04-02 13:55:53 +02:00
|
|
|
*/
|
2005-03-17 22:41:03 +01:00
|
|
|
if (!(table= create_tmp_table(thd, tmp_table_param, all_fields,
|
|
|
|
(ORDER*) 0, 0, TRUE,
|
2009-12-22 10:35:56 +01:00
|
|
|
(select_lex->options | thd->variables.option_bits),
|
2005-03-17 22:41:03 +01:00
|
|
|
HA_POS_ERROR, (char*) "")))
|
|
|
|
DBUG_RETURN(TRUE);
|
2003-03-18 00:07:40 +01:00
|
|
|
table->file->extra(HA_EXTRA_NO_ROWS);
|
2003-04-02 13:55:53 +02:00
|
|
|
table->no_rows= 1;
|
2003-05-31 11:44:19 +02:00
|
|
|
|
2007-12-14 12:24:20 +01:00
|
|
|
/*
|
|
|
|
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;
|
2003-05-31 11:44:19 +02:00
|
|
|
|
2007-12-14 12:24:20 +01:00
|
|
|
if (arg_count_order)
|
2003-03-18 00:07:40 +01:00
|
|
|
{
|
2005-03-17 22:41:03 +01:00
|
|
|
tree= &tree_base;
|
2003-04-02 13:55:53 +02:00
|
|
|
/*
|
2007-12-14 12:24:20 +01:00
|
|
|
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.
|
2003-04-02 13:55:53 +02:00
|
|
|
*/
|
2006-11-27 23:47:21 +01:00
|
|
|
init_tree(tree, (uint) min(thd->variables.max_heap_table_size,
|
|
|
|
thd->variables.sortbuff_size/16), 0,
|
2007-12-14 12:24:20 +01:00
|
|
|
tree_key_length,
|
|
|
|
group_concat_key_cmp_with_order , 0, NULL, (void*) this);
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
2005-03-17 22:41:03 +01:00
|
|
|
|
2007-12-14 12:24:20 +01:00
|
|
|
if (distinct)
|
|
|
|
unique_filter= new Unique(group_concat_key_cmp_with_distinct,
|
|
|
|
(void*)this,
|
|
|
|
tree_key_length,
|
2009-10-01 13:33:30 +02:00
|
|
|
ram_limitation(thd));
|
2007-12-14 12:24:20 +01:00
|
|
|
|
2005-03-17 22:41:03 +01:00
|
|
|
DBUG_RETURN(FALSE);
|
2003-03-18 00:07:40 +01:00
|
|
|
}
|
|
|
|
|
2004-04-05 12:56:05 +02:00
|
|
|
|
2003-06-04 17:28:51 +02:00
|
|
|
/* This is used by rollup to create a separate usable copy of the function */
|
|
|
|
|
|
|
|
void Item_func_group_concat::make_unique()
|
|
|
|
{
|
2005-03-17 22:41:03 +01:00
|
|
|
tmp_table_param= 0;
|
2003-06-04 17:28:51 +02:00
|
|
|
table=0;
|
|
|
|
original= 0;
|
2006-03-29 21:30:34 +02:00
|
|
|
force_copy_fields= 1;
|
2005-03-17 22:41:03 +01:00
|
|
|
tree= 0;
|
2003-06-04 17:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-03-18 00:07:40 +01:00
|
|
|
String* Item_func_group_concat::val_str(String* str)
|
|
|
|
{
|
2004-03-18 14:14:36 +01:00
|
|
|
DBUG_ASSERT(fixed == 1);
|
2003-04-02 13:55:53 +02:00
|
|
|
if (null_value)
|
|
|
|
return 0;
|
2007-10-29 11:53:10 +01:00
|
|
|
if (no_appended && tree)
|
2007-05-11 15:05:20 +02:00
|
|
|
/* Tree is used for sorting as in ORDER BY */
|
2010-05-31 17:29:54 +02:00
|
|
|
tree_walk(tree, &dump_leaf_key, this, left_root_right);
|
2003-03-18 00:07:40 +01:00
|
|
|
return &result;
|
|
|
|
}
|
2003-10-12 16:56:05 +02:00
|
|
|
|
2003-11-20 21:06:25 +01:00
|
|
|
|
2008-02-22 11:30:33 +01:00
|
|
|
void Item_func_group_concat::print(String *str, enum_query_type query_type)
|
2003-10-12 16:56:05 +02:00
|
|
|
{
|
2010-02-19 16:16:43 +01:00
|
|
|
/* orig_args is not filled with valid values until fix_fields() */
|
|
|
|
Item **pargs= fixed ? orig_args : args;
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN("group_concat("));
|
2003-10-12 16:56:05 +02:00
|
|
|
if (distinct)
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN("distinct "));
|
2004-04-05 12:56:05 +02:00
|
|
|
for (uint i= 0; i < arg_count_field; i++)
|
2003-10-12 16:56:05 +02:00
|
|
|
{
|
|
|
|
if (i)
|
|
|
|
str->append(',');
|
2010-02-19 20:06:47 +01:00
|
|
|
pargs[i]->print(str, query_type);
|
2003-10-12 16:56:05 +02:00
|
|
|
}
|
|
|
|
if (arg_count_order)
|
|
|
|
{
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN(" order by "));
|
2003-10-12 16:56:05 +02:00
|
|
|
for (uint i= 0 ; i < arg_count_order ; i++)
|
|
|
|
{
|
|
|
|
if (i)
|
2005-03-17 22:41:03 +01:00
|
|
|
str->append(',');
|
2010-03-31 15:00:56 +02:00
|
|
|
pargs[i + arg_count_field]->print(str, query_type);
|
2005-11-01 15:27:10 +01:00
|
|
|
if (order[i]->asc)
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN(" ASC"));
|
2005-11-01 15:27:10 +01:00
|
|
|
else
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN(" DESC"));
|
2003-10-12 16:56:05 +02:00
|
|
|
}
|
|
|
|
}
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN(" separator \'"));
|
2003-10-12 16:56:05 +02:00
|
|
|
str->append(*separator);
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN("\')"));
|
2003-10-12 16:56:05 +02:00
|
|
|
}
|
2007-12-14 12:24:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
Item_func_group_concat::~Item_func_group_concat()
|
|
|
|
{
|
2008-02-28 12:31:19 +01:00
|
|
|
if (!original && unique_filter)
|
2007-12-14 12:24:20 +01:00
|
|
|
delete unique_filter;
|
|
|
|
}
|