summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorgi Kodinov <kgeorge@mysql.com>2008-10-02 17:44:49 +0300
committerGeorgi Kodinov <kgeorge@mysql.com>2008-10-02 17:44:49 +0300
commita18639b63426092f6df98f6c67ab1139fe50e3c8 (patch)
tree413e89307c136e039f03c0ba72d7a866436e22e5
parent6037e8ec49572eae3a0a079f6b818caf0f96ab1b (diff)
downloadmariadb-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.result37
-rw-r--r--mysql-test/t/func_group.test40
-rw-r--r--sql/item.cc1
-rw-r--r--sql/item.h2
-rw-r--r--sql/sql_select.cc11
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