From e16535ce1957567b1f176bdbcda766a8104a5072 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 15 Mar 2005 22:50:54 -0800 Subject: [PATCH 1/2] olap.result, olap.test: Added a test case for bug #8616. item.h: Fixed bug #8616. Added class Item_null_result used in rollup processing. sql_select.h, sql_select.cc: Fixed bug #8616. Added JOIN::rollup_write_data to cover rollup queries with DISTINCT. Modified other rollup methods. sql/sql_select.cc: Fixed bug #8616. Added JOIN::rollup_write_data to cover rollup queries with DISTINCT. Modified other rollup methods. sql/sql_select.h: Fixed bug #8616. Added JOIN::rollup_write_data to cover rollup queries with DISTINCT. Modified other rollup methods. sql/item.h: Fixed bug #8616. Added class Item_null_result used in rollup processing. mysql-test/t/olap.test: Added a test case for bug #8616. mysql-test/r/olap.result: Added a test case for bug #8616. --- mysql-test/r/olap.result | 54 ++++++++++++++++++ mysql-test/t/olap.test | 27 +++++++++ sql/item.h | 11 ++++ sql/sql_select.cc | 118 ++++++++++++++++++++++++++++++--------- sql/sql_select.h | 3 +- 5 files changed, 186 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index bcbe5a8791c..67610108c61 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -307,3 +307,57 @@ day sample not_cancelled 2004-06-07 1 0 NULL 3 1 DROP TABLE user_day; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES +(1,4), +(2,2), (2,2), +(4,1), (4,1), (4,1), (4,1), +(2,1), (2,1); +SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) +4 +6 +4 +14 +SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) +4 +6 +14 +SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) +4 1 +6 2 +4 1 +14 3 +SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) +4 1 +6 2 +14 3 +SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(*) +4 1 +6 4 +4 4 +14 9 +SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(*) +4 1 +6 4 +4 4 +14 9 +SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) COUNT(*) +4 1 1 +6 2 4 +4 1 4 +14 3 9 +SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 +GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) COUNT(*) +4 1 1 +6 2 4 +4 1 4 +14 3 9 +DROP TABLE t1; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 674b4ade097..d2ea582e58c 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -125,3 +125,30 @@ SELECT DROP TABLE user_day; +# +# Test for bug #8616: distinct sum with rollup +# + +CREATE TABLE t1 (a int, b int); + +INSERT INTO t1 VALUES + (1,4), + (2,2), (2,2), + (4,1), (4,1), (4,1), (4,1), + (2,1), (2,1); + +SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 + GROUP BY a WITH ROLLUP; + +DROP TABLE t1; + diff --git a/sql/item.h b/sql/item.h index adc780677e1..e34a5f889d2 100644 --- a/sql/item.h +++ b/sql/item.h @@ -470,6 +470,17 @@ public: Item *safe_charset_converter(CHARSET_INFO *tocs); }; +class Item_null_result :public Item_null +{ +public: + Field *result_field; + Item_null_result() : Item_null(), result_field(0) {} + bool is_result_field() { return result_field != 0; } + void save_in_result_field(bool no_conversions) + { + save_in_field(result_field, no_conversions); + } +}; /* Item represents one placeholder ('?') of prepared statement */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b00f9e422a1..0bb4c6a9402 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -157,7 +157,7 @@ static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, uint elements, List &items); static void init_tmptable_sum_functions(Item_sum **func); static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table); -static void copy_sum_funcs(Item_sum **func_ptr); +static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end); static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab); static bool init_sum_functions(Item_sum **func, Item_sum **end); static bool update_sum_func(Item_sum **func); @@ -1328,7 +1328,7 @@ JOIN::exec() if (curr_join->tmp_having) curr_join->tmp_having->update_used_tables(); if (remove_duplicates(curr_join, curr_tmp_table, - curr_join->fields_list, curr_join->tmp_having)) + *curr_fields_list, curr_join->tmp_having)) DBUG_VOID_RETURN; curr_join->tmp_having=0; curr_join->select_distinct=0; @@ -6740,26 +6740,32 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if (join->procedure) join->procedure->end_group(); - if (idx < (int) join->send_group_parts) + int send_group_parts= join->send_group_parts; + if (idx < send_group_parts) { if (!join->first_record) { /* No matching rows for group function */ join->clear(); } - copy_sum_funcs(join->sum_funcs); - if (!join->having || join->having->val_int()) + copy_sum_funcs(join->sum_funcs, + join->sum_funcs_end[send_group_parts]); + if (join->having && join->having->val_int() == 0) + error= -1; + else if ((error=table->file->write_row(table->record[0]))) { - if ((error=table->file->write_row(table->record[0]))) - { - if (create_myisam_from_heap(join->thd, table, - &join->tmp_table_param, - error, 0)) - DBUG_RETURN(-1); // Not a table_is_full error - } - else - join->send_records++; + if (create_myisam_from_heap(join->thd, table, + &join->tmp_table_param, + error, 0)) + DBUG_RETURN(-1); + } + if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0) + { + if (join->rollup_write_data((uint) (idx+1), table)) + error= 1; } + if (error > 0) + DBUG_RETURN(-1); if (end_of_records) DBUG_RETURN(0); } @@ -8888,11 +8894,10 @@ update_tmptable_sum_func(Item_sum **func_ptr, /* Copy result of sum functions to record in tmp_table */ static void -copy_sum_funcs(Item_sum **func_ptr) +copy_sum_funcs(Item_sum **func_ptr, Item_sum **end_ptr) { - Item_sum *func; - for (; (func = *func_ptr) ; func_ptr++) - (void) func->save_in_result_field(1); + for (; func_ptr != end_ptr ; func_ptr++) + (void) (*func_ptr)->save_in_result_field(1); return; } @@ -9013,14 +9018,16 @@ bool JOIN::rollup_init() */ tmp_table_param.group_parts= send_group_parts; - if (!(rollup.fields= (List*) thd->alloc((sizeof(Item*) + - sizeof(List) + - ref_pointer_array_size) - * send_group_parts))) + if (!(rollup.null_items= (Item_null_result**) thd->alloc((sizeof(Item*) + + sizeof(Item**) + + sizeof(List) + + ref_pointer_array_size) + * send_group_parts ))) return 1; + + rollup.fields= (List*) (rollup.null_items + send_group_parts); rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts); ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts); - rollup.item_null= new (thd->mem_root) Item_null(); /* Prepare space for field list for the different levels @@ -9028,12 +9035,16 @@ bool JOIN::rollup_init() */ for (i= 0 ; i < send_group_parts ; i++) { + rollup.null_items[i]= new (thd->mem_root) Item_null_result(); List *rollup_fields= &rollup.fields[i]; rollup_fields->empty(); rollup.ref_pointer_arrays[i]= ref_array; ref_array+= all_fields.elements; + } + for (i= 0 ; i < send_group_parts; i++) + { for (j=0 ; j < fields_list.elements ; j++) - rollup_fields->push_back(rollup.item_null); + rollup.fields[i].push_back(rollup.null_items[i]); } return 0; } @@ -9137,7 +9148,8 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, { /* Check if this is something that is part of this group by */ ORDER *group_tmp; - for (group_tmp= start_group ; group_tmp ; group_tmp= group_tmp->next) + for (group_tmp= start_group, i-- ; + group_tmp ; group_tmp= group_tmp->next, i++) { if (*group_tmp->item == item) { @@ -9146,7 +9158,9 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, set to NULL in this level */ item->maybe_null= 1; // Value will be null sometimes - item= rollup.item_null; + Item_null_result *null_item= rollup.null_items[i]; + null_item->result_field= ((Item_field *) item)->result_field; + item= null_item; break; } } @@ -9206,6 +9220,58 @@ int JOIN::rollup_send_data(uint idx) return 0; } +/* + Write all rollup levels higher than the current one to a temp table + + SYNOPSIS: + rollup_write_data() + idx Level we are on: + 0 = Total sum level + 1 = First group changed (a) + 2 = Second group changed (a,b) + table reference to temp table + + SAMPLE + SELECT a, b, SUM(c) FROM t1 GROUP BY a,b WITH ROLLUP + + RETURN + 0 ok + 1 if write_data_failed() +*/ + +int JOIN::rollup_write_data(uint idx, TABLE *table) +{ + uint i; + for (i= send_group_parts ; i-- > idx ; ) + { + /* Get reference pointers to sum functions in place */ + memcpy((char*) ref_pointer_array, + (char*) rollup.ref_pointer_arrays[i], + ref_pointer_array_size); + if ((!having || having->val_int())) + { + int error; + Item *item; + List_iterator_fast it(rollup.fields[i]); + while ((item= it++)) + { + if (item->type() == Item::NULL_ITEM && item->is_result_field()) + item->save_in_result_field(1); + } + copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]); + if ((error= table->file->write_row(table->record[0]))) + { + if (create_myisam_from_heap(thd, table, &tmp_table_param, + error, 0)) + return 1; + } + } + } + /* Restore ref_pointer_array */ + set_items_ref_array(current_ref_pointer_array); + return 0; +} + /* clear results if there are not rows found for group (end_send_group/end_write_group) diff --git a/sql/sql_select.h b/sql/sql_select.h index bbd169d1850..4ea7e1b23e7 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -124,7 +124,7 @@ typedef struct st_rollup { enum State { STATE_NONE, STATE_INITED, STATE_READY }; State state; - Item *item_null; + Item_null_result **null_items; Item ***ref_pointer_arrays; List *fields; } ROLLUP; @@ -295,6 +295,7 @@ class JOIN :public Sql_alloc bool rollup_make_fields(List &all_fields, List &fields, Item_sum ***func); int rollup_send_data(uint idx); + int rollup_write_data(uint idx, TABLE *table); bool test_in_subselect(Item **where); void join_free(bool full); void clear(); From 31f6b0dde83e7c4fc1626958f40f2c22ca51f23b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Mar 2005 15:55:04 -0800 Subject: [PATCH 2/2] olap.result, olap.test: Added a test for bug #8615. sql_select.cc: Fixed bug #8615. This fix only removed the cause of the reported crash. It does not resolve other problems of rollup queries with DISTINCT. They were fixed in the previous patch for bug 8616. sql/sql_select.cc: Fixed bug #8615. This fix only removed the cause of the reported crash. It does not resolve other problems of rollup queries with DISTINCT. They were fixed in the previous patch for bug 8616. mysql-test/t/olap.test: Added a test for bug #8615. mysql-test/r/olap.result: Added a test for bug #8615. --- mysql-test/r/olap.result | 18 ++++++++++++++++++ mysql-test/t/olap.test | 5 ++++- sql/sql_select.cc | 7 ++++--- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 67610108c61..fe83800f658 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -360,4 +360,22 @@ SUM(b) COUNT(DISTINCT b) COUNT(*) 6 2 4 4 1 4 14 3 9 +SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +a sum(b) +1 4 +1 4 +2 2 +2 4 +2 6 +4 4 +4 4 +NULL 14 +SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +a sum(b) +1 4 +2 2 +2 4 +2 6 +4 4 +NULL 14 DROP TABLE t1; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index d2ea582e58c..6778af3d533 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -126,7 +126,7 @@ SELECT DROP TABLE user_day; # -# Test for bug #8616: distinct sum with rollup +# Tests for bugs #8616, #8615: distinct sum with rollup # CREATE TABLE t1 (a int, b int); @@ -150,5 +150,8 @@ SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; + DROP TABLE t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0bb4c6a9402..5bfe1346568 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1269,7 +1269,6 @@ JOIN::exec() { DBUG_VOID_RETURN; } - curr_join->group_list= 0; } thd->proc_info="Copying to group table"; @@ -1289,8 +1288,10 @@ JOIN::exec() } } if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, - 1) || - (tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, + 1)) + DBUG_VOID_RETURN; + curr_join->group_list= 0; + if ((tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, 0))) { error= tmp_error;