List:Internals« Previous MessageNext Message »
From:igor Date:May 30 2005 12:02pm
Subject:bk commit into 4.1 tree (igor:1.2301) BUG#7894
View as plain text  
Below is the list of changes that have just been committed into a local
4.1 repository of igor. When igor does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.2301 05/05/30 03:01:51 igor@stripped +3 -0
  olap.result, olap.test:
    Added test cases for bug #7894.
  sql_select.cc:
    Fixed bug #7894: GROUP BY queries with ROLLUP returned
    wrong results for expressions containing group by columns.
    The fix ensured correct results by replacement of all
    occurrences of group by fields in non-aggregate expressions
    for corresponding ref objects and preventing creation of
    fields in temporary tables for expression containing group
    by fields.

  mysql-test/r/olap.result
    1.18 05/05/30 02:59:49 igor@stripped +67 -1
    Added test cases for bug #7894.

  mysql-test/t/olap.test
    1.15 05/05/30 02:59:23 igor@stripped +30 -0
    Added test cases for bug #7894.

  sql/sql_select.cc
    1.402 05/05/30 02:46:02 igor@stripped +90 -5
    Fixed bug #7894: GROUP BY queries with ROLLUP returned
    wrong results for expressions containing group by columns.
    The fix ensured correct results by replacement of all
    occurrences of group by fields in non-aggregate expressions
    for corresponding ref objects and preventing creation of
    fields in temporary tables for expression containing group
    by fields.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	igor
# Host:	rurik.mysql.com
# Root:	/home/igor/dev/mysql-4.1-0

--- 1.401/sql/sql_select.cc	Thu May 26 03:09:09 2005
+++ 1.402/sql/sql_select.cc	Mon May 30 02:46:02 2005
@@ -9164,6 +9164,79 @@
   ROLLUP handling
 ****************************************************************************/
 
+/*
+  Replace occurences of group by fields in an expression by ref items
+
+  SYNOPSIS
+    change_group_ref()
+    thd                  reference to the context
+    expr                 expression to make replacement
+    group_list           list of references to group by items
+    changed        out:  returns 1 if item contains a replaced field item 
+     
+  DESCRIPTION
+    The function replaces occurrences of group by fields in expr
+    by ref objects for these fields unless they are under aggregate
+    functions.
+
+  IMPLEMENTATION
+    The function recursively traverses the tree of the expr expression,
+    looks for occurrences of the group by fields that are not under
+    aggregate functions and replaces them for the corresponding ref items.
+
+  NOTES
+    This substitution is needed GROUP BY queries with ROLLUP if
+    SELECT list contains expressions over group by attributes.
+
+  EXAMPLES
+    SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP
+    SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP 
+    
+  RETURN
+    0	if ok
+    1   on error
+*/
+
+static bool change_group_ref(THD *thd, Item *expr, ORDER *group_list,
+                             bool *changed)
+{
+  if (expr->type() != Item::FUNC_ITEM)
+    return 0;
+  Item_func *func_item= (Item_func *) expr;
+  if (func_item->arg_count)
+  {
+    Item **arg,**arg_end;
+    for (arg= func_item->arguments(),
+         arg_end= func_item->arguments()+func_item->arg_count;
+         arg != arg_end; arg++)
+    {
+      Item *item= *arg;
+      if (item->type() == Item::FIELD_ITEM || item->type() == Item::REF_ITEM)
+      {
+        ORDER *group_tmp;
+        for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next)
+        {
+          if (item->eq(*group_tmp->item,0))
+          {
+            Item *new_item;    
+            if(!(new_item= new Item_ref(group_tmp->item, 0, item->name)))
+              return 1;                                 // fatal_error is set
+            thd->change_item_tree(arg, new_item);
+            *changed= TRUE;
+          }
+        }
+      }
+      else if (item->type() == Item::FUNC_ITEM)
+      {
+        if (change_group_ref(thd, item, group_list, changed))
+          return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+
 /* Allocate memory needed for other rollup functions */
 
 bool JOIN::rollup_init()
@@ -9208,19 +9281,31 @@
     for (j=0 ; j < fields_list.elements ; j++)
       rollup.fields[i].push_back(rollup.null_items[i]);
   }
-  List_iterator_fast<Item> it(fields_list);
+  List_iterator_fast<Item> it(all_fields);
   Item *item;
   while ((item= it++))
   {
     ORDER *group_tmp;
     for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next)
     {
-      if (*group_tmp->item == item)
+      if (item->eq(*group_tmp->item,0))
         item->maybe_null= 1;
     }
+    if (item->type() == Item::FUNC_ITEM)
+    {
+      bool changed= 0;
+      if (change_group_ref(thd, item, group_list, &changed))
+        return 1;
+      /*
+        We have to prevent creation of a field in a temporary table for
+        an expression that contains GROUP BY attributes.
+        Marking the expression item as 'with_sum_func' will ensure this.
+      */ 
+      if (changed)
+        item->with_sum_func= 1;
+    }
   }
   return 0;
-
 }
   
 
