summaryrefslogtreecommitdiff
path: root/sql/item.h
diff options
context:
space:
mode:
authorGleb Shchepa <gshchepa@mysql.com>2010-02-06 23:54:30 +0400
committerGleb Shchepa <gshchepa@mysql.com>2010-02-06 23:54:30 +0400
commit994c0f83083ceee30430f28b8f1ced9b71944dbb (patch)
treebf8b15b6dfd85b7aed65d198e3d7eda5626b83d8 /sql/item.h
parent3ad5d21ebc981a0b8c59597f0f1a306f3c9d6bf2 (diff)
downloadmariadb-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.h6
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()
{