diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 69871b2110b..df0ee09ea8e 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -555,6 +555,31 @@ IFNULL(a, 'TEST') COALESCE(b, 'TEST') 4 TEST TEST TEST DROP TABLE t1,t2; +CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 VALUES (1, 2); +SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; +a b c count +1 1 1 1 +1 1 NULL 1 +1 2 1 1 +1 2 NULL 1 +1 NULL NULL 2 +NULL NULL NULL 2 +DROP TABLE t1; +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a a + 1 COUNT(*) +1 2 1 +2 3 1 +NULL NULL 2 +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a LENGTH(a) COUNT(*) +1 1 1 +2 1 1 +NULL NULL 2 +DROP TABLE t1; CREATE TABLE t1(id int, type char(1)); INSERT INTO t1 VALUES (1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), @@ -577,15 +602,19 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using filesort DROP VIEW v1; DROP TABLE t1; -CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); -INSERT INTO t1 VALUES (1, 1); -INSERT INTO t1 VALUES (1, 2); -SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; -a b c count -1 1 1 1 -1 1 NULL 1 -1 2 1 1 -1 2 NULL 1 -1 NULL NULL 2 -NULL NULL NULL 2 +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +CREATE VIEW v1 AS +SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +DESC v1; +Field Type Null Key Default Extra +a bigint(11) YES NULL +LENGTH(a) bigint(10) YES NULL +COUNT(*) bigint(21) NO 0 +SELECT * FROM v1; +a LENGTH(a) COUNT(*) +1 1 1 +2 1 1 +NULL NULL 2 +DROP VIEW v1; DROP TABLE t1; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 2e09bc5b3a3..3a6a5e46f37 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -250,6 +250,33 @@ SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 DROP TABLE t1,t2; +# +# Test for bug #11543: ROLLUP query with a repeated column in GROUP BY +# + +CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 VALUES (1, 2); + +SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; + +DROP TABLE t1; + +# +# Bug #12885(1): derived table specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes +# + +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); + +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; + +DROP TABLE t1; + +# End of 4.1 tests + # # Tests for bug #11639: ROLLUP over view executed through filesort # @@ -266,15 +293,20 @@ EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; DROP VIEW v1; DROP TABLE t1; -# Test for bug #11543: ROLLUP query with a repeated column in GROUP BY + +# +# Bug #12885(2): view specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes # -CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); -INSERT INTO t1 VALUES (1, 1); -INSERT INTO t1 VALUES (1, 2); +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); -SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; +CREATE VIEW v1 AS + SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +DESC v1; +SELECT * FROM v1; + +DROP VIEW v1; DROP TABLE t1; - -# End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bf06599b25e..28afec2f688 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13043,6 +13043,8 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) The function replaces occurrences of group by fields in expr by ref objects for these fields unless they are under aggregate functions. + The function also corrects value of the the maybe_null attribute + for the items of all subexpressions containing group by fields. IMPLEMENTATION The function recursively traverses the tree of the expr expression, @@ -13053,6 +13055,9 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) This substitution is needed GROUP BY queries with ROLLUP if SELECT list contains expressions over group by attributes. + TODO: Some functions are not null-preserving. For those functions + updating of the maybe_null attribute is an overkill. + EXAMPLES SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP @@ -13074,6 +13079,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, arg != arg_end; arg++) { Item *item= *arg; + bool arg_changed= FALSE; if (item->type() == Item::FIELD_ITEM || item->type() == Item::REF_ITEM) { ORDER *group_tmp; @@ -13086,15 +13092,20 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, item->name))) return 1; // fatal_error is set thd->change_item_tree(arg, new_item); - *changed= TRUE; + arg_changed= TRUE; } } } else if (item->type() == Item::FUNC_ITEM) { - if (change_group_ref(thd, (Item_func *) item, group_list, changed)) + if (change_group_ref(thd, (Item_func *) item, group_list, &arg_changed)) return 1; } + if (arg_changed) + { + expr->maybe_null= 1; + *changed= TRUE; + } } } return 0; @@ -13157,7 +13168,7 @@ bool JOIN::rollup_init() } if (item->type() == Item::FUNC_ITEM) { - bool changed= 0; + bool changed= FALSE; if (change_group_ref(thd, (Item_func *) item, group_list, &changed)) return 1; /*