From e62c8777484e647a481b99d8ff40238fbab417d3 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Mon, 29 Aug 2005 17:13:42 +0300 Subject: [PATCH] Fix for BUG#12672. --- mysql-test/r/group_min_max.result | 20 ++++++++++++++++ mysql-test/t/group_min_max.test | 19 +++++++++++++++ sql/opt_range.cc | 40 +++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 13eb2690e86..5b3e6f30710 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -1972,6 +1972,26 @@ a b c d +create table bug12672 ( +pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +) engine=innodb; +insert into bug12672 (a1, a2, b, c, d, dummy) select * from t1; +create index idx12672_0 on bug12672 (a1); +create index idx12672_1 on bug12672 (a1,a2,b,c); +create index idx12672_2 on bug12672 (a1,a2,b); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status Table is already up to date +explain select distinct a1 from bug12672 where pk_col not in (1,2,3,4); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE bug12672 range PRIMARY PRIMARY 4 NULL 93 Using where; Using temporary +select distinct a1 from bug12672 where pk_col not in (1,2,3,4); +a1 +a +b +c +d +drop table bug12672; drop table t1; drop table t2; drop table t3; diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index 6731be615fd..dd5f8b43248 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -651,6 +651,25 @@ select a1 from t1 where a2 = 'b' group by a1; explain select distinct a1 from t1 where a2 = 'b'; select distinct a1 from t1 where a2 = 'b'; +# +# Bug #12672: primary key implcitly included in every innodb index +# + +create table bug12672 ( + pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +) engine=innodb; + +insert into bug12672 (a1, a2, b, c, d, dummy) select * from t1; + +create index idx12672_0 on bug12672 (a1); +create index idx12672_1 on bug12672 (a1,a2,b,c); +create index idx12672_2 on bug12672 (a1,a2,b); +analyze table t1; + +explain select distinct a1 from bug12672 where pk_col not in (1,2,3,4); +select distinct a1 from bug12672 where pk_col not in (1,2,3,4); + +drop table bug12672; drop table t1; drop table t2; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index c1ebfe105b6..d0d06ea52b2 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7016,6 +7016,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) ha_rows cur_quick_prefix_records= 0; uint cur_param_idx; key_map cur_used_key_parts; + uint pk= param->table->s->primary_key; for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ; cur_index_info++, cur_index++) @@ -7024,6 +7025,45 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) if (!table->used_keys.is_set(cur_index)) goto next_index; + /* + If the current storage manager is such that it appends the primary key to + each index, then the above condition is insufficient to check if the + index is covering. In such cases it may happen that some fields are + covered by the PK index, but not by the current index. Since we can't + use the concatenation of both indexes for index lookup, such an index + does not qualify as covering in our case. If this is the case, below + we check that all query fields are indeed covered by 'cur_index'. + */ + if (pk < MAX_KEY && cur_index != pk && + (table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX)) + { + /* For each table field */ + for (uint i= 0; i < table->s->fields; i++) + { + Field *cur_field= table->field[i]; + /* + If the field is used in the current query, check that the + field is covered by some keypart of the current index. + */ + if (thd->query_id == cur_field->query_id) + { + bool is_covered= FALSE; + KEY_PART_INFO *key_part= cur_index_info->key_part; + KEY_PART_INFO *key_part_end= key_part + cur_index_info->key_parts; + for (; key_part != key_part_end ; key_part++) + { + if (key_part->field == cur_field) + { + is_covered= TRUE; + break; + } + } + if (!is_covered) + goto next_index; + } + } + } + /* Check (GA1) for GROUP BY queries. */