From 10fedf675a1de161aec4ee09026db35400344507 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 10 Jun 2011 10:14:20 +0200 Subject: [PATCH] change test_if_equality_guarantees_uniqueness() from an ad hoc set of limitations to a correct rule --- mysql-test/r/distinct.result | 26 ++++++++++++++++++++++++++ mysql-test/t/distinct.test | 19 +++++++++++++++++++ sql/sql_select.cc | 30 +++++++++++++----------------- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index fdd26d7e543..eafd16440b0 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -804,6 +804,32 @@ select distinct a from t1 where a = DATE('2010-10-10'); a 2010-10-10 20101010 +explain select distinct a from t1 where a = DATE('2010-10-10'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where; Using temporary +drop table t1; +# date = string +create table t1 (a date); +insert t1 values ('2010-10-10'), ('20101010'); +explain select distinct a from t1 where a = '2010-10-10'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +drop table t1; +# double = string +create table t1 (a double); +insert t1 values (2), (2); +explain select distinct a from t1 where a = '2'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +# double = int +explain select distinct a from t1 where a = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +# string = double +alter table t1 modify a varchar(100); +explain select distinct a from t1 where a = 2e0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where; Using temporary drop table t1; create table t1 (f1 varchar(40)); insert into t1 values ('2010-10-10 00:00:00.0001'),('2010-10-10 00:00:00.0002'),('2010-10-10 00:00:00.0003'); diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index 89d3f85a38d..796732fa097 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -622,6 +622,25 @@ create table t1 (a varchar(100)); insert t1 values ('2010-10-10'), ('20101010'); select * from t1 where a = DATE('2010-10-10'); select distinct a from t1 where a = DATE('2010-10-10'); +explain select distinct a from t1 where a = DATE('2010-10-10'); +drop table t1; +# +# test_if_equality_guarantees_uniqueness() and different type combinations +# +--echo # date = string +create table t1 (a date); +insert t1 values ('2010-10-10'), ('20101010'); +explain select distinct a from t1 where a = '2010-10-10'; +drop table t1; +--echo # double = string +create table t1 (a double); +insert t1 values (2), (2); +explain select distinct a from t1 where a = '2'; +--echo # double = int +explain select distinct a from t1 where a = 2; +--echo # string = double +alter table t1 modify a varchar(100); +explain select distinct a from t1 where a = 2e0; drop table t1; # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b00923949bb..b8b0e4fa2f0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12171,16 +12171,16 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) Checks if an equality predicate can be used to take away DISTINCT/GROUP BY because it is known to be true for exactly one distinct value (e.g. == ). - Arguments must be of the same type because e.g. - = may match more than 1 distinct value from - the column. - Additionally, strings must have the same collation. - Or the *field* must be a datetime - if the constant is a datetime - and a field is not - this is not enough, consider: - create table t1 (a varchar(100)); - insert t1 values ('2010-01-02'), ('2010-1-2'), ('20100102'); - select distinct t1 from t1 where a=date('2010-01-02'); - + Arguments must be compared in the native type of the left argument + and (for strings) in the native collation of the left argument. + Otherwise, for example, + = may match more than 1 distinct value or + the . + + @note We don't need to aggregate l and r collations here, because r - + the constant item - has already been converted to a proper collation + for comparison. We only need to compare this collation with field's collation. + @retval true can be used @retval false cannot be used */ @@ -12188,13 +12188,9 @@ static bool test_if_equality_guarantees_uniqueness(Item *l, Item *r) { return r->const_item() && - /* the field is a date (the const will be converted to a date) */ - (l->cmp_type() == TIME_RESULT || - /* or arguments are of the same result type */ - (r->result_type() == l->result_type() && - /* and must have the same collation if compared as strings */ - (l->result_type() != STRING_RESULT || - l->collation.collation == r->collation.collation))); + item_cmp_type(l->cmp_type(), r->cmp_type()) == l->cmp_type() && + (l->cmp_type() != STRING_RESULT || + l->collation.collation == r->collation.collation); } /**