From de69dbae0cf63f3bc4fae96fac84bfff17596969 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 22 Oct 2010 15:30:47 -0700 Subject: [PATCH] Fixed LP bug #663818. After the patch for bug 663840 had been applied the test case for bug 663818 triggered the assert introduced by this patch. It happened because the the patch turned out to be incomplete: the space needed for a key entry must be taken into account for the record written into the buffer, and, for the next record as well, when figuring out whether the record being written is the last for the buffer or not. --- mysql-test/r/innodb_mysql.result | 56 ++++++++++++++++++++++++++++++++ mysql-test/t/innodb_mysql.test | 36 ++++++++++++++++++++ sql/sql_join_cache.cc | 5 +-- sql/sql_select.h | 2 +- 4 files changed, 96 insertions(+), 3 deletions(-) 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