diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index b889d0310797cba3ad85717d8021ed99fe2448c8..6370f7699b3e375a1d8508dbbe3a24d212d50df8 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 0f0a632ff670152e864dde2554a23f7e6d129d97..bff07366ec2e7e00d70250d0a7a0252b0e92842b 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 885617669a97c30bee75605e09cf0470b550dfc3..466216ffb78a84823974bacbd622020928ea6ea1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -496,7 +496,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. */ @@ -517,6 +517,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 b9ce418858c7ca1d4cb08fb85a002de5f18fe72f..6c7a0976df1bc25a8cae27583839368509611752 100644 --- a/sql/item.h +++ b/sql/item.h @@ -741,6 +741,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; } @@ -1193,6 +1194,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 4ffce67638d724e2298aa4805198cd3a4aeaedd0..7f93327f68a71008565b6499d466ca4e38c3b1fc 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -8189,6 +8189,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. @@ -8595,11 +8596,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; + } } /*