From 4382bf720bab352034c73d370d4faf8c57dbf662 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Sun, 29 Apr 2007 20:23:05 +0400 Subject: [PATCH 1/4] type_datetime.result, type_datetime.test: The test case for the bug#27590 is altered. --- mysql-test/r/type_datetime.result | 16 +++++++--------- mysql-test/t/type_datetime.test | 4 +--- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index f5ff3369c8b..3a28410b7dc 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -221,15 +221,13 @@ f1 f2 select 1 from dual where cast('2001-1-1 2:3:4' as date) = cast('2001-01-01' as datetime); 1 1 -select f1, f2, UNIX_TIMESTAMP(f2), UNIX_TIMESTAMP(f1), -f1 > f2, f1 = f2, f1 < f2 -from t1; -f1 f2 UNIX_TIMESTAMP(f2) UNIX_TIMESTAMP(f1) f1 > f2 f1 = f2 f1 < f2 -2001-01-01 2001-01-01 01:01:01 978300061 978296400 0 0 1 -2001-02-05 2001-02-05 00:00:00 981320400 981320400 0 1 0 -2001-03-10 2001-03-09 01:01:01 984088861 984171600 1 0 0 -2001-04-15 2001-04-15 00:00:00 987282000 987282000 0 1 0 -2001-05-20 2001-05-20 01:01:01 990309661 990306000 0 0 1 +select f1, f2, f1 > f2, f1 = f2, f1 < f2 from t1; +f1 f2 f1 > f2 f1 = f2 f1 < f2 +2001-01-01 2001-01-01 01:01:01 0 0 1 +2001-02-05 2001-02-05 00:00:00 0 1 0 +2001-03-10 2001-03-09 01:01:01 1 0 0 +2001-04-15 2001-04-15 00:00:00 0 1 0 +2001-05-20 2001-05-20 01:01:01 0 0 1 drop table t1; create table t1 (f1 date, f2 datetime, f3 timestamp); insert into t1 values('2001-01-01','2001-01-01 01:01:01','2001-01-01 01:01:01'); diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 2c38b3ea9e3..fc7b20d77a4 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -157,9 +157,7 @@ select f1, f3 from t1 where f1 >= '2001-02-05 00:00:00' and f3 <= '2001-04-15'; select f1, f3 from t1 where f1 >= '2001-2-5 0:0:0' and f2 <= '2001-4-15'; select f1, f2 from t1 where if(1, f1, 0) >= f2; select 1 from dual where cast('2001-1-1 2:3:4' as date) = cast('2001-01-01' as datetime); -select f1, f2, UNIX_TIMESTAMP(f2), UNIX_TIMESTAMP(f1), - f1 > f2, f1 = f2, f1 < f2 - from t1; +select f1, f2, f1 > f2, f1 = f2, f1 < f2 from t1; drop table t1; # From ce0be732d08b4966115486191fc37af5e1478b00 Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Sun, 29 Apr 2007 16:04:43 -0700 Subject: [PATCH 2/4] Fixed bug #24856: the result set of a ROLLUP query with DISTINCT could lack some rollup rows (rows with NULLs for grouping attributes) if GROUP BY list contained constant expressions. This happened because the results of constant expressions were not put in the temporary table used for duplicate elimination. In fact a constant item from the GROUP BY list of a ROLLUP query can be replaced for an Item_null_result object when a rollup row is produced . Now the JOIN::rollup_init function wraps any constant item referenced in the GROYP BY list of a ROLLUP query into an Item_func object of a special class that is never detected as constant item. This ensures creation of fields for such constant items in temporary tables and guarantees right results when the result of the rollup operation first has to be written into a temporary table, e.g. in the cases when duplicate elimination is required. --- mysql-test/r/olap.result | 61 ++++++++++++++++++++++++++++++++++++++++ mysql-test/t/olap.test | 19 +++++++++++++ sql/item_func.h | 25 ++++++++++++++++ sql/sql_select.cc | 28 +++++++++++++++++- 4 files changed, 132 insertions(+), 1 deletion(-) 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) From 395d8751d598bddd10a21064a30fa644240b4bd6 Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Sun, 29 Apr 2007 18:28:58 -0700 Subject: [PATCH 3/4] Fix in comments. --- mysql-test/t/olap.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 99db3874883..61c1bd45e5f 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -282,7 +282,7 @@ 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 +# Bug #24856: ROLLUP by const item in a query with DISTINCT # CREATE TABLE t1 (a int, b int); From 2cf753a1e84e53f784eaa095058419faaa225855 Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Sun, 29 Apr 2007 20:14:35 -0700 Subject: [PATCH 4/4] Post-merge fix. --- mysql-test/r/olap.result | 1 + sql/item_func.h | 8 ++++++-- sql/sql_select.cc | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index fe6253611e8..b1c29a5aadb 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -667,6 +667,7 @@ x 2 90 x 3 30 x NULL 150 NULL NULL 150 +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"), diff --git a/sql/item_func.h b/sql/item_func.h index cdf397c82ed..ec5d6bcda02 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -728,10 +728,14 @@ 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(); } + { + name= a->name; + name_length= a->name_length; + } + double val_real() { return args[0]->val_real(); } longlong val_int() { return args[0]->val_int(); } String *val_str(String *str) { return args[0]->val_str(str); } + my_decimal *val_decimal(my_decimal *dec) { return args[0]->val_decimal(dec); } const char *func_name() const { return "rollup_const"; } bool const_item() const { return 0; } Item_result result_type() const { return args[0]->result_type(); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4545ff62f31..b7ac2130784 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14571,7 +14571,7 @@ bool JOIN::rollup_init() Item* new_item= new Item_func_rollup_const(item); if (!new_item) return 1; - new_item->fix_fields(thd,0, (Item **) 0); + new_item->fix_fields(thd, (Item **) 0); thd->change_item_tree(it.ref(), new_item); for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) {