diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index f108b96b82a..98133edd9ca 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -2390,3 +2390,59 @@ SECOND(c)-@bug47453 0 DROP TABLE t1, t2; End of 5.1 tests +# +# Bug #663818: wrong result when BNLH is used +# +CREATE TABLE t1(pk int NOT NULL PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(1), (2), (11), (12), (13), (14), +(15), (16), (17), (18), (19); +CREATE TABLE t2(pk int NOT NULL PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES +(1), (10), (11), (12), (13), (14), +(15), (16), (17), (18), (19), (20), (21); +SET SESSION join_buffer_size=10000; +SET SESSION join_cache_level=3; +EXPLAIN +SELECT t1.pk FROM t1,t2 +WHERE t1.pk = t2.pk AND t2.pk <> 8; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 11 Using where; Using index +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index; Using join buffer (flat, BNLH join) +SELECT t1.pk FROM t1,t2 +WHERE t1.pk = t2.pk AND t2.pk <> 8; +pk +1 +11 +12 +13 +14 +15 +16 +17 +18 +19 +SET SESSION join_cache_level=1; +EXPLAIN +SELECT t1.pk FROM t1,t2 +WHERE t1.pk = t2.pk AND t2.pk <> 8; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 11 Using where; Using index +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.pk 1 Using index +SELECT t1.pk FROM t1,t2 +WHERE t1.pk = t2.pk AND t2.pk <> 8; +pk +1 +11 +12 +13 +14 +15 +16 +17 +18 +19 +DROP TABLE t1,t2; +SET SESSION join_cache_level=DEFAULT; +SET SESSION join_buffer_size=DEFAULT; +End of 5.3 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index ada4323dcee..845f8731a16 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -634,3 +634,39 @@ SELECT SECOND(c)-@bug47453 FROM t1 JOIN t2 ON d=a; DROP TABLE t1, t2; --echo End of 5.1 tests + +--echo # +--echo # Bug #663818: wrong result when BNLH is used +--echo # + +CREATE TABLE t1(pk int NOT NULL PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES + (1), (2), (11), (12), (13), (14), + (15), (16), (17), (18), (19); +CREATE TABLE t2(pk int NOT NULL PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES + (1), (10), (11), (12), (13), (14), + (15), (16), (17), (18), (19), (20), (21); + +SET SESSION join_buffer_size=10000; + +SET SESSION join_cache_level=3; +EXPLAIN +SELECT t1.pk FROM t1,t2 + WHERE t1.pk = t2.pk AND t2.pk <> 8; +SELECT t1.pk FROM t1,t2 + WHERE t1.pk = t2.pk AND t2.pk <> 8; + +SET SESSION join_cache_level=1; +EXPLAIN +SELECT t1.pk FROM t1,t2 + WHERE t1.pk = t2.pk AND t2.pk <> 8; +SELECT t1.pk FROM t1,t2 + WHERE t1.pk = t2.pk AND t2.pk <> 8; + +DROP TABLE t1,t2; + +SET SESSION join_cache_level=DEFAULT; +SET SESSION join_buffer_size=DEFAULT; + +--echo End of 5.3 tests diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index dad3abd0af4..5cd02776003 100755 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -1161,10 +1161,11 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full) uchar *cp= pos; uchar *init_pos= cp; uchar *rec_len_ptr= 0; + uint key_extra= extra_key_length(); records++; /* Increment the counter of records in the cache */ - len= pack_length + extra_key_length(); + len= pack_length + key_extra; /* Make an adjustment for the size of the auxiliary buffer if there is any */ uint incr= aux_buffer_incr(records); @@ -1204,7 +1205,7 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full) This function is called only in the case when there is enough space left in the cache to store at least non-blob parts of the current record. */ - last_record= (len+pack_length_with_blob_ptrs) > rem_space(); + last_record= (len+pack_length_with_blob_ptrs+key_extra) > rem_space(); /* Save the position for the length of the record in the cache if it's needed. diff --git a/sql/sql_select.h b/sql/sql_select.h index da23a639ff4..7e67a1e985c 100755 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1282,7 +1282,7 @@ protected: Calculate how much space is taken by allocation of the key entry for a record in the join buffer */ - virtual uint extra_key_length() { return key_entry_length; } + uint extra_key_length() { return key_entry_length; } /* Skip record from a hashed join buffer if its match flag