From: Georgi Kodinov Date: May 25 2009 8:03am Subject: bzr commit into mysql-5.1-bugteam branch (joro:2908) Bug#44399 List-Archive: http://lists.mysql.com/commits/74870 X-Bug: 44399 Message-Id: <200905250803.n4P83wGc006406@magare.gmz> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============8479258891484057993==" --===============8479258891484057993== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/kgeorge/mysql/work/B44399-5.1-bugteam/ based on revid:davi.arnaut@stripped 2908 Georgi Kodinov 2009-05-25 Bug #44399 : crash with statement using TEXT columns, aggregates, GROUP BY, and HAVING When calculating GROUP BY the server caches some expressions. It does that by allocating a string slot (Item_copy_string) and assigning the value of the expression to it. This effectively means that the result type of the expression can be changed from whatever it was to a string. As this substitution takes place after the compile-time result type calculation for IN but before the run-time type calculations, it causes the type calculations in the IN function done at run time to get unexpected results different from what was prepared at compile time. In the CASE ... WHEN ... THEN ... statement there was a similar problem and it was solved by artificially adding a STRING argument to the set of types of the IN/CASE arguments at compile time, so if any of the arguments of the CASE function changes its type to a string it will still be covered by the information prepared at compile time. @ mysql-test/include/mix1.inc Bug #44399: extended the test to cover the different types @ mysql-test/r/func_in.result Bug #44399: test case @ mysql-test/r/innodb_mysql.result Bug #44399: extended the test to cover the different types @ mysql-test/t/func_in.test Bug #44399: test case @ sql/item.cc Bug #44399: Implement typed caching for GROUP BY @ sql/item.h Bug #44399: Implement typed caching for GROUP BY @ sql/item_cmpfunc.cc Bug #44399: remove the special case @ sql/sql_select.cc Bug #44399: Implement typed caching for GROUP BY modified: mysql-test/include/mix1.inc mysql-test/r/func_in.result mysql-test/r/innodb_mysql.result mysql-test/t/func_in.test sql/item.cc sql/item.h sql/item_cmpfunc.cc sql/sql_select.cc === modified file 'mysql-test/include/mix1.inc' --- a/mysql-test/include/mix1.inc 2009-05-19 06:48:04 +0000 +++ b/mysql-test/include/mix1.inc 2009-05-25 08:00:40 +0000 @@ -1544,4 +1544,31 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) DROP TABLE t1; +eval +CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3)) + ENGINE=$engine_type; +INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2); + +SELECT 1 FROM (SELECT COUNT(DISTINCT c1) + FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; +EXPLAIN +SELECT 1 FROM (SELECT COUNT(DISTINCT c1) + FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; + +DROP TABLE t1; + +eval +CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2), + KEY (c3), KEY (c2, c3)) + ENGINE=$engine_type; +INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2); + +SELECT 1 FROM (SELECT COUNT(DISTINCT c1) + FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; +EXPLAIN +SELECT 1 FROM (SELECT COUNT(DISTINCT c1) + FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; + +DROP TABLE t1; + --echo End of 5.1 tests === modified file 'mysql-test/r/func_in.result' --- a/mysql-test/r/func_in.result 2009-05-20 11:14:33 +0000 +++ b/mysql-test/r/func_in.result 2009-05-25 08:00:40 +0000 @@ -587,4 +587,25 @@ SELECT CASE c1 WHEN c1 + 1 THEN 1 END, A CASE c1 WHEN c1 + 1 THEN 1 END ABS(AVG(c0)) NULL 1.0000 DROP TABLE t1; +CREATE TABLE t1(a TEXT, b INT, c INT UNSIGNED, d DECIMAL(12,2), e REAL); +INSERT INTO t1 VALUES('iynfj', 1, 1, 1, 1); +INSERT INTO t1 VALUES('innfj', 2, 2, 2, 2); +SELECT SUM( DISTINCT a ) FROM t1 GROUP BY a HAVING a IN ( AVG( 1 ), 1 + a); +SUM( DISTINCT a ) +SELECT SUM( DISTINCT b ) FROM t1 GROUP BY b HAVING b IN ( AVG( 1 ), 1 + b); +SUM( DISTINCT b ) +1 +SELECT SUM( DISTINCT c ) FROM t1 GROUP BY c HAVING c IN ( AVG( 1 ), 1 + c); +SUM( DISTINCT c ) +1 +SELECT SUM( DISTINCT d ) FROM t1 GROUP BY d HAVING d IN ( AVG( 1 ), 1 + d); +SUM( DISTINCT d ) +1.00 +SELECT SUM( DISTINCT e ) FROM t1 GROUP BY e HAVING e IN ( AVG( 1 ), 1 + e); +SUM( DISTINCT e ) +1 +SELECT SUM( DISTINCT e ) FROM t1 GROUP BY b,c,d HAVING (b,c,d) IN +((AVG( 1 ), 1 + c, 1 + d), (AVG( 1 ), 2 + c, 2 + d)); +SUM( DISTINCT e ) +DROP TABLE t1; End of 5.1 tests === modified file 'mysql-test/r/innodb_mysql.result' --- a/mysql-test/r/innodb_mysql.result 2009-05-19 06:48:04 +0000 +++ b/mysql-test/r/innodb_mysql.result 2009-05-25 08:00:40 +0000 @@ -1718,6 +1718,35 @@ id select_type table type possible_keys 1 PRIMARY system NULL NULL NULL NULL 1 2 DERIVED t1 index c3,c2 c2 10 NULL 5 DROP TABLE t1; +CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3)) +ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2); +SELECT 1 FROM (SELECT COUNT(DISTINCT c1) +FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; +1 +1 +EXPLAIN +SELECT 1 FROM (SELECT COUNT(DISTINCT c1) +FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY system NULL NULL NULL NULL 1 +2 DERIVED t1 index c3,c2 c2 18 NULL 5 +DROP TABLE t1; +CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2), +KEY (c3), KEY (c2, c3)) +ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2); +SELECT 1 FROM (SELECT COUNT(DISTINCT c1) +FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; +1 +1 +EXPLAIN +SELECT 1 FROM (SELECT COUNT(DISTINCT c1) +FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY system NULL NULL NULL NULL 1 +2 DERIVED t1 index c3,c2 c2 14 NULL 5 +DROP TABLE t1; End of 5.1 tests drop table if exists t1, t2, t3; create table t1(a int); === modified file 'mysql-test/t/func_in.test' --- a/mysql-test/t/func_in.test 2009-05-20 11:14:33 +0000 +++ b/mysql-test/t/func_in.test 2009-05-25 08:00:40 +0000 @@ -439,4 +439,21 @@ SELECT CASE c1 WHEN c1 + 1 THEN 1 END, A DROP TABLE t1; +# +# Bug #44399: crash with statement using TEXT columns, aggregates, GROUP BY, +# and HAVING +# + +CREATE TABLE t1(a TEXT, b INT, c INT UNSIGNED, d DECIMAL(12,2), e REAL); +INSERT INTO t1 VALUES('iynfj', 1, 1, 1, 1); +INSERT INTO t1 VALUES('innfj', 2, 2, 2, 2); +SELECT SUM( DISTINCT a ) FROM t1 GROUP BY a HAVING a IN ( AVG( 1 ), 1 + a); +SELECT SUM( DISTINCT b ) FROM t1 GROUP BY b HAVING b IN ( AVG( 1 ), 1 + b); +SELECT SUM( DISTINCT c ) FROM t1 GROUP BY c HAVING c IN ( AVG( 1 ), 1 + c); +SELECT SUM( DISTINCT d ) FROM t1 GROUP BY d HAVING d IN ( AVG( 1 ), 1 + d); +SELECT SUM( DISTINCT e ) FROM t1 GROUP BY e HAVING e IN ( AVG( 1 ), 1 + e); +SELECT SUM( DISTINCT e ) FROM t1 GROUP BY b,c,d HAVING (b,c,d) IN + ((AVG( 1 ), 1 + c, 1 + d), (AVG( 1 ), 2 + c, 2 + d)); +DROP TABLE t1; + --echo End of 5.1 tests === modified file 'sql/item.cc' --- a/sql/item.cc 2009-05-21 20:22:46 +0000 +++ b/sql/item.cc 2009-05-25 08:00:40 +0000 @@ -3269,9 +3269,57 @@ Item_param::set_param_type_and_swap_valu } /**************************************************************************** + Item_copy +****************************************************************************/ +Item_copy *Item_copy::create (Item *item) +{ + switch (item->result_type()) + { + case STRING_RESULT: + return new Item_copy_string (item); + case REAL_RESULT: + return new Item_copy_float (item); + case INT_RESULT: + return item->unsigned_flag ? + new Item_copy_uint (item) : new Item_copy_int (item); + case DECIMAL_RESULT: + return new Item_copy_decimal (item); + + case ROW_RESULT: + DBUG_ASSERT (0); + } + /* should not happen */ + return NULL; +} + +/**************************************************************************** Item_copy_string ****************************************************************************/ +double Item_copy_string::val_real() +{ + int err_not_used; + char *end_not_used; + return (null_value ? 0.0 : + my_strntod(str_value.charset(), (char*) str_value.ptr(), + str_value.length(), &end_not_used, &err_not_used)); +} + +longlong Item_copy_string::val_int() +{ + int err; + return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(), + str_value.length(),10, (char**) 0, + &err); +} + + +int Item_copy_string::save_in_field(Field *field, bool no_conversions) +{ + return save_str_value_in_field(field, &str_value); +} + + void Item_copy_string::copy() { String *res=item->val_str(&str_value); @@ -3294,12 +3342,163 @@ my_decimal *Item_copy_string::val_decima { // Item_copy_string is used without fix_fields call if (null_value) - return 0; + return (my_decimal *) 0; string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value); return (decimal_value); } +/**************************************************************************** + Item_copy_int +****************************************************************************/ + +void Item_copy_int::copy() +{ + cached_value= item->val_int(); + null_value=item->null_value; +} + +static int save_int_value_in_field (Field *field, longlong nr, + bool null_value, bool unsigned_flag); + +int Item_copy_int::save_in_field(Field *field, bool no_conversions) +{ + return save_int_value_in_field(field, cached_value, + null_value, unsigned_flag); +} + + +String *Item_copy_int::val_str(String *str) +{ + if (null_value) + return (String *) 0; + + str->set(cached_value, &my_charset_bin); + return str; +} + + +my_decimal *Item_copy_int::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return (my_decimal *) 0; + + int2my_decimal(E_DEC_FATAL_ERROR, cached_value, unsigned_flag, decimal_value); + return decimal_value; +} + + +/**************************************************************************** + Item_copy_uint +****************************************************************************/ + +String *Item_copy_uint::val_str(String *str) +{ + if (null_value) + return (String *) 0; + + str->set((ulonglong) cached_value, &my_charset_bin); + return str; +} + + +/**************************************************************************** + Item_copy_float +****************************************************************************/ + +String *Item_copy_float::val_str(String *str) +{ + if (null_value) + return (String *) 0; + else + { + double nr= val_real(); + str->set_real(nr,decimals, &my_charset_bin); + return str; + } +} + + +my_decimal *Item_copy_float::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return (my_decimal *) 0; + else + { + double nr= val_real(); + double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value); + return decimal_value; + } +} + + +int Item_copy_float::save_in_field(Field *field, bool no_conversions) +{ + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + return field->store(cached_value); +} + + +/**************************************************************************** + Item_copy_decimal +****************************************************************************/ + +int Item_copy_decimal::save_in_field(Field *field, bool no_conversions) +{ + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + return field->store_decimal(&cached_value); +} + + +String *Item_copy_decimal::val_str(String *result) +{ + if (null_value) + return (String *) 0; + result->set_charset(&my_charset_bin); + my_decimal2string(E_DEC_FATAL_ERROR, &cached_value, 0, 0, 0, result); + return result; +} + + +double Item_copy_decimal::val_real() +{ + if (null_value) + return 0.0; + else + { + double result; + my_decimal2double(E_DEC_FATAL_ERROR, &cached_value, &result); + return result; + } +} + + +longlong Item_copy_decimal::val_int() +{ + if (null_value) + return LL(0); + else + { + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, &cached_value, unsigned_flag, &result); + return result; + } +} + + +void Item_copy_decimal::copy() +{ + my_decimal *nr= item->val_decimal(&cached_value); + if (nr && nr != &cached_value) + memcpy (&cached_value, nr, sizeof (my_decimal)); + null_value= item->null_value; +} + + /* Functions to convert item to field (for send_fields) */ @@ -4947,10 +5146,9 @@ int Item_uint::save_in_field(Field *fiel return Item_int::save_in_field(field, no_conversions); } - -int Item_int::save_in_field(Field *field, bool no_conversions) +static int save_int_value_in_field (Field *field, longlong nr, + bool null_value, bool unsigned_flag) { - longlong nr=val_int(); if (null_value) return set_field_to_null(field); field->set_notnull(); @@ -4958,6 +5156,12 @@ int Item_int::save_in_field(Field *field } +int Item_int::save_in_field(Field *field, bool no_conversions) +{ + return save_int_value_in_field (field, val_int(), null_value, unsigned_flag); +} + + int Item_decimal::save_in_field(Field *field, bool no_conversions) { field->set_notnull(); === modified file 'sql/item.h' --- a/sql/item.h 2009-04-01 11:10:03 +0000 +++ b/sql/item.h 2009-05-25 08:00:40 +0000 @@ -2443,48 +2443,203 @@ public: #include "item_xmlfunc.h" #endif -class Item_copy_string :public Item +/** + Base class to implement typed value caching Item classes + + Item_copy_ classes are very similar to the corresponding Item_ + classes (e.g. Item_copy_int is similar to Item_int) but they add + the following additional functionality to Item_ : + 1. Nullability + 2. Possibility to store the value not only on instantiation time, + but also later. + Item_copy_ classes are a functionality subset of Item_cache_ + classes, as e.g. they don't support comparisons with the original Item + as Item_cache_ classes do. + Item_copy_ classes are used in GROUP BY calculation. + TODO: Item_copy should be made an abstract interface and Item_copy_ + classes should inherit both the respective Item_ class and the interface. + Ideally we should drop Item_copy_ classes altogether and merge + their functionality to Item_cache_ (and these should be made to inherit + from Item_). +*/ + +class Item_copy :public Item { +protected: + + /** + Stores the type of the resulting field that would be used to store the data + in the cache. This is to avoid calls to the original item. + */ enum enum_field_types cached_field_type; -public: + + /** The original item that is copied */ Item *item; - Item_copy_string(Item *i) :item(i) + + /** + Stores the result type of the original item, so it can be returned + without calling the original item's method + */ + Item_result cached_result_type; + + /** + Constructor of the Item_copy class + + stores metadata information about the original class as well as a + pointer to it. + */ + Item_copy(Item *i) { + item= i; null_value=maybe_null=item->maybe_null; decimals=item->decimals; max_length=item->max_length; name=item->name; cached_field_type= item->field_type(); + cached_result_type= item->result_type(); + unsigned_flag= item->unsigned_flag; } + +public: + /** + Factory method to create the appropriate subclass dependent on the type of + the original item. + + @param item the original item. + */ + static Item_copy *create (Item *item); + + /** + Update the cache with the value of the original item + + This is the method that updates the cached value. + It must be explicitly called by the user of this class to store the value + of the orginal item in the cache. + */ + virtual void copy() = 0; + + Item *get_item() { return item; } + /** All of the subclasses should have the same type tag */ enum Type type() const { return COPY_STR_ITEM; } - enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return cached_field_type; } - double val_real() + enum Item_result result_type () const { return cached_result_type; } + + void make_field(Send_field *field) { item->make_field(field); } + table_map used_tables() const { return (table_map) 1L; } + bool const_item() const { return 0; } + bool is_null() { return null_value; } + + /* + Override the methods below as pure virtual to make sure all the + sub-classes implement them. + */ + + virtual String *val_str(String*) = 0; + virtual my_decimal *val_decimal(my_decimal *) = 0; + virtual double val_real() = 0; + virtual longlong val_int() = 0; + virtual int save_in_field(Field *field, bool no_conversions) = 0; +}; + +/** + Implementation of a string cache. + + Uses Item::str_value for storage +*/ +class Item_copy_string : public Item_copy +{ +public: + Item_copy_string (Item *item) : Item_copy(item) {} + + String *val_str(String*); + my_decimal *val_decimal(my_decimal *); + double val_real(); + longlong val_int(); + void copy(); + int save_in_field(Field *field, bool no_conversions); +}; + + +class Item_copy_int : public Item_copy +{ +protected: + longlong cached_value; +public: + Item_copy_int (Item *i) : Item_copy(i) {} + int save_in_field(Field *field, bool no_conversions); + + virtual String *val_str(String*); + virtual my_decimal *val_decimal(my_decimal *); + virtual double val_real() { - int err_not_used; - char *end_not_used; - return (null_value ? 0.0 : - my_strntod(str_value.charset(), (char*) str_value.ptr(), - str_value.length(), &end_not_used, &err_not_used)); + return null_value ? 0.0 : (double) cached_value; } - longlong val_int() + virtual longlong val_int() + { + return null_value ? LL(0) : cached_value; + } + virtual void copy(); +}; + + +class Item_copy_uint : public Item_copy_int +{ +public: + Item_copy_uint (Item *item) : Item_copy_int(item) + { + unsigned_flag= 1; + } + + String *val_str(String*); + double val_real() { - int err; - return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(), - str_value.length(),10, (char**) 0, - &err); + return null_value ? 0.0 : (double) (ulonglong) cached_value; } +}; + + +class Item_copy_float : public Item_copy +{ +protected: + double cached_value; +public: + Item_copy_float (Item *i) : Item_copy(i) {} + int save_in_field(Field *field, bool no_conversions); + String *val_str(String*); my_decimal *val_decimal(my_decimal *); - void make_field(Send_field *field) { item->make_field(field); } - void copy(); - int save_in_field(Field *field, bool no_conversions) + double val_real() { - return save_str_value_in_field(field, &str_value); + return null_value ? 0.0 : cached_value; } - table_map used_tables() const { return (table_map) 1L; } - bool const_item() const { return 0; } - bool is_null() { return null_value; } + longlong val_int() + { + return (longlong) rint(val_real()); + } + void copy() + { + cached_value= item->val_real(); + null_value= item->null_value; + } +}; + + +class Item_copy_decimal : public Item_copy +{ +protected: + my_decimal cached_value; +public: + Item_copy_decimal (Item *i) : Item_copy(i) {} + int save_in_field(Field *field, bool no_conversions); + + String *val_str(String*); + my_decimal *val_decimal(my_decimal *) + { + return null_value ? NULL: &cached_value; + } + double val_real(); + longlong val_int(); + void copy(); }; === modified file 'sql/item_cmpfunc.cc' --- a/sql/item_cmpfunc.cc 2009-05-20 11:14:33 +0000 +++ b/sql/item_cmpfunc.cc 2009-05-25 08:00:40 +0000 @@ -2724,16 +2724,6 @@ void Item_func_case::fix_length_and_dec( nagg++; if (!(found_types= collect_cmp_types(agg, nagg))) return; - if (with_sum_func || current_thd->lex->current_select->group_list.elements) - { - /* - See TODO commentary in the setup_copy_fields function: - item in a group may be wrapped with an Item_copy_string item. - That item has a STRING_RESULT result type, so we need - to take this type into account. - */ - found_types |= (1 << item_cmp_type(left_result_type, STRING_RESULT)); - } for (i= 0; i <= (uint)DECIMAL_RESULT; i++) { === modified file 'sql/sql_select.cc' --- a/sql/sql_select.cc 2009-05-15 13:25:29 +0000 +++ b/sql/sql_select.cc 2009-05-25 08:00:40 +0000 @@ -13855,7 +13855,7 @@ SORT_FIELD *make_unireg_sortorder(ORDER pos->field= ((Item_sum*) item)->get_tmp_table_field(); else if (item->type() == Item::COPY_STR_ITEM) { // Blob patch - pos->item= ((Item_copy_string*) item)->item; + pos->item= ((Item_copy*) item)->get_item(); } else pos->item= *order->item; @@ -14926,7 +14926,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA pos= item; if (item->field->flags & BLOB_FLAG) { - if (!(pos= new Item_copy_string(pos))) + if (!(pos= Item_copy::create(pos))) goto err; /* Item_copy_string::copy for function can call @@ -14980,7 +14980,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA on how the value is to be used: In some cases this may be an argument in a group function, like: IF(ISNULL(col),0,COUNT(*)) */ - if (!(pos=new Item_copy_string(pos))) + if (!(pos= Item_copy::create(pos))) goto err; if (i < border) // HAVING, ORDER and GROUP BY { @@ -15033,8 +15033,8 @@ copy_fields(TMP_TABLE_PARAM *param) (*ptr->do_copy)(ptr); List_iterator_fast it(param->copy_funcs); - Item_copy_string *item; - while ((item = (Item_copy_string*) it++)) + Item_copy *item; + while ((item = (Item_copy*) it++)) item->copy(); } --===============8479258891484057993== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/joro@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: joro@stripped # target_branch: file:///home/kgeorge/mysql/work/B44399-5.1-bugteam/ # testament_sha1: 4b01592ef121ea539f24c275ace341b69ec64acf # timestamp: 2009-05-25 11:03:58 +0300 # base_revision_id: davi.arnaut@stripped\ # jlsx55gmo3ny0ss7 # # Begin bundle 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 --===============8479258891484057993==--