diff options
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r-- | sql/item_sum.cc | 313 |
1 files changed, 173 insertions, 140 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc index a381361e8a2..759a53c3c5e 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Sum functions (COUNT, MIN...) */ +/** + @file + + @brief + Sum functions (COUNT, MIN...) +*/ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -23,28 +28,25 @@ #include "mysql_priv.h" #include "sql_select.h" -/* - Prepare an aggregate function item for checking context conditions - - SYNOPSIS - init_sum_func_check() - thd reference to the thread context info +/** + Prepare an aggregate function item for checking context conditions. - DESCRIPTION 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. - NOTES + @param thd reference to the thread context info + + @note This function is to be called for any item created for a set function object when the traversal of trees built for expressions used in the query is performed at the phase of context analysis. This function is to be invoked at the descent of this traversal. - - RETURN - TRUE if an error is reported + @retval + TRUE if an error is reported + @retval FALSE otherwise */ @@ -70,15 +72,9 @@ bool Item_sum::init_sum_func_check(THD *thd) return FALSE; } -/* - Check constraints imposed on a usage of a set function - - SYNOPSIS - check_sum_func() - thd reference to the thread context info - ref location of the pointer to this item in the embedding expression +/** + Check constraints imposed on a usage of a set function. - DESCRIPTION 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 @@ -90,13 +86,6 @@ bool Item_sum::init_sum_func_check(THD *thd) adds it to the chain of items for such set functions that is attached to the the st_select_lex structure for this subquery. - NOTES - 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. - - IMPLEMENTATION 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. @@ -107,16 +96,28 @@ bool Item_sum::init_sum_func_check(THD *thd) of set functions are allowed (i.e either in the SELECT list or in the HAVING clause of the corresponding subquery) Consider the query: - 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); + @code + SELECT SUM(t1.b) FROM t1 GROUP BY t1.a + HAVING t1.a IN (SELECT t2.c FROM t2 WHERE AVG(t1.b) > 20) AND + t1.a > (SELECT MIN(t2.d) FROM t2); + @endcode allow_sum_func will contain: - for SUM(t1.b) - 1 at the first position - for AVG(t1.b) - 1 at the first position, 0 at the second position - for MIN(t2.d) - 1 at the first position, 1 at the second position. + - 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. - RETURN - TRUE if an error is reported + @retval + TRUE if an error is reported + @retval FALSE otherwise */ @@ -264,15 +265,9 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) return FALSE; } -/* - Attach a set function to the subquery where it must be aggregated +/** + Attach a set function to the subquery where it must be aggregated. - SYNOPSIS - register_sum_func() - thd reference to the thread context info - ref location of the pointer to this item in the embedding expression - - DESCRIPTION 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 @@ -280,14 +275,18 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) inner_sum_func_list defined for each subquery. When the item is placed there the field 'ref_by' is set to ref. - NOTES. + @note Now we 'register' only set functions that are aggregated in outer subqueries. Actually it makes sense to link all set function for a subquery in one chain. It would simplify the process of 'splitting' for set functions. - RETURN + @param thd reference to the thread context info + @param ref location of the pointer to this item in the embedding expression + + @retval FALSE if the executes without failures (currently always) + @retval TRUE otherwise */ @@ -379,8 +378,8 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements), } -/* - Constructor used in processing select with temporary tebles +/** + Constructor used in processing select with temporary tebles. */ Item_sum::Item_sum(THD *thd, Item_sum *item): @@ -438,7 +437,7 @@ void Item_sum::make_field(Send_field *tmp_field) } -void Item_sum::print(String *str) +void Item_sum::print(String *str, enum_query_type query_type) { /* orig_args is not filled with valid values until fix_fields() */ Item **pargs= fixed ? orig_args : args; @@ -447,7 +446,7 @@ void Item_sum::print(String *str) { if (i) str->append(','); - pargs[i]->print(str); + pargs[i]->print(str, query_type); } str->append(')'); } @@ -482,14 +481,15 @@ Item *Item_sum::get_tmp_table_item(THD *thd) } -bool Item_sum::walk (Item_processor processor, byte *argument) +bool Item_sum::walk (Item_processor processor, bool walk_subquery, + uchar *argument) { if (arg_count) { Item **arg,**arg_end; for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++) { - if ((*arg)->walk(processor, argument)) + if ((*arg)->walk(processor, walk_subquery, argument)) return 1; } } @@ -500,32 +500,35 @@ bool Item_sum::walk (Item_processor processor, byte *argument) Field *Item_sum::create_tmp_field(bool group, TABLE *table, uint convert_blob_length) { + Field *field; switch (result_type()) { case REAL_RESULT: - return new Field_double(max_length, maybe_null, name, table, decimals, - TRUE); + field= new Field_double(max_length, maybe_null, name, decimals, TRUE); + break; case INT_RESULT: - return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag); + field= new Field_longlong(max_length, maybe_null, name, unsigned_flag); + break; case STRING_RESULT: - /* - Make sure that the blob fits into a Field_varstring which has - 2-byte lenght. - */ - if (max_length/collation.collation->mbmaxlen > 255 && - convert_blob_length <= Field_varstring::MAX_SIZE && convert_blob_length) - return new Field_varstring(convert_blob_length, maybe_null, - name, table, - collation.collation); - return make_string_field(table); -case DECIMAL_RESULT: - return new Field_new_decimal(max_length, maybe_null, name, table, + if (max_length/collation.collation->mbmaxlen <= 255 || + convert_blob_length > Field_varstring::MAX_SIZE || + !convert_blob_length) + return make_string_field(table); + field= new Field_varstring(convert_blob_length, maybe_null, + name, table->s, collation.collation); + break; + case DECIMAL_RESULT: + field= new Field_new_decimal(max_length, maybe_null, name, decimals, unsigned_flag); + break; case ROW_RESULT: default: // This case should never be choosen DBUG_ASSERT(0); return 0; } + if (field) + field->init(table); + return field; } @@ -652,8 +655,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) return TRUE; // 'item' can be changed during fix_fields - if ((!item->fixed && - item->fix_fields(thd, args)) || + if ((!item->fixed && item->fix_fields(thd, args)) || (item= args[0])->check_cols(1)) return TRUE; decimals=item->decimals; @@ -702,9 +704,10 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table, uint convert_blob_length) { + Field *field; if (args[0]->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field*) args[0])->field; + field= ((Item_field*) args[0])->field; if ((field= create_tmp_field_from_field(current_thd, field, name, table, NULL, convert_blob_length))) @@ -718,16 +721,21 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table, */ switch (args[0]->field_type()) { case MYSQL_TYPE_DATE: - return new Field_newdate(maybe_null, name, table, collation.collation); + field= new Field_newdate(maybe_null, name, collation.collation); + break; case MYSQL_TYPE_TIME: - return new Field_time(maybe_null, name, table, collation.collation); + field= new Field_time(maybe_null, name, collation.collation); + break; case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATETIME: - return new Field_datetime(maybe_null, name, table, collation.collation); - default: + field= new Field_datetime(maybe_null, name, collation.collation); break; + default: + return Item_sum::create_tmp_field(group, table, convert_blob_length); } - return Item_sum::create_tmp_field(group, table, convert_blob_length); + if (field) + field->init(table); + return field; } @@ -735,6 +743,10 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table, ** reset and add of sum_func ***********************************************************************/ +/** + @todo + check if the following assignments are really needed +*/ Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item) :Item_sum_num(thd, item), hybrid_type(item->hybrid_type), curr_dec_buff(item->curr_dec_buff) @@ -885,7 +897,7 @@ static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2) static int item_sum_distinct_walk(void *element, element_count num_of_dups, void *item) { - return ((Item_sum_distinct*) (item))->unique_walk_function(element); + return ((Item_sum_distinct*) (item))->unique_walk_function(element); } C_MODE_END @@ -913,7 +925,7 @@ Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original) } -/* +/** Behaves like an Integer except to fix_length_and_dec(). Additionally div() converts val with this traits to a val with true decimal traits along with conversion of integer value to decimal value. @@ -970,7 +982,7 @@ void Item_sum_distinct::fix_length_and_dec() */ if (table_field_type == MYSQL_TYPE_INT24 || (table_field_type >= MYSQL_TYPE_TINY && - table_field_type <= MYSQL_TYPE_LONG)) + table_field_type <= MYSQL_TYPE_LONG)) { val.traits= Hybrid_type_traits_fast_decimal::instance(); break; @@ -990,10 +1002,14 @@ void Item_sum_distinct::fix_length_and_dec() } +/** + @todo + check that the case of CHAR(0) works OK +*/ bool Item_sum_distinct::setup(THD *thd) { - List<create_field> field_list; - create_field field_def; /* field definition */ + List<Create_field> field_list; + Create_field field_def; /* field definition */ DBUG_ENTER("Item_sum_distinct::setup"); /* It's legal to call setup() more than once when in a subquery */ if (tree) @@ -1239,6 +1255,7 @@ Item *Item_sum_avg::copy_or_same(THD* thd) Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, uint convert_blob_len) { + Field *field; if (group) { /* @@ -1246,14 +1263,18 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, The easiest way is to do this is to store both value in a string and unpack on access. */ - return new Field_string(((hybrid_type == DECIMAL_RESULT) ? + field= new Field_string(((hybrid_type == DECIMAL_RESULT) ? dec_bin_size : sizeof(double)) + sizeof(longlong), - 0, name, table, &my_charset_bin); + 0, name, &my_charset_bin); } - if (hybrid_type == DECIMAL_RESULT) - return new Field_new_decimal(max_length, maybe_null, name, table, + else if (hybrid_type == DECIMAL_RESULT) + field= new Field_new_decimal(max_length, maybe_null, name, decimals, unsigned_flag); - return new Field_double(max_length, maybe_null, name, table, decimals, TRUE); + else + field= new Field_double(max_length, maybe_null, name, decimals, TRUE); + if (field) + field->init(table); + return field; } @@ -1446,6 +1467,7 @@ Item *Item_sum_variance::copy_or_same(THD* thd) Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table, uint convert_blob_len) { + Field *field; if (group) { /* @@ -1453,9 +1475,15 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table, The easiest way is to do this is to store both value in a string and unpack on access. */ - return new Field_string(sizeof(double)*2 + sizeof(longlong), 0, name, table, &my_charset_bin); + field= new Field_string(sizeof(double)*2 + sizeof(longlong), 0, name, &my_charset_bin); } - return new Field_double(max_length, maybe_null, name, table, decimals, TRUE); + else + field= new Field_double(max_length, maybe_null, name, decimals, TRUE); + + if (field != NULL) + field->init(table); + + return field; } @@ -1512,7 +1540,7 @@ my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf) void Item_sum_variance::reset_field() { double nr; - char *res= result_field->ptr; + uchar *res= result_field->ptr; nr= args[0]->val_real(); /* sets null_value as side-effect */ @@ -1535,7 +1563,7 @@ void Item_sum_variance::reset_field() void Item_sum_variance::update_field() { ulonglong field_count; - char *res=result_field->ptr; + uchar *res=result_field->ptr; double nr= args[0]->val_real(); /* sets null_value as side-effect */ @@ -1666,16 +1694,13 @@ Item_sum_hybrid::val_str(String *str) case STRING_RESULT: return &value; case REAL_RESULT: - str->set(sum,decimals, &my_charset_bin); + str->set_real(sum,decimals, &my_charset_bin); break; case DECIMAL_RESULT: my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str); return str; case INT_RESULT: - if (unsigned_flag) - str->set((ulonglong) sum_int, &my_charset_bin); - else - str->set((longlong) sum_int, &my_charset_bin); + str->set_int(sum_int, unsigned_flag, &my_charset_bin); break; case ROW_RESULT: default: @@ -1902,7 +1927,7 @@ bool Item_sum_and::add() void Item_sum_num::reset_field() { double nr= args[0]->val_real(); - char *res=result_field->ptr; + uchar *res=result_field->ptr; if (maybe_null) { @@ -2024,7 +2049,7 @@ void Item_sum_sum::reset_field() void Item_sum_count::reset_field() { - char *res=result_field->ptr; + uchar *res=result_field->ptr; longlong nr=0; if (!args[0]->maybe_null || !args[0]->is_null()) @@ -2035,7 +2060,7 @@ void Item_sum_count::reset_field() void Item_sum_avg::reset_field() { - char *res=result_field->ptr; + uchar *res=result_field->ptr; if (hybrid_type == DECIMAL_RESULT) { longlong tmp; @@ -2076,15 +2101,15 @@ void Item_sum_bit::reset_field() void Item_sum_bit::update_field() { - char *res=result_field->ptr; + uchar *res=result_field->ptr; bits= uint8korr(res); add(); int8store(res, bits); } -/* -** calc next value and merge it with field_value +/** + calc next value and merge it with field_value. */ void Item_sum_sum::update_field() @@ -2111,7 +2136,7 @@ void Item_sum_sum::update_field() else { double old_nr,nr; - char *res=result_field->ptr; + uchar *res=result_field->ptr; float8get(old_nr,res); nr= args[0]->val_real(); @@ -2128,7 +2153,7 @@ void Item_sum_sum::update_field() void Item_sum_count::update_field() { longlong nr; - char *res=result_field->ptr; + uchar *res=result_field->ptr; nr=sint8korr(res); if (!args[0]->maybe_null || !args[0]->is_null()) @@ -2140,7 +2165,7 @@ void Item_sum_count::update_field() void Item_sum_avg::update_field() { longlong field_count; - char *res=result_field->ptr; + uchar *res=result_field->ptr; if (hybrid_type == DECIMAL_RESULT) { my_decimal value, *arg_val= args[0]->val_decimal(&value); @@ -2260,6 +2285,10 @@ Item_sum_hybrid::min_max_update_int_field() } +/** + @todo + optimize: do not get result_field in case of args[0] is NULL +*/ void Item_sum_hybrid::min_max_update_decimal_field() { @@ -2309,7 +2338,7 @@ double Item_avg_field::val_real() // fix_fields() never calls for this Item double nr; longlong count; - char *res; + uchar *res; if (hybrid_type == DECIMAL_RESULT) return val_real_from_decimal(); @@ -2442,20 +2471,20 @@ double Item_variance_field::val_real() ** COUNT(DISTINCT ...) ****************************************************************************/ -int simple_str_key_cmp(void* arg, byte* key1, byte* key2) +int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2) { Field *f= (Field*) arg; - return f->cmp((const char*)key1, (const char*)key2); + return f->cmp(key1, key2); } -/* +/** Did not make this one static - at least gcc gets confused when I try to declare a static function as a friend. If you can figure out the syntax to make a static function a friend, make this one static */ -int composite_key_cmp(void* arg, byte* key1, byte* key2) +int composite_key_cmp(void* arg, uchar* key1, uchar* key2) { Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg; Field **field = item->table->field; @@ -2465,7 +2494,7 @@ int composite_key_cmp(void* arg, byte* key1, byte* key2) { Field* f = *field; int len = *lengths++; - int res = f->cmp((char *) key1, (char *) key2); + int res = f->cmp(key1, key2); if (res) return res; key1 += len; @@ -2515,7 +2544,10 @@ void Item_sum_count_distinct::cleanup() } -/* This is used by rollup to create a separate usable copy of the function */ +/** + This is used by rollup to create a separate usable copy of + the function. +*/ void Item_sum_count_distinct::make_unique() { @@ -2590,7 +2622,7 @@ bool Item_sum_count_distinct::setup(THD *thd) table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows table->no_rows=1; - if (table->s->db_type == DB_TYPE_HEAP) + if (table->s->db_type() == heap_hton) { /* No blobs, otherwise it would have been MyISAM: set up a compare @@ -2682,7 +2714,7 @@ void Item_sum_count_distinct::clear() else if (table) { table->file->extra(HA_EXTRA_NO_CACHE); - table->file->delete_all_rows(); + table->file->ha_delete_all_rows(); table->file->extra(HA_EXTRA_WRITE_CACHE); } } @@ -2710,9 +2742,8 @@ bool Item_sum_count_distinct::add() */ return tree->unique_add(table->record[0] + table->s->null_bytes); } - if ((error= table->file->write_row(table->record[0])) && - error != HA_ERR_FOUND_DUPP_KEY && - error != HA_ERR_FOUND_DUPP_UNIQUE) + if ((error= table->file->ha_write_row(table->record[0])) && + table->file->is_fatal_error(error, HA_CHECK_DUP)) return TRUE; return FALSE; } @@ -2744,7 +2775,7 @@ longlong Item_sum_count_distinct::val_int() table->file->print_error(error, MYF(0)); } - return table->file->records; + return table->file->stats.records; } @@ -2782,7 +2813,7 @@ void Item_udf_sum::cleanup() } -void Item_udf_sum::print(String *str) +void Item_udf_sum::print(String *str, enum_query_type query_type) { str->append(func_name()); str->append('('); @@ -2790,7 +2821,7 @@ void Item_udf_sum::print(String *str) { if (i) str->append(','); - args[i]->print(str); + args[i]->print(str, query_type); } str->append(')'); } @@ -2884,7 +2915,7 @@ my_decimal *Item_sum_udf_int::val_decimal(my_decimal *dec) } -/* Default max_length is max argument length */ +/** Default max_length is max argument length. */ void Item_sum_udf_str::fix_length_and_dec() { @@ -2971,17 +3002,16 @@ int group_concat_key_cmp_with_distinct(void* arg, const void* key1, */ Field *field= item->get_tmp_table_field(); int res; - uint offset= field->offset()-table->s->null_bytes; - if((res= field->cmp((char*)key1 + offset, (char*)key2 + offset))) + uint offset= field->offset(field->table->record[0])-table->s->null_bytes; + if((res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset))) return res; } return 0; } -/* - function of sort for syntax: - GROUP_CONCAT(expr,... ORDER BY col,... ) +/** + function of sort for syntax: GROUP_CONCAT(expr,... ORDER BY col,... ) */ int group_concat_key_cmp_with_order(void* arg, const void* key1, @@ -3009,8 +3039,9 @@ int group_concat_key_cmp_with_order(void* arg, const void* key1, if (field && !item->const_item()) { int res; - uint offset= field->offset() - table->s->null_bytes; - if ((res= field->cmp((char *) key1 + offset, (char *) key2 + offset))) + uint offset= (field->offset(field->table->record[0]) - + table->s->null_bytes); + if ((res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset))) return (*order_item)->asc ? res : -res; } } @@ -3023,11 +3054,11 @@ int group_concat_key_cmp_with_order(void* arg, const void* key1, } -/* - Append data from current leaf to item->result +/** + Append data from current leaf to item->result. */ -int dump_leaf_key(byte* key, element_count count __attribute__((unused)), +int dump_leaf_key(uchar* key, element_count count __attribute__((unused)), Item_func_group_concat *item) { TABLE *table= item->table; @@ -3058,9 +3089,10 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)), because it contains both order and arg list fields. */ Field *field= (*arg)->get_tmp_table_field(); - uint offset= field->offset() - table->s->null_bytes; + uint offset= (field->offset(field->table->record[0]) - + table->s->null_bytes); DBUG_ASSERT(offset < table->s->reclength); - res= field->val_str(&tmp, (char *) key + offset); + res= field->val_str(&tmp, key + offset); } else res= (*arg)->val_str(&tmp); @@ -3094,12 +3126,13 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)), } -/* - Constructor of Item_func_group_concat - distinct_arg - distinct - select_list - list of expression for show values - order_list - list of sort columns - separator_arg - string value of separator +/** + Constructor of Item_func_group_concat. + + @param distinct_arg distinct + @param select_list list of expression for show values + @param order_list list of sort columns + @param separator_arg string value of separator. */ Item_func_group_concat:: @@ -3350,7 +3383,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) char *buf; String *new_separator; - if (!(buf= thd->stmt_arena->alloc(buflen)) || + if (!(buf= (char*) thd->stmt_arena->alloc(buflen)) || !(new_separator= new(thd->stmt_arena->mem_root) String(buf, buflen, collation.collation))) return TRUE; @@ -3531,7 +3564,7 @@ String* Item_func_group_concat::val_str(String* str) } -void Item_func_group_concat::print(String *str) +void Item_func_group_concat::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("group_concat(")); if (distinct) @@ -3540,7 +3573,7 @@ void Item_func_group_concat::print(String *str) { if (i) str->append(','); - args[i]->print(str); + args[i]->print(str, query_type); } if (arg_count_order) { @@ -3549,7 +3582,7 @@ void Item_func_group_concat::print(String *str) { if (i) str->append(','); - (*order[i]->item)->print(str); + (*order[i]->item)->print(str, query_type); if (order[i]->asc) str->append(STRING_WITH_LEN(" ASC")); else |