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