Commit 3103b4ca authored by igor@rurik.mysql.com's avatar igor@rurik.mysql.com

Merge rurik.mysql.com:/home/igor/mysql-4.1

into rurik.mysql.com:/home/igor/dev/mysql-4.1-0
parents 155f8ff8 45ba1388
...@@ -307,3 +307,75 @@ day sample not_cancelled ...@@ -307,3 +307,75 @@ day sample not_cancelled
2004-06-07 1 0 2004-06-07 1 0
NULL 3 1 NULL 3 1
DROP TABLE user_day; 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;
...@@ -125,3 +125,33 @@ SELECT ...@@ -125,3 +125,33 @@ SELECT
DROP TABLE user_day; 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;
...@@ -470,6 +470,17 @@ public: ...@@ -470,6 +470,17 @@ public:
Item *safe_charset_converter(CHARSET_INFO *tocs); 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 */ /* Item represents one placeholder ('?') of prepared statement */
......
...@@ -157,7 +157,7 @@ static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, ...@@ -157,7 +157,7 @@ static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array,
uint elements, List<Item> &items); uint elements, List<Item> &items);
static void init_tmptable_sum_functions(Item_sum **func); static void init_tmptable_sum_functions(Item_sum **func);
static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table); 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 add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static bool init_sum_functions(Item_sum **func, Item_sum **end); static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func); static bool update_sum_func(Item_sum **func);
...@@ -1269,7 +1269,6 @@ JOIN::exec() ...@@ -1269,7 +1269,6 @@ JOIN::exec()
{ {
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
curr_join->group_list= 0;
} }
thd->proc_info="Copying to group table"; thd->proc_info="Copying to group table";
...@@ -1289,8 +1288,10 @@ JOIN::exec() ...@@ -1289,8 +1288,10 @@ JOIN::exec()
} }
} }
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
1) || 1))
(tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, DBUG_VOID_RETURN;
curr_join->group_list= 0;
if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table,
0))) 0)))
{ {
error= tmp_error; error= tmp_error;
...@@ -1328,7 +1329,7 @@ JOIN::exec() ...@@ -1328,7 +1329,7 @@ JOIN::exec()
if (curr_join->tmp_having) if (curr_join->tmp_having)
curr_join->tmp_having->update_used_tables(); curr_join->tmp_having->update_used_tables();
if (remove_duplicates(curr_join, curr_tmp_table, 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; DBUG_VOID_RETURN;
curr_join->tmp_having=0; curr_join->tmp_having=0;
curr_join->select_distinct=0; curr_join->select_distinct=0;
...@@ -6740,26 +6741,32 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), ...@@ -6740,26 +6741,32 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{ {
if (join->procedure) if (join->procedure)
join->procedure->end_group(); 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) if (!join->first_record)
{ {
/* No matching rows for group function */ /* No matching rows for group function */
join->clear(); join->clear();
} }
copy_sum_funcs(join->sum_funcs); copy_sum_funcs(join->sum_funcs,
if (!join->having || join->having->val_int()) 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,
if (create_myisam_from_heap(join->thd, table, error, 0))
&join->tmp_table_param, DBUG_RETURN(-1);
error, 0)) }
DBUG_RETURN(-1); // Not a table_is_full error if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0)
} {
else if (join->rollup_write_data((uint) (idx+1), table))
join->send_records++; error= 1;
} }
if (error > 0)
DBUG_RETURN(-1);
if (end_of_records) if (end_of_records)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -8888,11 +8895,10 @@ update_tmptable_sum_func(Item_sum **func_ptr, ...@@ -8888,11 +8895,10 @@ update_tmptable_sum_func(Item_sum **func_ptr,
/* Copy result of sum functions to record in tmp_table */ /* Copy result of sum functions to record in tmp_table */
static void 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_ptr != end_ptr ; func_ptr++)
for (; (func = *func_ptr) ; func_ptr++) (void) (*func_ptr)->save_in_result_field(1);
(void) func->save_in_result_field(1);
return; return;
} }
...@@ -9013,14 +9019,16 @@ bool JOIN::rollup_init() ...@@ -9013,14 +9019,16 @@ bool JOIN::rollup_init()
*/ */
tmp_table_param.group_parts= send_group_parts; 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(List<Item>) + sizeof(Item**) +
ref_pointer_array_size) sizeof(List<Item>) +
* send_group_parts))) ref_pointer_array_size)
* send_group_parts )))
return 1; return 1;
rollup.fields= (List<Item>*) (rollup.null_items + send_group_parts);
rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts); rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts);
ref_array= (Item**) (rollup.ref_pointer_arrays+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 Prepare space for field list for the different levels
...@@ -9028,12 +9036,16 @@ bool JOIN::rollup_init() ...@@ -9028,12 +9036,16 @@ bool JOIN::rollup_init()
*/ */
for (i= 0 ; i < send_group_parts ; i++) 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]; List<Item> *rollup_fields= &rollup.fields[i];
rollup_fields->empty(); rollup_fields->empty();
rollup.ref_pointer_arrays[i]= ref_array; rollup.ref_pointer_arrays[i]= ref_array;
ref_array+= all_fields.elements; ref_array+= all_fields.elements;
}
for (i= 0 ; i < send_group_parts; i++)
{
for (j=0 ; j < fields_list.elements ; j++) 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; return 0;
} }
...@@ -9137,7 +9149,8 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &sel_fields, ...@@ -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 */ /* Check if this is something that is part of this group by */
ORDER *group_tmp; 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) if (*group_tmp->item == item)
{ {
...@@ -9146,7 +9159,9 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &sel_fields, ...@@ -9146,7 +9159,9 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &sel_fields,
set to NULL in this level set to NULL in this level
*/ */
item->maybe_null= 1; // Value will be null sometimes 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; break;
} }
} }
...@@ -9206,6 +9221,58 @@ int JOIN::rollup_send_data(uint idx) ...@@ -9206,6 +9221,58 @@ int JOIN::rollup_send_data(uint idx)
return 0; 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 clear results if there are not rows found for group
(end_send_group/end_write_group) (end_send_group/end_write_group)
......
...@@ -124,7 +124,7 @@ typedef struct st_rollup ...@@ -124,7 +124,7 @@ typedef struct st_rollup
{ {
enum State { STATE_NONE, STATE_INITED, STATE_READY }; enum State { STATE_NONE, STATE_INITED, STATE_READY };
State state; State state;
Item *item_null; Item_null_result **null_items;
Item ***ref_pointer_arrays; Item ***ref_pointer_arrays;
List<Item> *fields; List<Item> *fields;
} ROLLUP; } ROLLUP;
...@@ -295,6 +295,7 @@ class JOIN :public Sql_alloc ...@@ -295,6 +295,7 @@ class JOIN :public Sql_alloc
bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields, bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
Item_sum ***func); Item_sum ***func);
int rollup_send_data(uint idx); int rollup_send_data(uint idx);
int rollup_write_data(uint idx, TABLE *table);
bool test_in_subselect(Item **where); bool test_in_subselect(Item **where);
void join_free(bool full); void join_free(bool full);
void clear(); void clear();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment