Commit 4b93aa6a authored by MySQL Build Team's avatar MySQL Build Team

Backport into build-200911241145-5.1.40sp1

> ------------------------------------------------------------
> revno: 1810.3964.1
> revision-id: alexey.kopytov@sun.com-20091030155453-0vlfwki805h9os62
> parent: joerg@mysql.com-20091016122941-rf6z0keqvmlgjfto
> committer: Alexey Kopytov <Alexey.Kopytov@Sun.com>
> branch nick: my50-bug48131
> timestamp: Fri 2009-10-30 18:54:53 +0300
> message:
>   Bug #48131: crash group by with rollup, distinct, filesort,
>               with temporary tables
>   
>   There were two problems the test case from this bug was
>   triggering:
>   
>   1. JOIN::rollup_init() was supposed to wrap all constant Items
>   into another object for queries with the WITH ROLLUP modifier
>   to ensure they are never considered as constants and therefore
>   are written into temporary tables if the optimizer chooses to
>   employ them for DISTINCT/GROUP BY handling.
>   
>   However, JOIN::rollup_init() was called before
>   make_join_statistics(), so Items corresponding to fields in
>   const tables could not be handled as intended, which was
>   causing all kinds of problems later in the query execution. In
>   particular, create_tmp_table() assumed all constant items
>   except "hidden" ones to be removed earlier by remove_const()
>   which led to improperly initialized Field objects for the
>   temporary table being created. This is what was causing crashes
>   and valgrind errors in storage engines.
>   
>   2. Even when the above problem had been fixed, the query from
>   the test case produced incorrect results due to some
>   DISTINCT/GROUP BY optimizations being performed by the
>   optimizer that are inapplicable in the WITH ROLLUP case.
>   
>   Fixed by disabling inapplicable DISTINCT/GROUP BY optimizations
>   when the WITH ROLLUP modifier is present, and splitting the
>   const-wrapping part of JOIN::rollup_init() into a separate
>   method which is now invoked after make_join_statistics() when
>   the const tables are already known.
parent c14bf1ca
...@@ -733,4 +733,24 @@ SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP; ...@@ -733,4 +733,24 @@ SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP;
1 1
1 1
DROP TABLE t1; DROP TABLE t1;
#
# Bug #48131: crash group by with rollup, distinct,
# filesort, with temporary tables
#
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY);
INSERT INTO t1 VALUES (1), (2);
CREATE TABLE t2 (b INT);
INSERT INTO t2 VALUES (100);
SELECT a, b FROM t1, t2 GROUP BY a, b WITH ROLLUP;
a b
1 100
1 NULL
2 100
2 NULL
NULL NULL
SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP;
b
100
NULL
DROP TABLE t1, t2;
End of 5.0 tests End of 5.0 tests
...@@ -375,4 +375,19 @@ INSERT INTO t1 VALUES(0); ...@@ -375,4 +375,19 @@ INSERT INTO t1 VALUES(0);
SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP; SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # Bug #48131: crash group by with rollup, distinct,
--echo # filesort, with temporary tables
--echo #
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY);
INSERT INTO t1 VALUES (1), (2);
CREATE TABLE t2 (b INT);
INSERT INTO t2 VALUES (100);
SELECT a, b FROM t1, t2 GROUP BY a, b WITH ROLLUP;
SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP;
DROP TABLE t1, t2;
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -970,6 +970,12 @@ JOIN::optimize() ...@@ -970,6 +970,12 @@ JOIN::optimize()
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (select_lex->olap == ROLLUP_TYPE && rollup_process_const_fields())
{
DBUG_PRINT("error", ("Error: rollup_process_fields() failed"));
DBUG_RETURN(1);
}
/* Remove distinct if only const tables */ /* Remove distinct if only const tables */
select_distinct= select_distinct && (const_tables != tables); select_distinct= select_distinct && (const_tables != tables);
thd_proc_info(thd, "preparing"); thd_proc_info(thd, "preparing");
...@@ -1100,7 +1106,7 @@ JOIN::optimize() ...@@ -1100,7 +1106,7 @@ JOIN::optimize()
join_tab[const_tables].select->quick->get_type() != join_tab[const_tables].select->quick->get_type() !=
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)) QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX))
{ {
if (group_list && if (group_list && rollup.state == ROLLUP::STATE_NONE &&
list_contains_unique_index(join_tab[const_tables].table, list_contains_unique_index(join_tab[const_tables].table,
find_field_in_order_list, find_field_in_order_list,
(void *) group_list)) (void *) group_list))
...@@ -1144,7 +1150,8 @@ JOIN::optimize() ...@@ -1144,7 +1150,8 @@ JOIN::optimize()
if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE) if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE)
select_distinct=0; select_distinct=0;
} }
else if (select_distinct && tables - const_tables == 1) else if (select_distinct && tables - const_tables == 1 &&
rollup.state == ROLLUP::STATE_NONE)
{ {
/* /*
We are only using one table. In this case we change DISTINCT to a We are only using one table. In this case we change DISTINCT to a
...@@ -10203,6 +10210,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -10203,6 +10210,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
for (; cur_group ; cur_group= cur_group->next, key_part_info++) for (; cur_group ; cur_group= cur_group->next, key_part_info++)
{ {
Field *field=(*cur_group->item)->get_tmp_table_field(); Field *field=(*cur_group->item)->get_tmp_table_field();
DBUG_ASSERT(field->table == table);
bool maybe_null=(*cur_group->item)->maybe_null; bool maybe_null=(*cur_group->item)->maybe_null;
key_part_info->null_bit=0; key_part_info->null_bit=0;
key_part_info->field= field; key_part_info->field= field;
...@@ -15622,32 +15630,7 @@ bool JOIN::rollup_init() ...@@ -15622,32 +15630,7 @@ bool JOIN::rollup_init()
{ {
item->maybe_null= 1; item->maybe_null= 1;
found_in_group= 1; found_in_group= 1;
if (item->const_item()) break;
{
/*
For ROLLUP queries each constant item referenced in GROUP BY list
is wrapped up into an Item_func object yielding the same value
as the constant item. The objects of the wrapper class are never
considered as constant items and besides they inherit all
properties of the Item_result_field class.
This wrapping allows us to ensure writing constant items
into temporary tables whenever the result of the ROLLUP
operation has to be written into a temporary table, e.g. when
ROLLUP is used together with DISTINCT in the SELECT list.
Usually when creating temporary tables for a intermidiate
result we do not include fields for constant expressions.
*/
Item* new_item= new Item_func_rollup_const(item);
if (!new_item)
return 1;
new_item->fix_fields(thd, (Item **) 0);
thd->change_item_tree(it.ref(), new_item);
for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next)
{
if (*tmp->item == item)
thd->change_item_tree(tmp->item, new_item);
}
}
} }
} }
if (item->type() == Item::FUNC_ITEM && !found_in_group) if (item->type() == Item::FUNC_ITEM && !found_in_group)
...@@ -15666,6 +15649,59 @@ bool JOIN::rollup_init() ...@@ -15666,6 +15649,59 @@ bool JOIN::rollup_init()
} }
return 0; return 0;
} }
/**
Wrap all constant Items in GROUP BY list.
For ROLLUP queries each constant item referenced in GROUP BY list
is wrapped up into an Item_func object yielding the same value
as the constant item. The objects of the wrapper class are never
considered as constant items and besides they inherit all
properties of the Item_result_field class.
This wrapping allows us to ensure writing constant items
into temporary tables whenever the result of the ROLLUP
operation has to be written into a temporary table, e.g. when
ROLLUP is used together with DISTINCT in the SELECT list.
Usually when creating temporary tables for a intermidiate
result we do not include fields for constant expressions.
@retval
0 if ok
@retval
1 on error
*/
bool JOIN::rollup_process_const_fields()
{
ORDER *group_tmp;
Item *item;
List_iterator<Item> it(all_fields);
for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next)
{
if (!(*group_tmp->item)->const_item())
continue;
while ((item= it++))
{
if (*group_tmp->item == item)
{
Item* new_item= new Item_func_rollup_const(item);
if (!new_item)
return 1;
new_item->fix_fields(thd, (Item **) 0);
thd->change_item_tree(it.ref(), new_item);
for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next)
{
if (*tmp->item == item)
thd->change_item_tree(tmp->item, new_item);
}
break;
}
}
it.rewind();
}
return 0;
}
/** /**
......
...@@ -502,6 +502,7 @@ class JOIN :public Sql_alloc ...@@ -502,6 +502,7 @@ class JOIN :public Sql_alloc
} }
bool rollup_init(); bool rollup_init();
bool rollup_process_const_fields();
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);
......
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