summaryrefslogtreecommitdiff
path: root/sql/item_sum.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r--sql/item_sum.cc624
1 files changed, 539 insertions, 85 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 269190ef3df..d4abdfc614f 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -30,6 +30,10 @@
#include "sql_priv.h"
#include "sql_select.h"
#include "uniques.h"
+#include "sp_rcontext.h"
+#include "sp.h"
+#include "sql_parse.h"
+#include "sp_head.h"
/**
Calculate the affordable RAM limit for structures like TREE or Unique
@@ -1126,7 +1130,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1))
return TRUE;
set_if_bigger(decimals, args[i]->decimals);
- with_subselect|= args[i]->with_subselect;
+ m_with_subquery|= args[i]->with_subquery();
with_window_func|= args[i]->with_window_func;
}
result_field=0;
@@ -1146,18 +1150,20 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
bool
Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
{
+ DBUG_ENTER("Item_sum_hybrid::fix_fields");
DBUG_ASSERT(fixed == 0);
Item *item= args[0];
if (init_sum_func_check(thd))
- return TRUE;
+ DBUG_RETURN(TRUE);
// 'item' can be changed during fix_fields
if ((!item->fixed && item->fix_fields(thd, args)) ||
(item= args[0])->check_cols(1))
- return TRUE;
- with_subselect= args[0]->with_subselect;
+ DBUG_RETURN(TRUE);
+
+ m_with_subquery= args[0]->with_subquery();
with_window_func|= args[0]->with_window_func;
fix_length_and_dec();
@@ -1166,11 +1172,11 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
result_field=0;
if (check_sum_func(thd, ref))
- return TRUE;
+ DBUG_RETURN(TRUE);
orig_args[0]= args[0];
fixed= 1;
- return FALSE;
+ DBUG_RETURN(FALSE);
}
@@ -1201,15 +1207,16 @@ void Item_sum_hybrid::fix_length_and_dec()
void Item_sum_hybrid::setup_hybrid(THD *thd, Item *item, Item *value_arg)
{
+ DBUG_ENTER("Item_sum_hybrid::setup_hybrid");
if (!(value= item->get_cache(thd)))
- return;
+ DBUG_VOID_RETURN;
value->setup(thd, item);
value->store(value_arg);
/* Don't cache value, as it will change */
if (!item->const_item())
value->set_used_tables(RAND_TABLE_BIT);
if (!(arg_cache= item->get_cache(thd)))
- return;
+ DBUG_VOID_RETURN;
arg_cache->setup(thd, item);
/* Don't cache value, as it will change */
if (!item->const_item())
@@ -1217,23 +1224,178 @@ void Item_sum_hybrid::setup_hybrid(THD *thd, Item *item, Item *value_arg)
cmp= new Arg_comparator();
if (cmp)
cmp->set_cmp_func(this, (Item**)&arg_cache, (Item**)&value, FALSE);
+ DBUG_VOID_RETURN;
}
Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table)
{
+ DBUG_ENTER("Item_sum_hybrid::create_tmp_field");
+
if (args[0]->type() == Item::FIELD_ITEM)
{
Field *field= ((Item_field*) args[0])->field;
if ((field= create_tmp_field_from_field(table->in_use, field, &name,
table, NULL)))
field->flags&= ~NOT_NULL_FLAG;
- return field;
+ DBUG_RETURN(field);
}
- return tmp_table_field_from_field_type(table);
+ DBUG_RETURN(tmp_table_field_from_field_type(table));
+}
+
+/***********************************************************************
+** Item_sum_sp class
+***********************************************************************/
+
+Item_sum_sp::Item_sum_sp(THD *thd, Name_resolution_context *context_arg,
+ sp_name *name_arg, sp_head *sp, List<Item> &list)
+ :Item_sum(thd, list), Item_sp(thd, context_arg, name_arg)
+{
+ maybe_null= 1;
+ quick_group= 0;
+ m_sp= sp;
+}
+
+Item_sum_sp::Item_sum_sp(THD *thd, Name_resolution_context *context_arg,
+ sp_name *name_arg, sp_head *sp)
+ :Item_sum(thd), Item_sp(thd, context_arg, name_arg)
+{
+ maybe_null= 1;
+ quick_group= 0;
+ m_sp= sp;
}
+bool
+Item_sum_sp::fix_fields(THD *thd, Item **ref)
+{
+ DBUG_ASSERT(fixed == 0);
+ if (init_sum_func_check(thd))
+ return TRUE;
+ decimals= 0;
+
+ m_sp= m_sp ? m_sp : sp_handler_function.sp_find_routine(thd, m_name, true);
+
+ if (!m_sp)
+ {
+ my_missing_function_error(m_name->m_name, ErrConvDQName(m_name).ptr());
+ context->process_error(thd);
+ return TRUE;
+ }
+
+ if (init_result_field(thd, max_length, maybe_null, &null_value, &name))
+ return TRUE;
+
+ for (uint i= 0 ; i < arg_count ; i++)
+ {
+ if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1))
+ return TRUE;
+ set_if_bigger(decimals, args[i]->decimals);
+ m_with_subquery|= args[i]->with_subquery();
+ with_window_func|= args[i]->with_window_func;
+ }
+ result_field= NULL;
+ max_length= float_length(decimals);
+ null_value= 1;
+ fix_length_and_dec();
+
+ if (check_sum_func(thd, ref))
+ return TRUE;
+
+ memcpy(orig_args, args, sizeof(Item *) * arg_count);
+ fixed= 1;
+ return FALSE;
+}
+
+/**
+ Execute function to store value in result field.
+ This is called when we need the value to be returned for the function.
+ Here we send a signal in form of the server status that all rows have been
+ fetched and now we have to exit from the function with the return value.
+ @return Function returns error status.
+ @retval FALSE on success.
+ @retval TRUE if an error occurred.
+*/
+
+bool
+Item_sum_sp::execute()
+{
+ THD *thd= current_thd;
+ bool res;
+ uint old_server_status= thd->server_status;
+
+ /* We set server status so we can send a signal to exit from the
+ function with the return value. */
+
+ thd->server_status= SERVER_STATUS_LAST_ROW_SENT;
+ res= Item_sp::execute(thd, &null_value, args, arg_count);
+ thd->server_status= old_server_status;
+ return res;
+}
+
+/**
+ Handles the aggregation of the values.
+ @note: See class description for more details on how and why this is done.
+ @return The error state.
+ @retval FALSE on success.
+ @retval TRUE if an error occurred.
+*/
+
+bool
+Item_sum_sp::add()
+{
+ return execute_impl(current_thd, args, arg_count);
+}
+
+
+void
+Item_sum_sp::clear()
+{
+ delete func_ctx;
+ func_ctx= NULL;
+ sp_query_arena->free_items();
+ free_root(&sp_mem_root, MYF(0));
+}
+
+const Type_handler *Item_sum_sp::type_handler() const
+{
+ DBUG_ENTER("Item_sum_sp::type_handler");
+ DBUG_PRINT("info", ("m_sp = %p", (void *) m_sp));
+ DBUG_ASSERT(sp_result_field);
+ // This converts ENUM/SET to STRING
+ const Type_handler *handler= sp_result_field->type_handler();
+ DBUG_RETURN(handler->type_handler_for_item_field());
+}
+
+void
+Item_sum_sp::cleanup()
+{
+ Item_sp::cleanup();
+ Item_sum::cleanup();
+}
+
+/**
+ Initialize local members with values from the Field interface.
+ @note called from Item::fix_fields.
+*/
+
+void
+Item_sum_sp::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_sum_sp::fix_length_and_dec");
+ DBUG_ASSERT(sp_result_field);
+ Type_std_attributes::set(sp_result_field);
+ Item_sum::fix_length_and_dec();
+ DBUG_VOID_RETURN;
+}
+
+const char *
+Item_sum_sp::func_name() const
+{
+ THD *thd= current_thd;
+ return Item_sp::func_name(thd);
+}
+
/***********************************************************************
** reset and add of sum_func
***********************************************************************/
@@ -1245,6 +1407,7 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table)
Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item)
:Item_sum_num(thd, item),
Type_handler_hybrid_field_type(item),
+ direct_added(FALSE), direct_reseted_field(FALSE),
curr_dec_buff(item->curr_dec_buff),
count(item->count)
{
@@ -1264,6 +1427,15 @@ Item *Item_sum_sum::copy_or_same(THD* thd)
}
+void Item_sum_sum::cleanup()
+{
+ DBUG_ENTER("Item_sum_sum::cleanup");
+ direct_added= direct_reseted_field= FALSE;
+ Item_sum_num::cleanup();
+ DBUG_VOID_RETURN;
+}
+
+
void Item_sum_sum::clear()
{
DBUG_ENTER("Item_sum_sum::clear");
@@ -1313,6 +1485,38 @@ void Item_sum_sum::fix_length_and_dec()
}
+void Item_sum_sum::direct_add(my_decimal *add_sum_decimal)
+{
+ DBUG_ENTER("Item_sum_sum::direct_add");
+ DBUG_PRINT("info", ("add_sum_decimal: %p", add_sum_decimal));
+ direct_added= TRUE;
+ direct_reseted_field= FALSE;
+ if (add_sum_decimal)
+ {
+ direct_sum_is_null= FALSE;
+ direct_sum_decimal= *add_sum_decimal;
+ }
+ else
+ {
+ direct_sum_is_null= TRUE;
+ direct_sum_decimal= decimal_zero;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_sum_sum::direct_add(double add_sum_real, bool add_sum_is_null)
+{
+ DBUG_ENTER("Item_sum_sum::direct_add");
+ DBUG_PRINT("info", ("add_sum_real: %f", add_sum_real));
+ direct_added= TRUE;
+ direct_reseted_field= FALSE;
+ direct_sum_is_null= add_sum_is_null;
+ direct_sum_real= add_sum_real;
+ DBUG_VOID_RETURN;
+}
+
+
bool Item_sum_sum::add()
{
DBUG_ENTER("Item_sum_sum::add");
@@ -1326,50 +1530,84 @@ void Item_sum_sum::add_helper(bool perform_removal)
if (result_type() == DECIMAL_RESULT)
{
- my_decimal value;
- const my_decimal *val= aggr->arg_val_decimal(&value);
- if (!aggr->arg_is_null(true))
+ if (unlikely(direct_added))
{
- if (perform_removal)
+ /* Add value stored by Item_sum_sum::direct_add */
+ DBUG_ASSERT(!perform_removal);
+
+ direct_added= FALSE;
+ if (likely(!direct_sum_is_null))
{
- if (count > 0)
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
+ &direct_sum_decimal, dec_buffs + curr_dec_buff);
+ curr_dec_buff^= 1;
+ null_value= 0;
+ }
+ }
+ else
+ {
+ direct_reseted_field= FALSE;
+ my_decimal value;
+ const my_decimal *val= aggr->arg_val_decimal(&value);
+ if (!aggr->arg_is_null(true))
+ {
+ if (perform_removal)
{
- my_decimal_sub(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff ^ 1),
- dec_buffs + curr_dec_buff, val);
- count--;
+ if (count > 0)
+ {
+ my_decimal_sub(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff ^ 1),
+ dec_buffs + curr_dec_buff, val);
+ count--;
+ }
+ else
+ DBUG_VOID_RETURN;
}
else
- DBUG_VOID_RETURN;
- }
- else
- {
- count++;
- my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff ^ 1),
- val, dec_buffs + curr_dec_buff);
+ {
+ count++;
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff ^ 1),
+ val, dec_buffs + curr_dec_buff);
+ }
+ curr_dec_buff^= 1;
+ null_value= (count > 0) ? 0 : 1;
}
- curr_dec_buff^= 1;
- null_value= (count > 0) ? 0 : 1;
}
}
else
{
- if (perform_removal && count > 0)
- sum-= aggr->arg_val_real();
+ if (unlikely(direct_added))
+ {
+ /* Add value stored by Item_sum_sum::direct_add */
+ DBUG_ASSERT(!perform_removal);
+
+ direct_added= FALSE;
+ if (!direct_sum_is_null)
+ {
+ sum+= direct_sum_real;
+ null_value= 0;
+ }
+ }
else
- sum+= aggr->arg_val_real();
- if (!aggr->arg_is_null(true))
{
- if (perform_removal)
+ direct_reseted_field= FALSE;
+ if (perform_removal && count > 0)
+ sum-= aggr->arg_val_real();
+ else
+ sum+= aggr->arg_val_real();
+ if (!aggr->arg_is_null(true))
{
- if (count > 0)
+ if (perform_removal)
{
- count--;
+ if (count > 0)
+ {
+ count--;
+ }
}
- }
- else
- count++;
+ else
+ count++;
- null_value= (count > 0) ? 0 : 1;
+ null_value= (count > 0) ? 0 : 1;
+ }
}
}
DBUG_VOID_RETURN;
@@ -1556,22 +1794,46 @@ bool Aggregator_distinct::arg_is_null(bool use_null_value)
Item *Item_sum_count::copy_or_same(THD* thd)
{
- return new (thd->mem_root) Item_sum_count(thd, this);
+ DBUG_ENTER("Item_sum_count::copy_or_same");
+ DBUG_RETURN(new (thd->mem_root) Item_sum_count(thd, this));
+}
+
+
+void Item_sum_count::direct_add(longlong add_count)
+{
+ DBUG_ENTER("Item_sum_count::direct_add");
+ DBUG_PRINT("info", ("add_count: %lld", add_count));
+ direct_counted= TRUE;
+ direct_reseted_field= FALSE;
+ direct_count= add_count;
+ DBUG_VOID_RETURN;
}
void Item_sum_count::clear()
{
+ DBUG_ENTER("Item_sum_count::clear");
count= 0;
+ DBUG_VOID_RETURN;
}
bool Item_sum_count::add()
{
- if (aggr->arg_is_null(false))
- return 0;
- count++;
- return 0;
+ DBUG_ENTER("Item_sum_count::add");
+ if (direct_counted)
+ {
+ direct_counted= FALSE;
+ count+= direct_count;
+ }
+ else
+ {
+ direct_reseted_field= FALSE;
+ if (aggr->arg_is_null(false))
+ DBUG_RETURN(0);
+ count++;
+ }
+ DBUG_RETURN(0);
}
@@ -1590,10 +1852,11 @@ void Item_sum_count::remove()
longlong Item_sum_count::val_int()
{
+ DBUG_ENTER("Item_sum_count::val_int");
DBUG_ASSERT(fixed == 1);
if (aggr)
aggr->endup();
- return (longlong) count;
+ DBUG_RETURN((longlong)count);
}
@@ -1601,6 +1864,8 @@ void Item_sum_count::cleanup()
{
DBUG_ENTER("Item_sum_count::cleanup");
count= 0;
+ direct_counted= FALSE;
+ direct_reseted_field= FALSE;
Item_sum_int::cleanup();
DBUG_VOID_RETURN;
}
@@ -2015,10 +2280,13 @@ Item *Item_sum_variance::result_item(THD *thd, Field *field)
void Item_sum_hybrid::clear()
{
+ DBUG_ENTER("Item_sum_hybrid::clear");
value->clear();
null_value= 1;
+ DBUG_VOID_RETURN;
}
+
bool
Item_sum_hybrid::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
@@ -2031,51 +2299,66 @@ Item_sum_hybrid::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
return retval;
}
+
+void Item_sum_hybrid::direct_add(Item *item)
+{
+ DBUG_ENTER("Item_sum_hybrid::direct_add");
+ DBUG_PRINT("info", ("item: %p", item));
+ direct_added= TRUE;
+ direct_item= item;
+ DBUG_VOID_RETURN;
+}
+
+
double Item_sum_hybrid::val_real()
{
+ DBUG_ENTER("Item_sum_hybrid::val_real");
DBUG_ASSERT(fixed == 1);
if (null_value)
- return 0.0;
+ DBUG_RETURN(0.0);
double retval= value->val_real();
if ((null_value= value->null_value))
DBUG_ASSERT(retval == 0.0);
- return retval;
+ DBUG_RETURN(retval);
}
longlong Item_sum_hybrid::val_int()
{
+ DBUG_ENTER("Item_sum_hybrid::val_int");
DBUG_ASSERT(fixed == 1);
if (null_value)
- return 0;
+ DBUG_RETURN(0);
longlong retval= value->val_int();
if ((null_value= value->null_value))
DBUG_ASSERT(retval == 0);
- return retval;
+ DBUG_RETURN(retval);
}
my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val)
{
+ DBUG_ENTER("Item_sum_hybrid::val_decimal");
DBUG_ASSERT(fixed == 1);
if (null_value)
- return 0;
+ DBUG_RETURN(0);
my_decimal *retval= value->val_decimal(val);
if ((null_value= value->null_value))
DBUG_ASSERT(retval == NULL);
- return retval;
+ DBUG_RETURN(retval);
}
String *
Item_sum_hybrid::val_str(String *str)
{
+ DBUG_ENTER("Item_sum_hybrid::val_str");
DBUG_ASSERT(fixed == 1);
if (null_value)
- return 0;
+ DBUG_RETURN(0);
String *retval= value->val_str(str);
if ((null_value= value->null_value))
DBUG_ASSERT(retval == NULL);
- return retval;
+ DBUG_RETURN(retval);
}
@@ -2099,6 +2382,7 @@ void Item_sum_hybrid::cleanup()
void Item_sum_hybrid::no_rows_in_result()
{
+ DBUG_ENTER("Item_sum_hybrid::no_rows_in_result");
/* We may be called here twice in case of ref field in function */
if (was_values)
{
@@ -2106,6 +2390,7 @@ void Item_sum_hybrid::no_rows_in_result()
was_null_value= value->null_value;
clear();
}
+ DBUG_VOID_RETURN;
}
void Item_sum_hybrid::restore_to_before_no_rows_in_result()
@@ -2120,14 +2405,26 @@ void Item_sum_hybrid::restore_to_before_no_rows_in_result()
Item *Item_sum_min::copy_or_same(THD* thd)
{
+ DBUG_ENTER("Item_sum_min::copy_or_same");
Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this);
item->setup_hybrid(thd, args[0], value);
- return item;
+ DBUG_RETURN(item);
}
bool Item_sum_min::add()
{
+ Item *tmp_item;
+ DBUG_ENTER("Item_sum_min::add");
+ DBUG_PRINT("enter", ("this: %p", this));
+
+ if (unlikely(direct_added))
+ {
+ /* Change to use direct_item */
+ tmp_item= arg_cache->get_item();
+ arg_cache->store(direct_item);
+ }
+ DBUG_PRINT("info", ("null_value: %s", null_value ? "TRUE" : "FALSE"));
/* args[0] < value */
arg_cache->cache_value();
if (!arg_cache->null_value &&
@@ -2137,7 +2434,13 @@ bool Item_sum_min::add()
value->cache_value();
null_value= 0;
}
- return 0;
+ if (unlikely(direct_added))
+ {
+ /* Restore original item */
+ direct_added= FALSE;
+ arg_cache->store(tmp_item);
+ }
+ DBUG_RETURN(0);
}
@@ -2151,8 +2454,19 @@ Item *Item_sum_max::copy_or_same(THD* thd)
bool Item_sum_max::add()
{
+ Item *tmp_item;
+ DBUG_ENTER("Item_sum_max::add");
+ DBUG_PRINT("enter", ("this: %p", this));
+
+ if (unlikely(direct_added))
+ {
+ /* Change to use direct_item */
+ tmp_item= arg_cache->get_item();
+ arg_cache->store(direct_item);
+ }
/* args[0] > value */
arg_cache->cache_value();
+ DBUG_PRINT("info", ("null_value: %s", null_value ? "TRUE" : "FALSE"));
if (!arg_cache->null_value &&
(null_value || cmp->compare() > 0))
{
@@ -2160,7 +2474,13 @@ bool Item_sum_max::add()
value->cache_value();
null_value= 0;
}
- return 0;
+ if (unlikely(direct_added))
+ {
+ /* Restore original item */
+ direct_added= FALSE;
+ arg_cache->store(tmp_item);
+ }
+ DBUG_RETURN(0);
}
@@ -2339,14 +2659,26 @@ void Item_sum_num::reset_field()
void Item_sum_hybrid::reset_field()
{
+ Item *tmp_item, *arg0;
+ DBUG_ENTER("Item_sum_hybrid::reset_field");
+
+ arg0= args[0];
+ if (unlikely(direct_added))
+ {
+ /* Switch to use direct item */
+ tmp_item= value->get_item();
+ value->store(direct_item);
+ arg0= direct_item;
+ }
+
switch(result_type()) {
case STRING_RESULT:
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff),result_field->charset()),*res;
- res=args[0]->val_str(&tmp);
- if (args[0]->null_value)
+ res= arg0->val_str(&tmp);
+ if (arg0->null_value)
{
result_field->set_null();
result_field->reset();
@@ -2360,11 +2692,11 @@ void Item_sum_hybrid::reset_field()
}
case INT_RESULT:
{
- longlong nr=args[0]->val_int();
+ longlong nr= arg0->val_int();
if (maybe_null)
{
- if (args[0]->null_value)
+ if (arg0->null_value)
{
nr=0;
result_field->set_null();
@@ -2372,16 +2704,17 @@ void Item_sum_hybrid::reset_field()
else
result_field->set_notnull();
}
+ DBUG_PRINT("info", ("nr: %lld", nr));
result_field->store(nr, unsigned_flag);
break;
}
case REAL_RESULT:
{
- double nr= args[0]->val_real();
+ double nr= arg0->val_real();
if (maybe_null)
{
- if (args[0]->null_value)
+ if (arg0->null_value)
{
nr=0.0;
result_field->set_null();
@@ -2394,11 +2727,11 @@ void Item_sum_hybrid::reset_field()
}
case DECIMAL_RESULT:
{
- my_decimal value_buff, *arg_dec= args[0]->val_decimal(&value_buff);
+ my_decimal value_buff, *arg_dec= arg0->val_decimal(&value_buff);
if (maybe_null)
{
- if (args[0]->null_value)
+ if (arg0->null_value)
result_field->set_null();
else
result_field->set_notnull();
@@ -2416,26 +2749,49 @@ void Item_sum_hybrid::reset_field()
case TIME_RESULT:
DBUG_ASSERT(0);
}
+
+ if (unlikely(direct_added))
+ {
+ direct_added= FALSE;
+ value->store(tmp_item);
+ }
+ DBUG_VOID_RETURN;
}
void Item_sum_sum::reset_field()
{
+ my_bool null_flag;
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
if (result_type() == DECIMAL_RESULT)
{
- my_decimal value, *arg_val= args[0]->val_decimal(&value);
- if (!arg_val) // Null
- arg_val= &decimal_zero;
+ my_decimal value, *arg_val;
+ if (unlikely(direct_added))
+ arg_val= &direct_sum_decimal;
+ else
+ {
+ if (!(arg_val= args[0]->val_decimal(&value)))
+ arg_val= &decimal_zero; // Null
+ }
result_field->store_decimal(arg_val);
}
else
{
DBUG_ASSERT(result_type() == REAL_RESULT);
- double nr= args[0]->val_real(); // Nulls also return 0
+ double nr= likely(!direct_added) ? args[0]->val_real() : direct_sum_real;
float8store(result_field->ptr, nr);
}
- if (args[0]->null_value)
+
+ if (unlikely(direct_added))
+ {
+ direct_added= FALSE;
+ direct_reseted_field= TRUE;
+ null_flag= direct_sum_is_null;
+ }
+ else
+ null_flag= args[0]->null_value;
+
+ if (null_flag)
result_field->set_null();
else
result_field->set_notnull();
@@ -2444,13 +2800,22 @@ void Item_sum_sum::reset_field()
void Item_sum_count::reset_field()
{
+ DBUG_ENTER("Item_sum_count::reset_field");
uchar *res=result_field->ptr;
longlong nr=0;
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
- if (!args[0]->maybe_null || !args[0]->is_null())
- nr=1;
+ if (unlikely(direct_counted))
+ {
+ nr= direct_count;
+ direct_counted= FALSE;
+ direct_reseted_field= TRUE;
+ }
+ else if (!args[0]->maybe_null || !args[0]->is_null())
+ nr= 1;
+ DBUG_PRINT("info", ("nr: %lld", nr));
int8store(res,nr);
+ DBUG_VOID_RETURN;
}
@@ -2518,13 +2883,26 @@ void Item_sum_sum::update_field()
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
if (result_type() == DECIMAL_RESULT)
{
- my_decimal value, *arg_val= args[0]->val_decimal(&value);
- if (!args[0]->null_value)
+ my_decimal value, *arg_val;
+ my_bool null_flag;
+ if (unlikely(direct_added || direct_reseted_field))
+ {
+ direct_added= direct_reseted_field= FALSE;
+ arg_val= &direct_sum_decimal;
+ null_flag= direct_sum_is_null;
+ }
+ else
+ {
+ arg_val= args[0]->val_decimal(&value);
+ null_flag= args[0]->null_value;
+ }
+
+ if (!null_flag)
{
if (!result_field->is_null())
{
- my_decimal field_value,
- *field_val= result_field->val_decimal(&field_value);
+ my_decimal field_value;
+ my_decimal *field_val= result_field->val_decimal(&field_value);
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, field_val);
result_field->store_decimal(dec_buffs);
}
@@ -2538,11 +2916,22 @@ void Item_sum_sum::update_field()
else
{
double old_nr,nr;
- uchar *res=result_field->ptr;
+ uchar *res= result_field->ptr;
+ my_bool null_flag;
float8get(old_nr,res);
- nr= args[0]->val_real();
- if (!args[0]->null_value)
+ if (unlikely(direct_added || direct_reseted_field))
+ {
+ direct_added= direct_reseted_field= FALSE;
+ null_flag= direct_sum_is_null;
+ nr= direct_sum_real;
+ }
+ else
+ {
+ nr= args[0]->val_real();
+ null_flag= args[0]->null_value;
+ }
+ if (!null_flag)
{
old_nr+=nr;
result_field->set_notnull();
@@ -2554,13 +2943,21 @@ void Item_sum_sum::update_field()
void Item_sum_count::update_field()
{
+ DBUG_ENTER("Item_sum_count::update_field");
longlong nr;
uchar *res=result_field->ptr;
nr=sint8korr(res);
- if (!args[0]->maybe_null || !args[0]->is_null())
+ if (unlikely(direct_counted || direct_reseted_field))
+ {
+ direct_counted= direct_reseted_field= FALSE;
+ nr+= direct_count;
+ }
+ else if (!args[0]->maybe_null || !args[0]->is_null())
nr++;
+ DBUG_PRINT("info", ("nr: %lld", nr));
int8store(res,nr);
+ DBUG_VOID_RETURN;
}
@@ -2618,6 +3015,13 @@ Item *Item_sum_avg::result_item(THD *thd, Field *field)
void Item_sum_hybrid::update_field()
{
+ DBUG_ENTER("Item_sum_hybrid::update_field");
+ Item *tmp_item;
+ if (unlikely(direct_added))
+ {
+ tmp_item= args[0];
+ args[0]= direct_item;
+ }
switch (result_type()) {
case STRING_RESULT:
min_max_update_str_field();
@@ -2631,12 +3035,19 @@ void Item_sum_hybrid::update_field()
default:
min_max_update_real_field();
}
+ if (unlikely(direct_added))
+ {
+ direct_added= FALSE;
+ args[0]= tmp_item;
+ }
+ DBUG_VOID_RETURN;
}
void
Item_sum_hybrid::min_max_update_str_field()
{
+ DBUG_ENTER("Item_sum_hybrid::min_max_update_str_field");
DBUG_ASSERT(cmp);
String *res_str=args[0]->val_str(&cmp->value1);
@@ -2649,6 +3060,7 @@ Item_sum_hybrid::min_max_update_str_field()
result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
result_field->set_notnull();
}
+ DBUG_VOID_RETURN;
}
@@ -2657,6 +3069,7 @@ Item_sum_hybrid::min_max_update_real_field()
{
double nr,old_nr;
+ DBUG_ENTER("Item_sum_hybrid::min_max_update_real_field");
old_nr=result_field->val_real();
nr= args[0]->val_real();
if (!args[0]->null_value)
@@ -2669,6 +3082,7 @@ Item_sum_hybrid::min_max_update_real_field()
else if (result_field->is_null(0))
result_field->set_null();
result_field->store(old_nr);
+ DBUG_VOID_RETURN;
}
@@ -2677,6 +3091,7 @@ Item_sum_hybrid::min_max_update_int_field()
{
longlong nr,old_nr;
+ DBUG_ENTER("Item_sum_hybrid::min_max_update_int_field");
old_nr=result_field->val_int();
nr=args[0]->val_int();
if (!args[0]->null_value)
@@ -2696,7 +3111,9 @@ Item_sum_hybrid::min_max_update_int_field()
}
else if (result_field->is_null(0))
result_field->set_null();
+ DBUG_PRINT("info", ("nr: %lld", old_nr));
result_field->store(old_nr, unsigned_flag);
+ DBUG_VOID_RETURN;
}
@@ -2707,6 +3124,7 @@ Item_sum_hybrid::min_max_update_int_field()
void
Item_sum_hybrid::min_max_update_decimal_field()
{
+ DBUG_ENTER("Item_sum_hybrid::min_max_update_decimal_field");
my_decimal old_val, nr_val;
const my_decimal *old_nr;
const my_decimal *nr= args[0]->val_decimal(&nr_val);
@@ -2727,6 +3145,7 @@ Item_sum_hybrid::min_max_update_decimal_field()
}
else if (result_field->is_null(0))
result_field->set_null();
+ DBUG_VOID_RETURN;
}
@@ -2850,7 +3269,7 @@ double Item_sum_udf_float::val_real()
double res;
DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_sum_udf_float::val");
- DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ DBUG_PRINT("enter",("result_type: %d arg_count: %d",
args[0]->result_type(), arg_count));
res= udf.val(&tmp_null_value);
null_value= tmp_null_value;
@@ -2894,7 +3313,7 @@ my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf)
my_bool tmp_null_value;
DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_func_udf_decimal::val_decimal");
- DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ DBUG_PRINT("enter",("result_type: %d arg_count: %d",
args[0]->result_type(), arg_count));
res= udf.val_decimal(&tmp_null_value, dec_buf);
@@ -2920,7 +3339,7 @@ longlong Item_sum_udf_int::val_int()
longlong res;
DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_sum_udf_int::val_int");
- DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ DBUG_PRINT("enter",("result_type: %d arg_count: %d",
args[0]->result_type(), arg_count));
res= udf.val_int(&tmp_null_value);
null_value= tmp_null_value;
@@ -3114,6 +3533,11 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)),
Item **arg= item->args, **arg_end= item->args + item->arg_count_field;
uint old_length= result->length();
+ ulonglong *offset_limit= &item->copy_offset_limit;
+ ulonglong *row_limit = &item->copy_row_limit;
+ if (item->limit_clause && !(*row_limit))
+ return 1;
+
if (item->no_appended)
item->no_appended= FALSE;
else
@@ -3121,6 +3545,14 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)),
tmp.length(0);
+ if (item->limit_clause && (*offset_limit))
+ {
+ item->row_count++;
+ item->no_appended= TRUE;
+ (*offset_limit)--;
+ return 0;
+ }
+
for (; arg < arg_end; arg++)
{
String *res;
@@ -3150,6 +3582,8 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)),
result->append(*res);
}
+ if (item->limit_clause)
+ (*row_limit)--;
item->row_count++;
/* stop if length of result more than max_length */
@@ -3198,7 +3632,8 @@ Item_func_group_concat::
Item_func_group_concat(THD *thd, Name_resolution_context *context_arg,
bool distinct_arg, List<Item> *select_list,
const SQL_I_List<ORDER> &order_list,
- String *separator_arg)
+ String *separator_arg, bool limit_clause,
+ Item *row_limit_arg, Item *offset_limit_arg)
:Item_sum(thd), tmp_table_param(0), separator(separator_arg), tree(0),
unique_filter(NULL), table(0),
order(0), context(context_arg),
@@ -3207,7 +3642,9 @@ Item_func_group_concat(THD *thd, Name_resolution_context *context_arg,
row_count(0),
distinct(distinct_arg),
warning_for_row(FALSE),
- force_copy_fields(0), original(0)
+ force_copy_fields(0), row_limit(NULL),
+ offset_limit(NULL), limit_clause(limit_clause),
+ copy_offset_limit(0), copy_row_limit(0), original(0)
{
Item *item_select;
Item **arg_ptr;
@@ -3249,6 +3686,11 @@ Item_func_group_concat(THD *thd, Name_resolution_context *context_arg,
/* orig_args is only used for print() */
orig_args= (Item**) (order + arg_count_order);
memcpy(orig_args, args, sizeof(Item*) * arg_count);
+ if (limit_clause)
+ {
+ row_limit= row_limit_arg;
+ offset_limit= offset_limit_arg;
+ }
}
@@ -3268,7 +3710,9 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
warning_for_row(item->warning_for_row),
always_null(item->always_null),
force_copy_fields(item->force_copy_fields),
- original(item)
+ row_limit(item->row_limit), offset_limit(item->offset_limit),
+ limit_clause(item->limit_clause),copy_offset_limit(item->copy_offset_limit),
+ copy_row_limit(item->copy_row_limit), original(item)
{
quick_group= item->quick_group;
result.set_charset(collation.collation);
@@ -3363,6 +3807,10 @@ void Item_func_group_concat::clear()
null_value= TRUE;
warning_for_row= FALSE;
no_appended= TRUE;
+ if (offset_limit)
+ copy_offset_limit= offset_limit->val_int();
+ if (row_limit)
+ copy_row_limit= row_limit->val_int();
if (tree)
reset_tree(tree);
if (unique_filter)
@@ -3447,7 +3895,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
args[i]->fix_fields(thd, args + i)) ||
args[i]->check_cols(1))
return TRUE;
- with_subselect|= args[i]->with_subselect;
+ m_with_subquery|= args[i]->with_subquery();
with_window_func|= args[i]->with_window_func;
}
@@ -3617,6 +4065,12 @@ bool Item_func_group_concat::setup(THD *thd)
(void*)this,
tree_key_length,
ram_limitation(thd));
+ if ((row_limit && row_limit->cmp_type() != INT_RESULT) ||
+ (offset_limit && offset_limit->cmp_type() != INT_RESULT))
+ {
+ my_error(ER_INVALID_VALUE_TO_LIMIT, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
DBUG_RETURN(FALSE);
}