From ca862231f731dd23b8eaa83d3d052b84cc60a04b Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 22 Oct 2010 10:53:29 -0700 Subject: [PATCH] Fixed LP bug #663840. When adding a new record into the join buffer that is employed by BNLH join algorithm the writing procedure JOIN_CACHE::write_record_data checks whether there is enough space for the record in the buffer. When doing this it must take into account a possible new key entry added to the buffer. It might happen, as it has been demonstrated by the bug test case, that there is enough remaining space in the buffer for the record, but not for the additional key entry for this record. In this case the key entry overwrites the end of the record that might cause a crash or wrong results. Fixed by taking into account a possible addition of new key entry when estimating the remaining free space in the buffer. --- mysql-test/r/join_cache.result | 108 ++++++++++++++++++++++++++++++--- mysql-test/t/join_cache.test | 59 +++++++++++++++--- sql/sql_join_cache.cc | 3 +- sql/sql_select.h | 12 ++++ 4 files changed, 166 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index b7724c316f9..0c9c98e4b59 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -4998,9 +4998,9 @@ id1 num3 text1 id4 id3 dummy 228808822 18 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 826928662 935693782 0 228808822 1 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 826928662 935693782 0 228808822 3 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 826928662 935693782 0 -228808822 4 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 826928662 935693782 0 228808822 17 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 826928662 935693782 0 228808822 50 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 826928662 935693782 0 +228808822 4 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 826928662 935693782 0 228808822 89 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 228808822 19 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 228808822 9 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 @@ -5009,9 +5009,9 @@ id1 num3 text1 id4 id3 dummy 228808822 1 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 228808822 10 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 228808822 26 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 +228808822 4 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 228808822 3 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 228808822 1 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 -228808822 4 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 228808822 3 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 228808822 28 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 228808822 62 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 2381969632 2482416112 0 @@ -5202,8 +5202,8 @@ a DROP TABLE t1,t2,t3; set join_cache_level=default; # -# Bug#51084: Batched key access crashes for SELECT with -# derived table and LEFT JOIN +# Bug #51084: Batched key access crashes for SELECT with +# derived table and LEFT JOIN # CREATE TABLE t1 ( carrier int, @@ -5243,7 +5243,7 @@ id select_type table type possible_keys key key_len ref rows Extra SET join_cache_level=default; DROP TABLE t1,t2,t3,t4; # -# BUG#52636: allowing JOINs on NULL values w/ join_cache_level = 5-8 +# Bug #52636: allowing JOINs on NULL values w/ join_cache_level = 5-8 # CREATE TABLE t1 (b int); INSERT INTO t1 VALUES (NULL),(3); @@ -5304,8 +5304,8 @@ NULL set join_cache_level = default; DROP TABLE t1,t2; # -# BUG#54359 "Extra rows with join_cache_level=7,8 and two joins -# --and multi-column index" +# Bug #54359: Extra rows with join_cache_level=7,8 and two joins +# and multi-column index" # CREATE TABLE t1 ( pk int NOT NULL, @@ -5331,7 +5331,7 @@ a set join_cache_level = default; DROP TABLE t1; # -# Bug#54235 Extra rows with join_cache_level=6,8 and two LEFT JOINs +# Bug #54235: Extra rows with join_cache_level=6,8 and two LEFT JOINs # CREATE TABLE t1 (a int); CREATE TABLE t2 (a int); @@ -5370,4 +5370,96 @@ a 1 set join_cache_level = default; DROP TABLE t1,t2,t3,t4; +# +# Bug #663840: Memory overwrite causing crash with hash join +# +SET SESSION join_cache_level=3; +SET SESSION join_buffer_size=100; +Warnings: +Warning 1292 Truncated incorrect join_buffer_size value: '100' +CREATE TABLE t3 ( +i int NOT NULL, +j int NOT NULL, +d date NOT NULL, +t time NOT NULL, +v varchar(1) NOT NULL, +u varchar(1) NOT NULL, +INDEX idx (v) +) COLLATE=latin1_bin; +INSERT INTO t3 VALUES +(3,8,'2008-12-04','00:00:00','v','v'), (3,8,'2009-03-28','00:00:00','f','f'), +(3,5,'1900-01-01','00:55:47','v','v'), (2,8,'2009-10-02','00:00:00','s','s'), +(1,8,'1900-01-01','20:51:59','a','a'), (0,6,'2008-06-04','09:47:27','p','p'), +(8,7,'2009-01-13','21:58:29','z','z'), (5,2,'1900-01-01','22:45:53','a','a'), +(9,5,'2008-01-28','14:06:48','h','h'), (5,7,'2004-09-18','22:17:16','h','h'), +(4,2,'2006-10-14','14:59:37','v','v'), (2,9,'1900-01-01','23:37:40','v','v'), +(33,142,'2000-11-28','14:14:01','b','b'), (5,3,'2008-04-04','02:54:19','y','y'), +(1,0,'2002-07-13','06:34:26','v','v'), (9,3,'2003-01-03','18:07:38','m','m'), +(1,5,'2006-04-02','13:55:23','z','z'), (3,9,'2006-10-19','20:32:28','n','n'), +(8,1,'2005-06-08','11:57:44','d','d'), (231,107,'2006-12-26','03:10:35','a','a'); +CREATE TABLE t1 SELECT * FROM t3; +DELETE FROM t1 WHERE i > 8; +CREATE TABLE t2 SELECT * FROM t3; +DELETE FROM t2 WHERE j > 10; +EXPLAIN +SELECT t1.i, t1.d, t1.v, t2.i, t2.d, t2.t, t2.v FROM t1,t2,t3 +WHERE t3.u <='a' AND t2.j < 5 AND t3.v = t2.u; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 16 +1 SIMPLE t2 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 ref idx idx 3 test.t2.u 2 Using where; Using join buffer (flat, BNLH join) +SELECT t1.i, t1.d, t1.v, t2.i, t2.d, t2.t, t2.v FROM t1,t2,t3 +WHERE t3.u <='a' AND t2.j < 5 AND t3.v = t2.u; +i d v i d t v +3 2008-12-04 v 5 1900-01-01 22:45:53 a +3 2009-03-28 f 5 1900-01-01 22:45:53 a +3 1900-01-01 v 5 1900-01-01 22:45:53 a +2 2009-10-02 s 5 1900-01-01 22:45:53 a +3 2008-12-04 v 5 1900-01-01 22:45:53 a +3 2009-03-28 f 5 1900-01-01 22:45:53 a +3 1900-01-01 v 5 1900-01-01 22:45:53 a +2 2009-10-02 s 5 1900-01-01 22:45:53 a +3 2008-12-04 v 5 1900-01-01 22:45:53 a +3 2009-03-28 f 5 1900-01-01 22:45:53 a +3 1900-01-01 v 5 1900-01-01 22:45:53 a +2 2009-10-02 s 5 1900-01-01 22:45:53 a +1 1900-01-01 a 5 1900-01-01 22:45:53 a +0 2008-06-04 p 5 1900-01-01 22:45:53 a +8 2009-01-13 z 5 1900-01-01 22:45:53 a +5 1900-01-01 a 5 1900-01-01 22:45:53 a +1 1900-01-01 a 5 1900-01-01 22:45:53 a +0 2008-06-04 p 5 1900-01-01 22:45:53 a +8 2009-01-13 z 5 1900-01-01 22:45:53 a +5 1900-01-01 a 5 1900-01-01 22:45:53 a +1 1900-01-01 a 5 1900-01-01 22:45:53 a +0 2008-06-04 p 5 1900-01-01 22:45:53 a +8 2009-01-13 z 5 1900-01-01 22:45:53 a +5 1900-01-01 a 5 1900-01-01 22:45:53 a +5 2004-09-18 h 5 1900-01-01 22:45:53 a +4 2006-10-14 v 5 1900-01-01 22:45:53 a +2 1900-01-01 v 5 1900-01-01 22:45:53 a +5 2008-04-04 y 5 1900-01-01 22:45:53 a +5 2004-09-18 h 5 1900-01-01 22:45:53 a +4 2006-10-14 v 5 1900-01-01 22:45:53 a +2 1900-01-01 v 5 1900-01-01 22:45:53 a +5 2008-04-04 y 5 1900-01-01 22:45:53 a +5 2004-09-18 h 5 1900-01-01 22:45:53 a +4 2006-10-14 v 5 1900-01-01 22:45:53 a +2 1900-01-01 v 5 1900-01-01 22:45:53 a +5 2008-04-04 y 5 1900-01-01 22:45:53 a +1 2002-07-13 v 5 1900-01-01 22:45:53 a +1 2006-04-02 z 5 1900-01-01 22:45:53 a +3 2006-10-19 n 5 1900-01-01 22:45:53 a +8 2005-06-08 d 5 1900-01-01 22:45:53 a +1 2002-07-13 v 5 1900-01-01 22:45:53 a +1 2006-04-02 z 5 1900-01-01 22:45:53 a +3 2006-10-19 n 5 1900-01-01 22:45:53 a +8 2005-06-08 d 5 1900-01-01 22:45:53 a +1 2002-07-13 v 5 1900-01-01 22:45:53 a +1 2006-04-02 z 5 1900-01-01 22:45:53 a +3 2006-10-19 n 5 1900-01-01 22:45:53 a +8 2005-06-08 d 5 1900-01-01 22:45:53 a +DROP TABLE t1,t2,t3; +SET SESSION join_cache_level=DEFAULT; +SET SESSION join_buffer_size=DEFAULT; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index 8ab9165457b..d83646b5e99 100755 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -1983,8 +1983,8 @@ DROP TABLE t1,t2,t3; set join_cache_level=default; --echo # ---echo # Bug#51084: Batched key access crashes for SELECT with ---echo # derived table and LEFT JOIN +--echo # Bug #51084: Batched key access crashes for SELECT with +--echo # derived table and LEFT JOIN --echo # CREATE TABLE t1 ( @@ -2027,7 +2027,7 @@ SET join_cache_level=default; DROP TABLE t1,t2,t3,t4; --echo # ---echo # BUG#52636: allowing JOINs on NULL values w/ join_cache_level = 5-8 +--echo # Bug #52636: allowing JOINs on NULL values w/ join_cache_level = 5-8 --echo # CREATE TABLE t1 (b int); @@ -2077,8 +2077,8 @@ set join_cache_level = default; DROP TABLE t1,t2; --echo # ---echo # BUG#54359 "Extra rows with join_cache_level=7,8 and two joins ---echo # --and multi-column index" +--echo # Bug #54359: Extra rows with join_cache_level=7,8 and two joins +--echo # and multi-column index" --echo # CREATE TABLE t1 ( @@ -2104,9 +2104,8 @@ SELECT t.a FROM t1 t, t1 s FORCE INDEX(idx) set join_cache_level = default; DROP TABLE t1; - --echo # ---echo # Bug#54235 Extra rows with join_cache_level=6,8 and two LEFT JOINs +--echo # Bug #54235: Extra rows with join_cache_level=6,8 and two LEFT JOINs --echo # CREATE TABLE t1 (a int); @@ -2136,5 +2135,51 @@ SELECT t1.a set join_cache_level = default; DROP TABLE t1,t2,t3,t4; +--echo # +--echo # Bug #663840: Memory overwrite causing crash with hash join +--echo # + +SET SESSION join_cache_level=3; +SET SESSION join_buffer_size=100; + +CREATE TABLE t3 ( + i int NOT NULL, + j int NOT NULL, + d date NOT NULL, + t time NOT NULL, + v varchar(1) NOT NULL, + u varchar(1) NOT NULL, + INDEX idx (v) +) COLLATE=latin1_bin; + +INSERT INTO t3 VALUES + (3,8,'2008-12-04','00:00:00','v','v'), (3,8,'2009-03-28','00:00:00','f','f'), + (3,5,'1900-01-01','00:55:47','v','v'), (2,8,'2009-10-02','00:00:00','s','s'), + (1,8,'1900-01-01','20:51:59','a','a'), (0,6,'2008-06-04','09:47:27','p','p'), + (8,7,'2009-01-13','21:58:29','z','z'), (5,2,'1900-01-01','22:45:53','a','a'), + (9,5,'2008-01-28','14:06:48','h','h'), (5,7,'2004-09-18','22:17:16','h','h'), + (4,2,'2006-10-14','14:59:37','v','v'), (2,9,'1900-01-01','23:37:40','v','v'), + (33,142,'2000-11-28','14:14:01','b','b'), (5,3,'2008-04-04','02:54:19','y','y'), + (1,0,'2002-07-13','06:34:26','v','v'), (9,3,'2003-01-03','18:07:38','m','m'), + (1,5,'2006-04-02','13:55:23','z','z'), (3,9,'2006-10-19','20:32:28','n','n'), + (8,1,'2005-06-08','11:57:44','d','d'), (231,107,'2006-12-26','03:10:35','a','a'); + +CREATE TABLE t1 SELECT * FROM t3; +DELETE FROM t1 WHERE i > 8; +CREATE TABLE t2 SELECT * FROM t3; +DELETE FROM t2 WHERE j > 10; + +EXPLAIN +SELECT t1.i, t1.d, t1.v, t2.i, t2.d, t2.t, t2.v FROM t1,t2,t3 + WHERE t3.u <='a' AND t2.j < 5 AND t3.v = t2.u; + +SELECT t1.i, t1.d, t1.v, t2.i, t2.d, t2.t, t2.v FROM t1,t2,t3 + WHERE t3.u <='a' AND t2.j < 5 AND t3.v = t2.u; + +DROP TABLE t1,t2,t3; + +SET SESSION join_cache_level=DEFAULT; +SET SESSION join_buffer_size=DEFAULT; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index cd45145f69c..dad3abd0af4 100755 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -1164,7 +1164,7 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full) records++; /* Increment the counter of records in the cache */ - len= pack_length; + len= pack_length + extra_key_length(); /* Make an adjustment for the size of the auxiliary buffer if there is any */ uint incr= aux_buffer_incr(records); @@ -2723,6 +2723,7 @@ bool JOIN_CACHE_HASHED::put_record() memcpy(cp, key, key_len); } last_key_entry= cp; + DBUG_ASSERT(last_key_entry >= end_pos); /* Increment the counter of key_entries in the hash table */ key_entries++; } diff --git a/sql/sql_select.h b/sql/sql_select.h index 4279761fda3..da23a639ff4 100755 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -790,6 +790,12 @@ protected: return max(buff_size-(end_pos-buff)-aux_buff_size,0); } + /* + Shall calculate how much space is taken by allocation of the key + for a record in the join buffer + */ + virtual uint extra_key_length() { return 0; } + /* Read all flag and data fields of a record from the join buffer */ uint read_all_record_fields(); @@ -1272,6 +1278,12 @@ protected: return max(last_key_entry-end_pos-aux_buff_size,0); } + /* + 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; } + /* Skip record from a hashed join buffer if its match flag is set to MATCH_FOUND