diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index b1703c51f4e..8ab69dee77d 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -1954,6 +1954,15 @@ id select_type table type possible_keys key key_len ref rows Extra explain select sum(ord(a1)) from t1 where (a1 > 'a') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 163 NULL 128 Using where; Using index +explain select distinct(a1) from t1 where ord(a2) = 98; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index +select distinct(a1) from t1 where ord(a2) = 98; +a1 +a +b +c +d explain select a1 from t1 where a2 = 'b' group by a1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 130 NULL 5 Using where; Using index for group-by diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index 8dc55532bbf..69c5d58b409 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -641,6 +641,14 @@ explain select a1,a2,count(a2) from t1 group by a1,a2,b; explain select a1,a2,count(a2) from t1 where (a1 > 'a') group by a1,a2,b; explain select sum(ord(a1)) from t1 where (a1 > 'a') group by a1,a2,b; + +# +# Bug #16710: select distinct doesn't return all it should +# + +explain select distinct(a1) from t1 where ord(a2) = 98; +select distinct(a1) from t1 where ord(a2) = 98; + # # BUG#11044: DISTINCT or GROUP BY queries with equality predicates instead of MIN/MAX. # diff --git a/sql/item.cc b/sql/item.cc index 70fea63ba7e..e8cfab34d54 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -499,7 +499,7 @@ bool Item_ident::remove_dependence_processor(byte * arg) arguments in a condition the method must return false. RETURN - false to force the evaluation of collect_item_field_processor + FALSE to force the evaluation of collect_item_field_processor for the subsequent items. */ @@ -520,6 +520,38 @@ bool Item_field::collect_item_field_processor(byte *arg) } +/* + Check if an Item_field references some field from a list of fields. + + SYNOPSIS + Item_field::find_item_in_field_list_processor + arg Field being compared, arg must be of type Field + + DESCRIPTION + Check whether the Item_field represented by 'this' references any + of the fields in the keyparts passed via 'arg'. Used with the + method Item::walk() to test whether any keypart in a sequence of + keyparts is referenced in an expression. + + RETURN + TRUE if 'this' references the field 'arg' + FALE otherwise +*/ +bool Item_field::find_item_in_field_list_processor(byte *arg) +{ + KEY_PART_INFO *first_non_group_part= *((KEY_PART_INFO **) arg); + KEY_PART_INFO *last_part= *(((KEY_PART_INFO **) arg) + 1); + KEY_PART_INFO *cur_part; + + for (cur_part= first_non_group_part; cur_part != last_part; cur_part++) + { + if (field->eq(cur_part->field)) + return TRUE; + } + return FALSE; +} + + bool Item::check_cols(uint c) { if (c != 1) diff --git a/sql/item.h b/sql/item.h index af42ce38b9b..5924db8865c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -699,6 +699,7 @@ public: virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; } virtual bool cleanup_processor(byte *arg); virtual bool collect_item_field_processor(byte * arg) { return 0; } + virtual bool find_item_in_field_list_processor(byte *arg) { return 0; } virtual bool change_context_processor(byte *context) { return 0; } virtual bool reset_query_id_processor(byte *query_id) { return 0; } @@ -1146,6 +1147,7 @@ public: bool is_null() { return field->is_null(); } Item *get_tmp_table_item(THD *thd); bool collect_item_field_processor(byte * arg); + bool find_item_in_field_list_processor(byte *arg); bool reset_query_id_processor(byte *arg) { field->query_id= *((query_id_t *) arg); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 1b712700b18..da4b1288faf 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -6876,6 +6876,7 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts, bool have_min, bool have_max, double *read_cost, ha_rows *records); + /* Test if this access method is applicable to a GROUP query with MIN/MAX functions, and if so, construct a new TRP object. @@ -7282,11 +7283,36 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) } else if (min_max_arg_part && (min_max_arg_part - first_non_group_part > 0)) + { /* There is a gap but no range tree, thus no predicates at all for the non-group keyparts. */ goto next_index; + } + else if (first_non_group_part && join->conds) + { + /* + If there is no MIN/MAX function in the query, but some index + key part is referenced in the WHERE clause, then this index + cannot be used because the WHERE condition over the keypart's + field cannot be 'pushed' to the index (because there is no + range 'tree'), and the WHERE clause must be evaluated before + GROUP BY/DISTINCT. + */ + /* + Store the first and last keyparts that need to be analyzed + into one array that can be passed as parameter. + */ + KEY_PART_INFO *key_part_range[2]; + key_part_range[0]= first_non_group_part; + key_part_range[1]= last_part; + + /* Check if cur_part is referenced in the WHERE clause. */ + if (join->conds->walk(&Item::find_item_in_field_list_processor, + (byte*) key_part_range)) + goto next_index; + } } /*