Loading mysql-test/r/olap.result +72 −0 Original line number Diff line number Diff line Loading @@ -307,3 +307,75 @@ 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 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; mysql-test/t/olap.test +30 −0 Original line number Diff line number Diff line Loading @@ -125,3 +125,33 @@ SELECT DROP TABLE user_day; # # Tests for bugs #8616, #8615: 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; 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; sql/item.h +11 −0 Original line number Diff line number Diff line Loading @@ -470,6 +470,17 @@ class Item_null :public Item 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 */ Loading sql/sql_select.cc +96 −29 Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, uint elements, List<Item> &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); Loading Loading @@ -1269,7 +1269,6 @@ JOIN::exec() { DBUG_VOID_RETURN; } curr_join->group_list= 0; } thd->proc_info="Copying to group table"; Loading @@ -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<Item> *) 0, curr_tmp_table, 1)) DBUG_VOID_RETURN; curr_join->group_list= 0; if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0))) { error= tmp_error; Loading Loading @@ -1328,7 +1329,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; Loading Loading @@ -6740,26 +6741,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()) { if ((error=table->file->write_row(table->record[0]))) 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 (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, error, 0)) DBUG_RETURN(-1); // Not a table_is_full error DBUG_RETURN(-1); } else join->send_records++; 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); } Loading Loading @@ -8888,11 +8895,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; } Loading Loading @@ -9013,14 +9019,16 @@ bool JOIN::rollup_init() */ tmp_table_param.group_parts= send_group_parts; if (!(rollup.fields= (List<Item>*) thd->alloc((sizeof(Item*) + if (!(rollup.null_items= (Item_null_result**) thd->alloc((sizeof(Item*) + sizeof(Item**) + sizeof(List<Item>) + ref_pointer_array_size) * send_group_parts ))) return 1; rollup.fields= (List<Item>*) (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 Loading @@ -9028,12 +9036,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<Item> *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; } Loading Loading @@ -9137,7 +9149,8 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &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) { Loading @@ -9146,7 +9159,9 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &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; } } Loading Loading @@ -9206,6 +9221,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<Item> 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) Loading sql/sql_select.h +2 −1 Original line number Diff line number Diff line Loading @@ -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<Item> *fields; } ROLLUP; Loading Loading @@ -295,6 +295,7 @@ class JOIN :public Sql_alloc bool rollup_make_fields(List<Item> &all_fields, List<Item> &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(); Loading Loading
mysql-test/r/olap.result +72 −0 Original line number Diff line number Diff line Loading @@ -307,3 +307,75 @@ 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 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;
mysql-test/t/olap.test +30 −0 Original line number Diff line number Diff line Loading @@ -125,3 +125,33 @@ SELECT DROP TABLE user_day; # # Tests for bugs #8616, #8615: 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; 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;
sql/item.h +11 −0 Original line number Diff line number Diff line Loading @@ -470,6 +470,17 @@ class Item_null :public Item 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 */ Loading
sql/sql_select.cc +96 −29 Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, uint elements, List<Item> &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); Loading Loading @@ -1269,7 +1269,6 @@ JOIN::exec() { DBUG_VOID_RETURN; } curr_join->group_list= 0; } thd->proc_info="Copying to group table"; Loading @@ -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<Item> *) 0, curr_tmp_table, 1)) DBUG_VOID_RETURN; curr_join->group_list= 0; if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0))) { error= tmp_error; Loading Loading @@ -1328,7 +1329,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; Loading Loading @@ -6740,26 +6741,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()) { if ((error=table->file->write_row(table->record[0]))) 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 (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, error, 0)) DBUG_RETURN(-1); // Not a table_is_full error DBUG_RETURN(-1); } else join->send_records++; 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); } Loading Loading @@ -8888,11 +8895,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; } Loading Loading @@ -9013,14 +9019,16 @@ bool JOIN::rollup_init() */ tmp_table_param.group_parts= send_group_parts; if (!(rollup.fields= (List<Item>*) thd->alloc((sizeof(Item*) + if (!(rollup.null_items= (Item_null_result**) thd->alloc((sizeof(Item*) + sizeof(Item**) + sizeof(List<Item>) + ref_pointer_array_size) * send_group_parts ))) return 1; rollup.fields= (List<Item>*) (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 Loading @@ -9028,12 +9036,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<Item> *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; } Loading Loading @@ -9137,7 +9149,8 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &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) { Loading @@ -9146,7 +9159,9 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &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; } } Loading Loading @@ -9206,6 +9221,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<Item> 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) Loading
sql/sql_select.h +2 −1 Original line number Diff line number Diff line Loading @@ -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<Item> *fields; } ROLLUP; Loading Loading @@ -295,6 +295,7 @@ class JOIN :public Sql_alloc bool rollup_make_fields(List<Item> &all_fields, List<Item> &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(); Loading