Skip to content

Commit 90cb721

Browse files
committed
MDEV-16603 Crash with set join_cache_level=4
When the definition of the index used for hash join was created in create_hj_key_for_table() it could cause memory overwrite due to a bug that led to an underestimation of the number of the index component.
1 parent 9d41dd2 commit 90cb721

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

mysql-test/r/join_cache.result

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5871,4 +5871,37 @@ SET join_buffer_size = default;
58715871
SET join_buffer_space_limit= default;
58725872
set optimizer_switch=@save_optimizer_switch;
58735873
DROP TABLE t1,t4,t5,t2;
5874+
#
5875+
# MDEV-16603: BNLH for query with materialized semi-join
5876+
#
5877+
set join_cache_level=4;
5878+
CREATE TABLE t1 ( i1 int, v1 varchar(1)) ENGINE=InnoDB;
5879+
INSERT INTO t1 VALUES (7,'x');
5880+
CREATE TABLE t2 (i1 int, v1 varchar(1), KEY v1 (v1,i1)) ENGINE=InnoDB;
5881+
INSERT INTO t2 VALUES
5882+
(NULL,'x'),(1,'x'),(3,'x'),(5,'x'),(8,'x'),(48,'x'),
5883+
(228,'x'),(3,'y'),(1,'z'),(9,'z');
5884+
CREATE TABLE temp
5885+
SELECT t1.i1 AS f1, t1.v1 AS f2 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1));
5886+
SELECT * FROM temp
5887+
WHERE (f1,f2) IN (SELECT t1.i1, t1.v1 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1)));
5888+
f1 f2
5889+
7 x
5890+
7 x
5891+
7 x
5892+
7 x
5893+
7 x
5894+
7 x
5895+
7 x
5896+
EXPLAIN EXTENDED SELECT * FROM temp
5897+
WHERE (f1,f2) IN (SELECT t1.i1, t1.v1 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1)));
5898+
id select_type table type possible_keys key key_len ref rows filtered Extra
5899+
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 1 100.00
5900+
1 PRIMARY temp hash_ALL NULL #hash#$hj 9 test.t1.i1,test.t1.v1 7 100.00 Using where; Using join buffer (flat, BNLH join)
5901+
2 MATERIALIZED t1 ALL NULL NULL NULL NULL 1 100.00 Using where
5902+
2 MATERIALIZED t2 hash_index v1 #hash#v1:v1 4:9 test.t1.v1 10 10.00 Using join buffer (flat, BNLH join)
5903+
Warnings:
5904+
Note 1003 select `test`.`temp`.`f1` AS `f1`,`test`.`temp`.`f2` AS `f2` from `test`.`temp` semi join (`test`.`t2` join `test`.`t1`) where ((`test`.`temp`.`f1` = `test`.`t1`.`i1`) and (`test`.`t2`.`v1` = `test`.`t1`.`v1`) and (`test`.`temp`.`f2` = `test`.`t1`.`v1`))
5905+
DROP TABLE t1,t2,temp;
5906+
SET join_cache_level = default;
58745907
set @@optimizer_switch=@save_optimizer_switch;

mysql-test/t/join_cache.test

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3836,5 +3836,36 @@ set optimizer_switch=@save_optimizer_switch;
38363836

38373837
DROP TABLE t1,t4,t5,t2;
38383838

3839+
--echo #
3840+
--echo # MDEV-16603: BNLH for query with materialized semi-join
3841+
--echo #
3842+
3843+
--source include/have_innodb.inc
3844+
3845+
set join_cache_level=4;
3846+
3847+
CREATE TABLE t1 ( i1 int, v1 varchar(1)) ENGINE=InnoDB;
3848+
INSERT INTO t1 VALUES (7,'x');
3849+
3850+
CREATE TABLE t2 (i1 int, v1 varchar(1), KEY v1 (v1,i1)) ENGINE=InnoDB;
3851+
3852+
INSERT INTO t2 VALUES
3853+
(NULL,'x'),(1,'x'),(3,'x'),(5,'x'),(8,'x'),(48,'x'),
3854+
(228,'x'),(3,'y'),(1,'z'),(9,'z');
3855+
3856+
CREATE TABLE temp
3857+
SELECT t1.i1 AS f1, t1.v1 AS f2 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1));
3858+
3859+
let $q =
3860+
SELECT * FROM temp
3861+
WHERE (f1,f2) IN (SELECT t1.i1, t1.v1 FROM (t2 JOIN t1 ON (t1.v1 = t2.v1)));
3862+
3863+
eval $q;
3864+
eval EXPLAIN EXTENDED $q;
3865+
3866+
DROP TABLE t1,t2,temp;
3867+
3868+
SET join_cache_level = default;
3869+
38393870
# this must be the last command in the file
38403871
set @@optimizer_switch=@save_optimizer_switch;

sql/sql_select.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7994,7 +7994,6 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
79947994
if (first_keyuse)
79957995
{
79967996
key_parts++;
7997-
first_keyuse= FALSE;
79987997
}
79997998
else
80007999
{
@@ -8004,14 +8003,15 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
80048003
if (curr->keypart == keyuse->keypart &&
80058004
!(~used_tables & curr->used_tables) &&
80068005
join_tab->keyuse_is_valid_for_access_in_chosen_plan(join,
8007-
keyuse) &&
8006+
curr) &&
80088007
are_tables_local(join_tab, curr->used_tables))
80098008
break;
80108009
}
80118010
if (curr == keyuse)
80128011
key_parts++;
80138012
}
80148013
}
8014+
first_keyuse= FALSE;
80158015
keyuse++;
80168016
} while (keyuse->table == table && keyuse->is_for_hash_join());
80178017
if (!key_parts)

0 commit comments

Comments
 (0)