@@ -9318,14 +9403,14 @@
 	*(*func)= (Item_sum*) item;
 	(*func)++;
       }
-      else if (real_fields)
+      else 
       {
 	/* Check if this is something that is part of this group by */
 	ORDER *group_tmp;
 	for (group_tmp= start_group, i= pos ;
              group_tmp ; group_tmp= group_tmp->next, i++)
 	{
-	  if (*group_tmp->item == item)
+          if (item->eq(*group_tmp->item,0))
 	  {
 	    /*
 	      This is an element that is used by the GROUP BY and should be

--- 1.17/mysql-test/r/olap.result	Wed May 18 05:15:18 2005
+++ 1.18/mysql-test/r/olap.result	Mon May 30 02:59:49 2005
@@ -248,7 +248,7 @@
 :Computer:	6900	1380.0000
 :Phone:	10	10.0000
 :TV:	600	120.0000
-:TV:	7785	519.0000
+NULL	7785	519.0000
 select product, country_id , year, sum(profit) from t1 group by product, country_id, year
with cube;
 ERROR 42000: This version of MySQL doesn't yet support 'CUBE'
 explain select product, country_id , year, sum(profit) from t1 group by product,
country_id, year with cube;
@@ -438,3 +438,69 @@
 5	5	6	5x	10	5
 NULL	8	9	8x	16	8
 DROP TABLE t1;
+CREATE TABLE t1 (a int(11));
+INSERT INTO t1 VALUES (1),(2);
+SELECT a, a+1, SUM(a) FROM t1 GROUP BY a WITH ROLLUP;
+a	a+1	SUM(a)
+1	2	1
+2	3	2
+NULL	NULL	3
+SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP;
+a+1
+2
+3
+NULL
+SELECT a+SUM(a) FROM t1 GROUP BY a WITH ROLLUP;
+a+SUM(a)
+2
+4
+NULL
+SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b > 2;
+a	b
+2	3
+SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING a IS NULL;
+a	b
+NULL	NULL
+SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b IS NULL;
+a	b
+NULL	NULL
+SELECT IFNULL(a, 'TEST') FROM t1 GROUP BY a WITH ROLLUP;
+IFNULL(a, 'TEST')
+1
+2
+TEST
+CREATE TABLE t2 (a int, b int);
+INSERT INTO t2 VALUES
+(1,4),
+(2,2), (2,2),
+(4,1), (4,1), (4,1), (4,1),
+(2,1), (2,1);
+SELECT a,b,SUM(b) FROM t2 GROUP BY a,b WITH ROLLUP;
+a	b	SUM(b)
+1	4	4
+1	NULL	4
+2	1	2
+2	2	4
+2	NULL	6
+4	1	4
+4	NULL	4
+NULL	NULL	14
+SELECT a,b,SUM(b), a+b as c FROM t2
+GROUP BY a,b WITH ROLLUP HAVING c IS NULL;
+a	b	SUM(b)	c
+1	NULL	4	NULL
+2	NULL	6	NULL
+4	NULL	4	NULL
+NULL	NULL	14	NULL
+SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 
+GROUP BY a, b WITH ROLLUP;
+IFNULL(a, 'TEST')	COALESCE(b, 'TEST')
+1	4
+1	TEST
+2	1
+2	2
+2	TEST
+4	1
+4	TEST
+TEST	TEST
+DROP TABLE t1,t2;

--- 1.14/mysql-test/t/olap.test	Wed May 18 05:14:32 2005
+++ 1.15/mysql-test/t/olap.test	Mon May 30 02:59:23 2005
@@ -208,3 +208,33 @@
 
 DROP TABLE t1;
 
+#
+# Tests for bug #7894: ROLLUP over expressions on group by attributes
+#
+
+CREATE TABLE t1 (a int(11));
+INSERT INTO t1 VALUES (1),(2);
+
+SELECT a, a+1, SUM(a) FROM t1 GROUP BY a WITH ROLLUP;
+SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP;
+SELECT a+SUM(a) FROM t1 GROUP BY a WITH ROLLUP;
+SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b > 2;
+SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING a IS NULL;
+SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b IS NULL;
+SELECT IFNULL(a, 'TEST') FROM t1 GROUP BY a WITH ROLLUP;
+
+CREATE TABLE t2 (a int, b int);
+INSERT INTO t2 VALUES
+  (1,4),
+  (2,2), (2,2),
+  (4,1), (4,1), (4,1), (4,1),
+  (2,1), (2,1);
+
+SELECT a,b,SUM(b) FROM t2 GROUP BY a,b WITH ROLLUP; 
+SELECT a,b,SUM(b), a+b as c FROM t2
+  GROUP BY a,b WITH ROLLUP HAVING c IS NULL;
+SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 
+  GROUP BY a, b WITH ROLLUP; 
+
+DROP TABLE t1,t2;
+
Thread
bk commit into 4.1 tree (igor:1.2301) BUG#7894igor30 May