diff options
author | Georgi Kodinov <kgeorge@mysql.com> | 2008-10-02 17:44:49 +0300 |
---|---|---|
committer | Georgi Kodinov <kgeorge@mysql.com> | 2008-10-02 17:44:49 +0300 |
commit | a18639b63426092f6df98f6c67ab1139fe50e3c8 (patch) | |
tree | 413e89307c136e039f03c0ba72d7a866436e22e5 | |
parent | 6037e8ec49572eae3a0a079f6b818caf0f96ab1b (diff) | |
download | mariadb-git-a18639b63426092f6df98f6c67ab1139fe50e3c8.tar.gz |
Bug #37348: Crash in or immediately after JOIN::make_sum_func_list
The optimizer pulls up aggregate functions which should be aggregated in
an outer select. At some point it may substitute such a function for a field
in the temporary table. The setup_copy_fields function doesn't take this
into account and may overrun the copy_field buffer.
Fixed by filtering out the fields referenced through the specialized
reference for aggregates (Item_aggregate_ref).
Added an assertion to make sure bugs that cause similar discrepancy
don't go undetected.
mysql-test/r/func_group.result:
Bug #37348: test case
mysql-test/t/func_group.test:
Bug #37348: test case
sql/item.cc:
Bug #37348: Added a way to distinguish Item_aggregate_ref from the other types of refs
sql/item.h:
Bug #37348: Added a way to distinguish Item_aggregate_ref from the other types of refs
sql/sql_select.cc:
Bug #37348:
- Don't consider copying field references
seen through Item_aggregate_ref
- check for discrepancies between the number of expected
fields that need copying and the actual fields copied.
-rw-r--r-- | mysql-test/r/func_group.result | 37 | ||||
-rw-r--r-- | mysql-test/t/func_group.test | 40 | ||||
-rw-r--r-- | sql/item.cc | 1 | ||||
-rw-r--r-- | sql/item.h | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 11 |
5 files changed, 89 insertions, 2 deletions
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index c198176532f..fd9cf69907c 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1416,4 +1416,41 @@ SELECT AVG(a), CAST(AVG(a) AS DECIMAL) FROM t1; AVG(a) CAST(AVG(a) AS DECIMAL) 15 15 DROP TABLE t1; +CREATE TABLE derived1 (a bigint(21)); +INSERT INTO derived1 VALUES (2); +CREATE TABLE D ( +pk int(11) NOT NULL AUTO_INCREMENT, +int_nokey int(11) DEFAULT NULL, +int_key int(11) DEFAULT NULL, +filler blob, +PRIMARY KEY (pk), +KEY int_key (int_key) +); +INSERT INTO D VALUES +(39,40,4,repeat(' X', 42)), +(43,56,4,repeat(' X', 42)), +(47,12,4,repeat(' X', 42)), +(71,28,4,repeat(' X', 42)), +(76,54,4,repeat(' X', 42)), +(83,45,4,repeat(' X', 42)), +(105,53,12,NULL); +SELECT +(SELECT COUNT( int_nokey ) +FROM derived1 AS X +WHERE +X.int_nokey < 61 +GROUP BY pk +LIMIT 1) +FROM D AS X +WHERE X.int_key < 13 +GROUP BY int_nokey LIMIT 1; +(SELECT COUNT( int_nokey ) +FROM derived1 AS X +WHERE +X.int_nokey < 61 +GROUP BY pk +LIMIT 1) +1 +DROP TABLE derived1; +DROP TABLE D; End of 5.0 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index b6143bc0c78..4eedd433d34 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -933,5 +933,45 @@ SELECT AVG(a), CAST(AVG(a) AS DECIMAL) FROM t1; DROP TABLE t1; +# +# Bug #37348: Crash in or immediately after JOIN::make_sum_func_list +# + +CREATE TABLE derived1 (a bigint(21)); +INSERT INTO derived1 VALUES (2); + + +CREATE TABLE D ( + pk int(11) NOT NULL AUTO_INCREMENT, + int_nokey int(11) DEFAULT NULL, + int_key int(11) DEFAULT NULL, + filler blob, + PRIMARY KEY (pk), + KEY int_key (int_key) +); + +INSERT INTO D VALUES + (39,40,4,repeat(' X', 42)), + (43,56,4,repeat(' X', 42)), + (47,12,4,repeat(' X', 42)), + (71,28,4,repeat(' X', 42)), + (76,54,4,repeat(' X', 42)), + (83,45,4,repeat(' X', 42)), + (105,53,12,NULL); + +SELECT + (SELECT COUNT( int_nokey ) + FROM derived1 AS X + WHERE + X.int_nokey < 61 + GROUP BY pk + LIMIT 1) +FROM D AS X +WHERE X.int_key < 13 +GROUP BY int_nokey LIMIT 1; + +DROP TABLE derived1; +DROP TABLE D; + ### --echo End of 5.0 tests diff --git a/sql/item.cc b/sql/item.cc index 66d5d55a21e..fc33f3d5cad 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1338,6 +1338,7 @@ public: else Item_ident::print(str, query_type); } + virtual Ref_Type ref_type() { return AGGREGATE_REF; } }; diff --git a/sql/item.h b/sql/item.h index be343e25d3f..00a2759a739 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2126,7 +2126,7 @@ class Item_ref :public Item_ident protected: void set_properties(); public: - enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF }; + enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF, AGGREGATE_REF }; Field *result_field; /* Save result here */ Item **ref; Item_ref(Name_resolution_context *context_arg, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6510d2428db..102809f9f64 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14804,6 +14804,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, Item *pos; List_iterator_fast<Item> li(all_fields); Copy_field *copy= NULL; + IF_DBUG(Copy_field *copy_start); res_selected_fields.empty(); res_all_fields.empty(); List_iterator_fast<Item> itr(res_all_fields); @@ -14816,12 +14817,19 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, goto err2; param->copy_funcs.empty(); + IF_DBUG(copy_start= copy); for (i= 0; (pos= li++); i++) { Field *field; uchar *tmp; Item *real_pos= pos->real_item(); - if (real_pos->type() == Item::FIELD_ITEM) + /* + Aggregate functions can be substituted for fields (by e.g. temp tables). + We need to filter those substituted fields out. + */ + if (real_pos->type() == Item::FIELD_ITEM && + !(real_pos != pos && + ((Item_ref *)pos)->ref_type() == Item_ref::AGGREGATE_REF)) { Item_field *item; if (!(item= new Item_field(thd, ((Item_field*) real_pos)))) @@ -14868,6 +14876,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, goto err; if (copy) { + DBUG_ASSERT (param->field_count > (uint) (copy - copy_start)); copy->set(tmp, item->result_field); item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1); #ifdef HAVE_purify |