diff --git a/mysql-test/include/world_schema.inc b/mysql-test/include/world_schema.inc index c683faf0114..bd7b768e83b 100644 --- a/mysql-test/include/world_schema.inc +++ b/mysql-test/include/world_schema.inc @@ -6,7 +6,7 @@ CREATE TABLE Country ( Capital int(11) default NULL, PRIMARY KEY (Code), UNIQUE INDEX (Name) -); +) COLLATE latin1_bin; CREATE TABLE City ( ID int(11) NOT NULL auto_increment, Name char(35) NOT NULL default '', @@ -15,11 +15,11 @@ CREATE TABLE City ( PRIMARY KEY (ID), INDEX (Population), INDEX (Country) -); +) COLLATE latin1_bin; CREATE TABLE CountryLanguage ( Country char(3) NOT NULL default '', Language char(30) NOT NULL default '', Percentage float(3,1) NOT NULL default '0.0', PRIMARY KEY (Country, Language), INDEX (Percentage) -); +) COLLATE latin1_bin; diff --git a/mysql-test/include/world_schema1.inc b/mysql-test/include/world_schema1.inc index 172e79a7c8c..48448b5c1d8 100644 --- a/mysql-test/include/world_schema1.inc +++ b/mysql-test/include/world_schema1.inc @@ -4,15 +4,15 @@ CREATE TABLE Country ( SurfaceArea float(10,2) NOT NULL default '0.00', Population int(11) NOT NULL default '0', Capital int(11) default NULL -); +) COLLATE latin1_bin; CREATE TABLE City ( ID int(11) NOT NULL, Name char(35) NOT NULL default '', Country char(3) NOT NULL default '', Population int(11) NOT NULL default '0' -); +) COLLATE latin1_bin; CREATE TABLE CountryLanguage ( Country char(3) NOT NULL default '', Language char(30) NOT NULL default '', Percentage float(3,1) NOT NULL default '0.0' -); +) COLLATE latin1_bin; diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index e0543fd085b..3c352386b8a 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -12,18 +12,18 @@ Name char(52) NOT NULL default '', SurfaceArea float(10,2) NOT NULL default '0.00', Population int(11) NOT NULL default '0', Capital int(11) default NULL -); +) COLLATE latin1_bin; CREATE TABLE City ( ID int(11) NOT NULL, Name char(35) NOT NULL default '', Country char(3) NOT NULL default '', Population int(11) NOT NULL default '0' -); +) COLLATE latin1_bin; CREATE TABLE CountryLanguage ( Country char(3) NOT NULL default '', Language char(30) NOT NULL default '', Percentage float(3,1) NOT NULL default '0.0' -); +) COLLATE latin1_bin; SELECT COUNT(*) FROM Country; COUNT(*) 239 @@ -810,7 +810,7 @@ Population int(11) NOT NULL default '0', Capital int(11) default NULL, PRIMARY KEY (Code), UNIQUE INDEX (Name) -); +) COLLATE latin1_bin; CREATE TABLE City ( ID int(11) NOT NULL auto_increment, Name char(35) NOT NULL default '', @@ -819,14 +819,14 @@ Population int(11) NOT NULL default '0', PRIMARY KEY (ID), INDEX (Population), INDEX (Country) -); +) COLLATE latin1_bin; CREATE TABLE CountryLanguage ( Country char(3) NOT NULL default '', Language char(30) NOT NULL default '', Percentage float(3,1) NOT NULL default '0.0', PRIMARY KEY (Country, Language), INDEX (Percentage) -); +) COLLATE latin1_bin; show variables like 'join_buffer_size'; Variable_name Value join_buffer_size 131072 @@ -5469,7 +5469,7 @@ SET SESSION join_buffer_size=DEFAULT; CREATE TABLE t1 ( pk int NOT NULL, i int NOT NULL, v varchar(1) NOT NULL, PRIMARY KEY (pk), INDEX idx1(i), INDEX idx2 (v,i) -); +) COLLATE latin1_bin; INSERT INTO t1 VALUES (10,8,'v'), (11,8,'f'), (12,5,'v'), (13,8,'s'), (14,8,'a'), (15,6,'p'), (16,7,'z'), (17,2,'a'), (18,5,'h'), (19,7,'h'), @@ -5477,16 +5477,16 @@ INSERT INTO t1 VALUES CREATE TABLE t2 ( pk int NOT NULL, i int NOT NULL, v varchar(1) NOT NULL, PRIMARY KEY (pk), INDEX idx1(i), INDEX idx2(v,i) -); +) COLLATE latin1_bin; INSERT INTO t2 VALUES (10,8,'v'), (11,8,'f'), (12,5,'v'), (13,8,'s'), (14,8,'a'), (15,6,'p'), (16,7,'z'), (17,2,'a'), (18,5,'h'), (19,7,'h'), (20,2,'v'), (21,9,'v'), (22,142,'b'), (23,3,'y'), (24,0,'v'), (25,3,'m'), (26,5,'z'), (27,9,'n'), (28,1,'d'), (29,107,'a'); CREATE TABLE t3 ( -pk int NOT NULL, i int(11) NOT NULL, v varchar(1) NOT NULL, +pk int NOT NULL, i int NOT NULL, v varchar(1) NOT NULL, PRIMARY KEY (pk), INDEX idx1(i), INDEX idx2(v,i) -); +) COLLATE latin1_bin; INSERT INTO t3 VALUES (1,9,'x'), (2,5,'g'), (3,1,'o'), (4,0,'g'), (5,1,'v'), (6,190,'m'), (7,6,'x'), (8,3,'c'), (9,4,'z'), (10,3,'i'), @@ -5542,4 +5542,51 @@ v p DROP TABLE t1,t2,t3; SET SESSION join_cache_level=DEFAULT; +# +# Bug #668290: hash join with non-binary collations +# +CREATE TABLE t1 ( +i int DEFAULT NULL, +cl varchar(10) CHARACTER SET latin1 DEFAULT NULL, +cu varchar(10) CHARACTER SET utf8 DEFAULT NULL, +INDEX cl (cl), +INDEX cu (cu) +); +INSERT INTO t1 VALUES +(650903552,'cmxffkpsel','z'), (535298048,'tvtjrcmxff','y'), +(1626865664,'when','for'), (39649280,'rcvljitvtj','ercvljitvt'), +(792068096,'ttercvljit','jttercvlji'); +INSERT INTO t1 SELECT * FROM t1; +CREATE TABLE t2 ( +cu varchar(10) CHARACTER SET utf8 DEFAULT NULL, +i int DEFAULT NULL, +cl varchar(10) CHARACTER SET latin1 DEFAULT NULL, +INDEX cu (cu), +INDEX cl (cl) +); +INSERT INTO t2 VALUES +('g',7,'like'), ('fujttercvl',6,'y'), +('s',2,'e'), ('didn\'t',0,'v'), + ('gvdrodpedk',8,'chogvdrodp'), ('jichogvdro',7,'will'); +EXPLAIN +SELECT t2.i FROM t1,t2 WHERE t1.cu = t2.cl ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t1 ref cu cu 33 func 2 Using where; Using index +SELECT t2.i FROM t1,t2 WHERE t1.cu = t2.cl ; +i +6 +6 +SET SESSION join_cache_level = 4; +EXPLAIN +SELECT t2.i FROM t1,t2 WHERE t1.cu = t2.cl ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t1 ref cu cu 33 func 2 Using where; Using index +SELECT t2.i FROM t1,t2 WHERE t1.cu = t2.cl ; +i +6 +6 +SET SESSION join_cache_level = DEFAULT; +DROP TABLE t1,t2; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index 010abed3c2b..48a2cd1d4a8 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -2192,7 +2192,7 @@ SET SESSION join_buffer_size=DEFAULT; CREATE TABLE t1 ( pk int NOT NULL, i int NOT NULL, v varchar(1) NOT NULL, PRIMARY KEY (pk), INDEX idx1(i), INDEX idx2 (v,i) -); +) COLLATE latin1_bin; INSERT INTO t1 VALUES (10,8,'v'), (11,8,'f'), (12,5,'v'), (13,8,'s'), (14,8,'a'), (15,6,'p'), (16,7,'z'), (17,2,'a'), (18,5,'h'), (19,7,'h'), @@ -2201,7 +2201,7 @@ INSERT INTO t1 VALUES CREATE TABLE t2 ( pk int NOT NULL, i int NOT NULL, v varchar(1) NOT NULL, PRIMARY KEY (pk), INDEX idx1(i), INDEX idx2(v,i) -); +) COLLATE latin1_bin; INSERT INTO t2 VALUES (10,8,'v'), (11,8,'f'), (12,5,'v'), (13,8,'s'), (14,8,'a'), (15,6,'p'), (16,7,'z'), (17,2,'a'), (18,5,'h'), (19,7,'h'), @@ -2209,9 +2209,9 @@ INSERT INTO t2 VALUES (25,3,'m'), (26,5,'z'), (27,9,'n'), (28,1,'d'), (29,107,'a'); CREATE TABLE t3 ( - pk int NOT NULL, i int(11) NOT NULL, v varchar(1) NOT NULL, + pk int NOT NULL, i int NOT NULL, v varchar(1) NOT NULL, PRIMARY KEY (pk), INDEX idx1(i), INDEX idx2(v,i) -); +) COLLATE latin1_bin; INSERT INTO t3 VALUES (1,9,'x'), (2,5,'g'), (3,1,'o'), (4,0,'g'), (5,1,'v'), (6,190,'m'), (7,6,'x'), (8,3,'c'), (9,4,'z'), (10,3,'i'), @@ -2243,5 +2243,48 @@ DROP TABLE t1,t2,t3; SET SESSION join_cache_level=DEFAULT; +--echo # +--echo # Bug #668290: hash join with non-binary collations +--echo # + +CREATE TABLE t1 ( + i int DEFAULT NULL, + cl varchar(10) CHARACTER SET latin1 DEFAULT NULL, + cu varchar(10) CHARACTER SET utf8 DEFAULT NULL, + INDEX cl (cl), + INDEX cu (cu) +); +INSERT INTO t1 VALUES + (650903552,'cmxffkpsel','z'), (535298048,'tvtjrcmxff','y'), + (1626865664,'when','for'), (39649280,'rcvljitvtj','ercvljitvt'), + (792068096,'ttercvljit','jttercvlji'); +INSERT INTO t1 SELECT * FROM t1; + +CREATE TABLE t2 ( + cu varchar(10) CHARACTER SET utf8 DEFAULT NULL, + i int DEFAULT NULL, + cl varchar(10) CHARACTER SET latin1 DEFAULT NULL, + INDEX cu (cu), + INDEX cl (cl) +); +INSERT INTO t2 VALUES + ('g',7,'like'), ('fujttercvl',6,'y'), + ('s',2,'e'), ('didn\'t',0,'v'), + ('gvdrodpedk',8,'chogvdrodp'), ('jichogvdro',7,'will'); + +EXPLAIN +SELECT t2.i FROM t1,t2 WHERE t1.cu = t2.cl ; +SELECT t2.i FROM t1,t2 WHERE t1.cu = t2.cl ; + +SET SESSION join_cache_level = 4; + +EXPLAIN +SELECT t2.i FROM t1,t2 WHERE t1.cu = t2.cl ; +SELECT t2.i FROM t1,t2 WHERE t1.cu = t2.cl ; + +SET SESSION join_cache_level = DEFAULT; + +DROP TABLE t1,t2; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/field.h b/sql/field.h index ca400caac59..a5f3ae6ba13 100644 --- a/sql/field.h +++ b/sql/field.h @@ -585,6 +585,10 @@ public: } /* Hash value */ virtual void hash(ulong *nr, ulong *nr2); + + /* Check whether the field can be used as a join attribute in hash join */ + virtual bool hash_join_is_possible() { return TRUE; } + friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(char * name, register TABLE *form, uint options, ulonglong auto_increment_value); @@ -760,6 +764,12 @@ public: my_decimal *val_decimal(my_decimal *); virtual bool str_needs_quotes() { return TRUE; } uint is_equal(Create_field *new_field); + + bool hash_join_is_possible() + { + /* TODO: support hash joins for non-binary collations */ + return (flags & BINARY_FLAG); + } }; @@ -1904,6 +1914,7 @@ public: uint size_of() const { return sizeof(*this); } int reset(void) { return !maybe_null() || Field_blob::reset(); } geometry_type get_geometry_type() { return geom_type; }; + bool hash_join_is_possible() { return FALSE; } }; #endif /*HAVE_SPATIAL*/ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 95ba424ee97..f4a86baa253 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5946,6 +5946,39 @@ void JOIN_TAB::calc_used_field_length(bool max_fl) } +/** + @brief + Check whether hash join algorithm can be used to join this table + + @details + This function finds out whether the ref items that have been chosen + by the planner to access this table can be used for hash join algorithms. + The answer depends on a certain property of the the fields of the + joined tables on which the hash join key is built. If hash join is + allowed for all these fields the answer is positive. + + @note + The function is supposed to be called now only after the function + get_best_combination has been called. + + @retval TRUE it's possible to use hash join to join this table + @retval FALSE otherwise +*/ + +bool JOIN_TAB::hash_join_is_possible() +{ + if (type != JT_REF && type != JT_EQ_REF) + return FALSE; + KEY *keyinfo= &table->key_info[ref.key]; + for (uint i= 0; i < ref.key_parts; i++) + { + if (!keyinfo->key_part[i].field->hash_join_is_possible()) + return FALSE; + } + return TRUE; +} + + static uint cache_record_length(JOIN *join,uint idx) { @@ -7649,8 +7682,10 @@ uint check_join_cache_usage(JOIN_TAB *tab, &bufsz, &flags, &cost); if ((cache_level <=4 && !no_hashed_cache) || no_bka_cache || - (flags & HA_MRR_NO_ASSOCIATION) && cache_level <=6) + ((flags & HA_MRR_NO_ASSOCIATION) && cache_level <=6)) { + if (!tab->hash_join_is_possible()) + goto no_join_cache; if (cache_level == 3) prev_cache= 0; if ((tab->cache= new JOIN_CACHE_BNLH(join, tab, prev_cache)) && diff --git a/sql/sql_select.h b/sql/sql_select.h index a57b5116bea..65e27466294 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -391,6 +391,7 @@ typedef struct st_join_table { return max_used_fieldlength; } double get_partial_join_cardinality() { return partial_join_cardinality; } + bool hash_join_is_possible(); } JOIN_TAB;