diff options
author | Gleb Shchepa <gshchepa@mysql.com> | 2010-02-06 23:54:30 +0400 |
---|---|---|
committer | Gleb Shchepa <gshchepa@mysql.com> | 2010-02-06 23:54:30 +0400 |
commit | 994c0f83083ceee30430f28b8f1ced9b71944dbb (patch) | |
tree | bf8b15b6dfd85b7aed65d198e3d7eda5626b83d8 /sql/item.h | |
parent | 3ad5d21ebc981a0b8c59597f0f1a306f3c9d6bf2 (diff) | |
download | mariadb-git-994c0f83083ceee30430f28b8f1ced9b71944dbb.tar.gz |
Bug #45640: optimizer bug produces wrong results
Grouping by a subquery in a query with a distinct aggregate
function lead to a wrong result (wrong and unordered
grouping values).
There are two related problems:
1) The query like this:
SELECT (SELECT t1.a) aa, COUNT(DISTINCT b) c
FROM t1 GROUP BY aa
returned wrong result, because the outer reference "t1.a"
in the subquery was substituted with the Item_ref item.
The Item_ref item obtains data from the result_field object
that refreshes once after the end of each group. This data
is not applicable to filesort since filesort() doesn't care
about groups (and doesn't update result_field objects with
copy_fields() and so on). Also that data is not applicable
to group separation algorithm: end_send_group() checks every
record with test_if_group_changed() that evaluates Item_ref
items, but it refreshes those Item_ref-s only after the end
of group, that is a vicious circle and the grouped column
values in the output are shifted.
Fix: if
a) we grouping by a subquery and
b) that subquery has outer references to FROM list
of the grouping query,
then we substitute these outer references with
Item_direct_ref like references under aggregate
functions: Item_direct_ref obtains data directly
from the current record.
2) The query with a non-trivial grouping expression like:
SELECT (SELECT t1.a) aa, COUNT(DISTINCT b) c
FROM t1 GROUP BY aa+0
also returned wrong result, since JOIN::exec() substitutes
references to top-level aliases in SELECT list with Item_copy
caching items. Item_copy items have same refreshing policy
as Item_ref items, so the whole groping expression with
Item_copy inside returns wrong result in filesort() and
end_send_group().
Fix: include aliased items into GROUP BY item tree instead
of Item_ref references to them.
mysql-test/r/group_by.result:
Test case for bug #45640
mysql-test/t/group_by.test:
Test case for bug #45640
sql/item.cc:
Bug #45640: optimizer bug produces wrong results
Item_field::fix_fields() has been modified to resolve
aliases in GROUP BY item trees into aliased items instead
of Item_ref items.
sql/item.h:
Bug #45640: optimizer bug produces wrong results
- Item::find_item_processor() has been introduced.
- Item_ref::walk() has been modified to apply processors
to itself too (not only to referenced item).
sql/mysql_priv.h:
Bug #45640: optimizer bug produces wrong results
fix_inner_refs() has been modified to accept group_list
parameter.
sql/sql_lex.cc:
Bug #45640: optimizer bug produces wrong results
Initialization of st_select_lex::group_fix_field has
been added.
sql/sql_lex.h:
Bug #45640: optimizer bug produces wrong results
The st_select_lex::group_fix_field field has been introduced
to control alias resolution in Itef_fied::fix_fields.
sql/sql_select.cc:
Bug #45640: optimizer bug produces wrong results
- The fix_inner_refs function has been modified to treat
subquery outer references like outer fields under aggregate
functions, if they are included in GROUP BY item tree.
- The find_order_in_list function has been modified to
fix Item_field alias fields included in the GROUP BY item
trees in a special manner.
Diffstat (limited to 'sql/item.h')
-rw-r--r-- | sql/item.h | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/sql/item.h b/sql/item.h index 88e90924fcc..d2e8382023b 100644 --- a/sql/item.h +++ b/sql/item.h @@ -901,6 +901,7 @@ public: virtual bool change_context_processor(uchar *context) { return 0; } virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; } virtual bool is_expensive_processor(uchar *arg) { return 0; } + virtual bool find_item_processor(uchar *arg) { return this == (void *) arg; } virtual bool register_field_in_read_map(uchar *arg) { return 0; } /* Check if a partition function is allowed @@ -2275,7 +2276,10 @@ public: return ref ? (*ref)->real_item() : this; } bool walk(Item_processor processor, bool walk_subquery, uchar *arg) - { return (*ref)->walk(processor, walk_subquery, arg); } + { + return (*ref)->walk(processor, walk_subquery, arg) || + (this->*processor)(arg); + } virtual void print(String *str, enum_query_type query_type); bool result_as_longlong() { |