From ce6c390c390b1993edade781c0ee21b07eb741cc Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Tue, 15 Mar 2005 22:50:54 -0800 Subject: [PATCH] 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. --- 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();