diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 74b7570ea2a..0300fc1759e 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -556,3 +556,64 @@ x a sum(b) 2006-07-01 NULL 11 NULL NULL 11 drop table t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 +VALUES (2,10),(3,30),(2,40),(1,10),(2,30),(1,20),(2,10); +SELECT a, SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +a SUM(b) +1 30 +2 90 +3 30 +NULL 150 +SELECT DISTINCT a, SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +a SUM(b) +1 30 +2 90 +3 30 +NULL 150 +SELECT a, b, COUNT(*) FROM t1 GROUP BY a,b WITH ROLLUP; +a b COUNT(*) +1 10 1 +1 20 1 +1 NULL 2 +2 10 2 +2 30 1 +2 40 1 +2 NULL 4 +3 30 1 +3 NULL 1 +NULL NULL 7 +SELECT DISTINCT a, b, COUNT(*) FROM t1 GROUP BY a,b WITH ROLLUP; +a b COUNT(*) +1 10 1 +1 20 1 +1 NULL 2 +2 10 2 +2 30 1 +2 40 1 +2 NULL 4 +3 30 1 +3 NULL 1 +NULL NULL 7 +SELECT 'x', a, SUM(b) FROM t1 GROUP BY 1,2 WITH ROLLUP; +x a SUM(b) +x 1 30 +x 2 90 +x 3 30 +x NULL 150 +NULL NULL 150 +SELECT DISTINCT 'x', a, SUM(b) FROM t1 GROUP BY 1,2 WITH ROLLUP; +x a SUM(b) +x 1 30 +x 2 90 +x 3 30 +x NULL 150 +NULL NULL 150 +SELECT DISTINCT 'x', a, SUM(b) FROM t1 GROUP BY 1,2 WITH ROLLUP; +x a SUM(b) +x 1 30 +x 2 90 +x 3 30 +x NULL 150 +NULL NULL 150 +DROP TABLE t1; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 683e1402678..99db3874883 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -281,4 +281,23 @@ select left(a,10), a, sum(b) from t1 group by 1,2 with rollup; select left(a,10) x, a, sum(b) from t1 group by x,a with rollup; drop table t1; +# +# Bug #20825: ROLLUP by const item in a query with DISTINCT +# + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 + VALUES (2,10),(3,30),(2,40),(1,10),(2,30),(1,20),(2,10); + +SELECT a, SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT a, SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT a, b, COUNT(*) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT DISTINCT a, b, COUNT(*) FROM t1 GROUP BY a,b WITH ROLLUP; + +SELECT 'x', a, SUM(b) FROM t1 GROUP BY 1,2 WITH ROLLUP; +SELECT DISTINCT 'x', a, SUM(b) FROM t1 GROUP BY 1,2 WITH ROLLUP; +SELECT DISTINCT 'x', a, SUM(b) FROM t1 GROUP BY 1,2 WITH ROLLUP; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/item_func.h b/sql/item_func.h index 467b88eda76..ebe3a589aa1 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -590,6 +590,31 @@ public: }; +/* + Objects of this class are used for ROLLUP queries to wrap up + each constant item referred to in GROUP BY list. +*/ + +class Item_func_rollup_const :public Item_func +{ +public: + Item_func_rollup_const(Item *a) :Item_func(a) + { name= a->name; } + double val() { return args[0]->val(); } + longlong val_int() { return args[0]->val_int(); } + String *val_str(String *str) { return args[0]->val_str(str); } + const char *func_name() const { return "rollup_const"; } + bool const_item() const { return 0; } + Item_result result_type() const { return args[0]->result_type(); } + void fix_length_and_dec() + { + collation= args[0]->collation; + max_length= args[0]->max_length; + decimals=args[0]->decimals; + } +}; + + class Item_func_length :public Item_int_func { String value; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index af3ad782ee3..36a15841065 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9754,7 +9754,7 @@ bool JOIN::rollup_init() for (j=0 ; j < fields_list.elements ; j++) rollup.fields[i].push_back(rollup.null_items[i]); } - List_iterator_fast it(all_fields); + List_iterator it(all_fields); Item *item; while ((item= it++)) { @@ -9767,6 +9767,32 @@ bool JOIN::rollup_init() { item->maybe_null= 1; found_in_group= 1; + if (item->const_item()) + { + /* + For ROLLUP queries each constant item referenced in GROUP BY list + is wrapped up into an Item_func object yielding the same value + as the constant item. The objects of the wrapper class are never + considered as constant items and besides they inherit all + properties of the Item_result_field class. + This wrapping allows us to ensure writing constant items + into temporary tables whenever the result of the ROLLUP + operation has to be written into a temporary table, e.g. when + ROLLUP is used together with DISTINCT in the SELECT list. + Usually when creating temporary tables for a intermidiate + result we do not include fields for constant expressions. + */ + Item* new_item= new Item_func_rollup_const(item); + if (!new_item) + return 1; + new_item->fix_fields(thd,0, (Item **) 0); + thd->change_item_tree(it.ref(), new_item); + for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) + { + if (*tmp->item == item) + thd->change_item_tree(tmp->item, new_item); + } + } } } if (item->type() == Item::FUNC_ITEM && !found_in_group)