MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Georgi Kodinov Date:October 2 2008 10:25am
Subject:bzr commit into mysql-5.1 branch (kgeorge:2757) Bug#37348
View as plain text  
#At file:///home/kgeorge/mysql/bzr/B37348-5.1-5.1.29-rc/

 2757 Georgi Kodinov	2008-10-02
      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 checking the type of the original item before considering an 
      Item_field referenced through an Item_aggregate_ref as a thing that 
      needs copying.
      Added an assertion to make sure bugs that cause similar discrepancy 
      don't go undetected.
modified:
  mysql-test/r/func_group.result
  mysql-test/t/func_group.test
  sql/item.cc
  sql/item.h
  sql/sql_select.cc

per-file messages:
  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: moved the definition of Item_aggregate_ref to the correct
    header file.
  sql/item.h
    Bug #37348: 
    - moved the definition of Item_aggregate_ref to the correct
      header file.
    - Added a member to collect the type of the item originally referenced 
      by this Item_ref subclass.     
    - 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 that was not originally pointing to a 
    field.
=== modified file 'mysql-test/r/func_group.result'
--- a/mysql-test/r/func_group.result	2008-03-19 11:25:36 +0000
+++ b/mysql-test/r/func_group.result	2008-10-02 10:25:19 +0000
@@ -1416,4 +1416,41 @@ SELECT AVG(a), CAST(AVG(a) AS DECIMAL) F
 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

=== modified file 'mysql-test/t/func_group.test'
--- a/mysql-test/t/func_group.test	2008-03-19 11:25:36 +0000
+++ b/mysql-test/t/func_group.test	2008-10-02 10:25:19 +0000
@@ -933,5 +933,45 @@ SELECT AVG(a), CAST(AVG(a) AS DECIMAL) F
 
 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

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2008-10-02 05:56:07 +0000
+++ b/sql/item.cc	2008-10-02 10:25:19 +0000
@@ -1319,28 +1319,6 @@ void Item_name_const::print(String *str,
 }
 
 
-/*
- need a special class to adjust printing : references to aggregate functions 
- must not be printed as refs because the aggregate functions that are added to
- the front of select list are not printed as well.
-*/
-class Item_aggregate_ref : public Item_ref
-{
-public:
-  Item_aggregate_ref(Name_resolution_context *context_arg, Item **item,
-                  const char *table_name_arg, const char *field_name_arg)
-    :Item_ref(context_arg, item, table_name_arg, field_name_arg) {}
-
-  virtual inline void print (String *str, enum_query_type query_type)
-  {
-    if (ref)
-      (*ref)->print(str, query_type);
-    else
-      Item_ident::print(str, query_type);
-  }
-};
-
-
 /**
   Move SUM items out from item tree and replace with reference.
 

=== modified file 'sql/item.h'
--- a/sql/item.h	2008-08-15 20:42:29 +0000
+++ b/sql/item.h	2008-10-02 10:25:19 +0000
@@ -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,
@@ -2419,6 +2419,32 @@ public:
   virtual Item *real_item() { return ref; }
 };
 
+
+/*
+ need a special class to adjust printing : references to aggregate functions 
+ must not be printed as refs because the aggregate functions that are added to
+ the front of select list are not printed as well.
+*/
+class Item_aggregate_ref : public Item_ref
+{
+public:
+  Item::Type original_type;
+  Item_aggregate_ref(Name_resolution_context *context_arg, Item **item,
+                  const char *table_name_arg, const char *field_name_arg)
+    :Item_ref(context_arg, item, table_name_arg, field_name_arg), 
+     original_type((*item)->type()) {}
+
+  virtual inline void print (String *str, enum_query_type query_type)
+  {
+    if (ref)
+      (*ref)->print(str, query_type);
+    else
+      Item_ident::print(str, query_type);
+  }
+  virtual Ref_Type ref_type() { return AGGREGATE_REF; }
+};
+
+
 #ifdef MYSQL_SERVER
 #include "gstream.h"
 #include "spatial.h"

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2008-08-28 09:54:50 +0000
+++ b/sql/sql_select.cc	2008-10-02 10:25:19 +0000
@@ -14804,6 +14804,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA
   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,22 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA
     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)
+    /* 
+      Process all fields that were not something else originally
+      and weren't substituted to Item_field later 
+    */
+    if (real_pos->type() == Item::FIELD_ITEM &&
+        !(pos->type() == Item::REF_ITEM &&
+          ((Item_ref *)pos)->ref_type() == Item_ref::AGGREGATE_REF &&
+          ((Item_aggregate_ref *)pos)->original_type != Item::FIELD_ITEM
+         )
+        )
     {
       Item_field *item;
       if (!(item= new Item_field(thd, ((Item_field*) real_pos))))
@@ -14868,6 +14879,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA
 	  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

Thread
bzr commit into mysql-5.1 branch (kgeorge:2757) Bug#37348Georgi Kodinov2 Oct