diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 119 |
1 files changed, 92 insertions, 27 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b970c184489..1ada220b446 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -191,7 +191,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 setup_sum_funcs(THD *thd, Item_sum **func_ptr); static bool init_sum_functions(Item_sum **func, Item_sum **end); @@ -1386,7 +1386,6 @@ JOIN::exec() { DBUG_VOID_RETURN; } - curr_join->group_list= 0; } thd->proc_info="Copying to group table"; @@ -1447,7 +1446,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; @@ -10132,26 +10131,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); } @@ -12413,11 +12418,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; } @@ -12539,14 +12543,16 @@ bool JOIN::rollup_init() */ tmp_table_param.group_parts= send_group_parts; - if (!(rollup.fields= (List<Item>*) thd->alloc((sizeof(Item*) + - sizeof(List<Item>) + - ref_pointer_array_size) - * send_group_parts))) + 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 @@ -12554,12 +12560,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; } @@ -12663,7 +12673,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) { @@ -12672,7 +12683,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; } } @@ -12733,6 +12746,58 @@ int JOIN::rollup_send_data(uint idx) } /* + 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) |