Commit a28c8a3c authored by Sergey Petrunya's avatar Sergey Petrunya

Merge semi-join+outer-join fixes into 5.3

parents cb164640 c25728cd
...@@ -1326,4 +1326,161 @@ x ...@@ -1326,4 +1326,161 @@ x
m m
c c
drop table t1,t2,t3,t4; drop table t1,t2,t3,t4;
#
# BUG#795530 Wrong result with subquery semijoin materialization and outer join
# Simplified testcase that uses DuplicateElimination
#
create table t1 (a int);
create table t2 (a int, b char(10));
insert into t1 values (1),(2);
insert into t2 values (1, 'one'), (3, 'three');
create table t3 (b char(10));
insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
explain select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Start temporary
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where; End temporary; Using join buffer (flat, BNL join)
select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
b
drop table t1, t2, t3;
#
# BUG#600958 RQG: Crash in optimize_semijoin_nests
#
CREATE TABLE t1 (
pk int(11) NOT NULL AUTO_INCREMENT,
col_int_key int(11) DEFAULT NULL,
col_date_key date DEFAULT NULL,
col_varchar_key varchar(1) DEFAULT NULL,
PRIMARY KEY (pk),
KEY col_int_key (col_int_key),
KEY col_date_key (col_date_key),
KEY col_varchar_key (col_varchar_key,col_int_key)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;
INSERT INTO t1 VALUES (10,8,'2002-02-21',NULL);
CREATE TABLE t2 (
pk int(11) NOT NULL AUTO_INCREMENT,
col_int_key int(11) DEFAULT NULL,
col_date_key date DEFAULT NULL,
col_varchar_key varchar(1) DEFAULT NULL,
PRIMARY KEY (pk),
KEY col_int_key (col_int_key),
KEY col_date_key (col_date_key),
KEY col_varchar_key (col_varchar_key,col_int_key)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
INSERT INTO t2 VALUES (1,7,'1900-01-01','f');
SELECT col_date_key FROM t1
WHERE 5 IN (
SELECT SUBQUERY3_t1 .col_int_key
FROM t2 SUBQUERY3_t1
LEFT JOIN t1 SUBQUERY3_t2 ON SUBQUERY3_t1 .col_varchar_key
);
col_date_key
drop table t2, t1;
#
# No BUG#: Duplicate weedout check is not done for outer joins
#
create table t1 (a int);
create table t2 (a int);
insert into t1 values (1),(1),(2),(2);
insert into t2 values (1);
create table t0 (a int);
insert into t0 values (1),(2);
set @tmp_20110622= @@optimizer_switch;
set optimizer_switch='firstmatch=off,loosescan=off,materialization=off';
# Check DuplicateWeedout + join buffer
explain
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
a
1
2
# Check DuplicateWeedout without join buffer
set @tmp_jcl_20110622= @@join_cache_level;
set join_cache_level= 0;
explain
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
a
1
2
# Check FirstMatch without join buffer:
set optimizer_switch='firstmatch=on';
explain
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; FirstMatch(t0)
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
a
1
2
#
# Now, check the same for multiple inner tables:
alter table t2 add b int;
update t2 set b=a;
create table t3 as select * from t2;
set optimizer_switch='firstmatch=off';
set join_cache_level= 0;
# DuplicateWeedout without join buffer
explain
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary
1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
a
1
2
set @@join_cache_level=@tmp_jcl_20110622;
# DuplicateWeedout + join buffer
explain
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
a
1
2
# Now, let the inner join side have a 'partial' match
select * from t3;
a b
1 1
insert into t3 values(2,2);
explain
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
1 PRIMARY t2 ALL NULL NULL NULL NULL 1
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; End temporary
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
a
1
2
set @@optimizer_switch=@tmp_20110622;
drop table t0, t1, t2;
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
...@@ -1334,6 +1334,163 @@ x ...@@ -1334,6 +1334,163 @@ x
m m
c c
drop table t1,t2,t3,t4; drop table t1,t2,t3,t4;
#
# BUG#795530 Wrong result with subquery semijoin materialization and outer join
# Simplified testcase that uses DuplicateElimination
#
create table t1 (a int);
create table t2 (a int, b char(10));
insert into t1 values (1),(2);
insert into t2 values (1, 'one'), (3, 'three');
create table t3 (b char(10));
insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
explain select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Start temporary
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where; End temporary; Using join buffer (incremental, BNL join)
select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
b
drop table t1, t2, t3;
#
# BUG#600958 RQG: Crash in optimize_semijoin_nests
#
CREATE TABLE t1 (
pk int(11) NOT NULL AUTO_INCREMENT,
col_int_key int(11) DEFAULT NULL,
col_date_key date DEFAULT NULL,
col_varchar_key varchar(1) DEFAULT NULL,
PRIMARY KEY (pk),
KEY col_int_key (col_int_key),
KEY col_date_key (col_date_key),
KEY col_varchar_key (col_varchar_key,col_int_key)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;
INSERT INTO t1 VALUES (10,8,'2002-02-21',NULL);
CREATE TABLE t2 (
pk int(11) NOT NULL AUTO_INCREMENT,
col_int_key int(11) DEFAULT NULL,
col_date_key date DEFAULT NULL,
col_varchar_key varchar(1) DEFAULT NULL,
PRIMARY KEY (pk),
KEY col_int_key (col_int_key),
KEY col_date_key (col_date_key),
KEY col_varchar_key (col_varchar_key,col_int_key)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
INSERT INTO t2 VALUES (1,7,'1900-01-01','f');
SELECT col_date_key FROM t1
WHERE 5 IN (
SELECT SUBQUERY3_t1 .col_int_key
FROM t2 SUBQUERY3_t1
LEFT JOIN t1 SUBQUERY3_t2 ON SUBQUERY3_t1 .col_varchar_key
);
col_date_key
drop table t2, t1;
#
# No BUG#: Duplicate weedout check is not done for outer joins
#
create table t1 (a int);
create table t2 (a int);
insert into t1 values (1),(1),(2),(2);
insert into t2 values (1);
create table t0 (a int);
insert into t0 values (1),(2);
set @tmp_20110622= @@optimizer_switch;
set optimizer_switch='firstmatch=off,loosescan=off,materialization=off';
# Check DuplicateWeedout + join buffer
explain
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary; Using join buffer (incremental, BNL join)
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
a
1
2
# Check DuplicateWeedout without join buffer
set @tmp_jcl_20110622= @@join_cache_level;
set join_cache_level= 0;
explain
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
a
1
2
# Check FirstMatch without join buffer:
set optimizer_switch='firstmatch=on';
explain
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; FirstMatch(t0)
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
a
1
2
#
# Now, check the same for multiple inner tables:
alter table t2 add b int;
update t2 set b=a;
create table t3 as select * from t2;
set optimizer_switch='firstmatch=off';
set join_cache_level= 0;
# DuplicateWeedout without join buffer
explain
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Start temporary
1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
a
1
2
set @@join_cache_level=@tmp_jcl_20110622;
# DuplicateWeedout + join buffer
explain
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join)
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; End temporary; Using join buffer (incremental, BNL join)
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
a
1
2
# Now, let the inner join side have a 'partial' match
select * from t3;
a b
1 1
insert into t3 values(2,2);
explain
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 Start temporary
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using join buffer (incremental, BNL join)
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (incremental, BNL join)
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
a
1
2
set @@optimizer_switch=@tmp_20110622;
drop table t0, t1, t2;
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
# #
# BUG#49129: Wrong result with IN-subquery with join_cache_level=6 and firstmatch=off # BUG#49129: Wrong result with IN-subquery with join_cache_level=6 and firstmatch=off
......
...@@ -636,7 +636,7 @@ from t1_16 ...@@ -636,7 +636,7 @@ from t1_16
where a1 in (select substring(b1,1,16) from t2_16 where b1 > '0'); where a1 in (select substring(b1,1,16) from t2_16 where b1 > '0');
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY t1_16 ALL NULL NULL NULL NULL 3 100.00
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 20 func 1 100.00 Using where 1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 20 func 1 100.00
2 SUBQUERY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2_16 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings: Warnings:
Note 1003 select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` semi join (`test`.`t2_16`) where ((`test`.`t2_16`.`b1` > '0') and (`test`.`t1_16`.`a1` = substr(`test`.`t2_16`.`b1`,1,16))) Note 1003 select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` semi join (`test`.`t2_16`) where ((`test`.`t2_16`.`b1` > '0') and (`test`.`t1_16`.`a1` = substr(`test`.`t2_16`.`b1`,1,16)))
...@@ -751,7 +751,7 @@ from t1_512 ...@@ -751,7 +751,7 @@ from t1_512
where a1 in (select substring(b1,1,512) from t2_512 where b1 > '0'); where a1 in (select substring(b1,1,512) from t2_512 where b1 > '0');
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY t1_512 ALL NULL NULL NULL NULL 3 100.00
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 517 func 1 100.00 Using where 1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 517 func 1 100.00
2 SUBQUERY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2_512 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings: Warnings:
Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` semi join (`test`.`t2_512`) where ((`test`.`t2_512`.`b1` > '0') and (`test`.`t1_512`.`a1` = substr(`test`.`t2_512`.`b1`,1,512))) Note 1003 select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` semi join (`test`.`t2_512`) where ((`test`.`t2_512`.`b1` > '0') and (`test`.`t1_512`.`a1` = substr(`test`.`t2_512`.`b1`,1,512)))
...@@ -847,7 +847,7 @@ from t1_1024 ...@@ -847,7 +847,7 @@ from t1_1024
where a1 in (select substring(b1,1,1024) from t2_1024 where b1 > '0'); where a1 in (select substring(b1,1,1024) from t2_1024 where b1 > '0');
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00
1 PRIMARY <subquery2> eq_ref NULL distinct_key 15 func,func 1 100.00 Using where 1 PRIMARY <subquery2> eq_ref NULL distinct_key 15 func,func 1 100.00
2 SUBQUERY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings: Warnings:
Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` semi join (`test`.`t2_1024`) where ((`test`.`t2_1024`.`b1` > '0') and (`test`.`t1_1024`.`a1` = substr(`test`.`t2_1024`.`b1`,1,1024))) Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` semi join (`test`.`t2_1024`) where ((`test`.`t2_1024`.`b1` > '0') and (`test`.`t1_1024`.`a1` = substr(`test`.`t2_1024`.`b1`,1,1024)))
...@@ -941,7 +941,7 @@ from t1_1025 ...@@ -941,7 +941,7 @@ from t1_1025
where a1 in (select substring(b1,1,1025) from t2_1025 where b1 > '0'); where a1 in (select substring(b1,1,1025) from t2_1025 where b1 > '0');
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00
1 PRIMARY <subquery2> eq_ref NULL distinct_key 15 func,func 1 100.00 Using where 1 PRIMARY <subquery2> eq_ref NULL distinct_key 15 func,func 1 100.00
2 SUBQUERY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings: Warnings:
Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` semi join (`test`.`t2_1025`) where ((`test`.`t2_1025`.`b1` > '0') and (`test`.`t1_1025`.`a1` = substr(`test`.`t2_1025`.`b1`,1,1025))) Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` semi join (`test`.`t2_1025`) where ((`test`.`t2_1025`.`b1` > '0') and (`test`.`t1_1025`.`a1` = substr(`test`.`t2_1025`.`b1`,1,1025)))
...@@ -1219,7 +1219,7 @@ insert into t1 values ('aa', 'aaaa'); ...@@ -1219,7 +1219,7 @@ insert into t1 values ('aa', 'aaaa');
explain select a,b from t1 where b in (select a from t1); explain select a,b from t1 where b in (select a from t1);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 1 PRIMARY t1 ALL NULL NULL NULL NULL 2
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 3 func 1 Using where 1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 3 func 1
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
select a,b from t1 where b in (select a from t1); select a,b from t1 where b in (select a from t1);
a b a b
......
...@@ -1212,5 +1212,133 @@ LEFT JOIN t2 JOIN t3 ON t3.f10 = t2.f10 ON t3.f11 != 0 ); ...@@ -1212,5 +1212,133 @@ LEFT JOIN t2 JOIN t3 ON t3.f10 = t2.f10 ON t3.f11 != 0 );
drop table t1,t2,t3,t4; drop table t1,t2,t3,t4;
--echo #
--echo # BUG#795530 Wrong result with subquery semijoin materialization and outer join
--echo # Simplified testcase that uses DuplicateElimination
--echo #
create table t1 (a int);
create table t2 (a int, b char(10));
insert into t1 values (1),(2);
insert into t2 values (1, 'one'), (3, 'three');
create table t3 (b char(10));
insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
explain select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
drop table t1, t2, t3;
--echo #
--echo # BUG#600958 RQG: Crash in optimize_semijoin_nests
--echo #
CREATE TABLE t1 (
pk int(11) NOT NULL AUTO_INCREMENT,
col_int_key int(11) DEFAULT NULL,
col_date_key date DEFAULT NULL,
col_varchar_key varchar(1) DEFAULT NULL,
PRIMARY KEY (pk),
KEY col_int_key (col_int_key),
KEY col_date_key (col_date_key),
KEY col_varchar_key (col_varchar_key,col_int_key)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;
INSERT INTO t1 VALUES (10,8,'2002-02-21',NULL);
CREATE TABLE t2 (
pk int(11) NOT NULL AUTO_INCREMENT,
col_int_key int(11) DEFAULT NULL,
col_date_key date DEFAULT NULL,
col_varchar_key varchar(1) DEFAULT NULL,
PRIMARY KEY (pk),
KEY col_int_key (col_int_key),
KEY col_date_key (col_date_key),
KEY col_varchar_key (col_varchar_key,col_int_key)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
INSERT INTO t2 VALUES (1,7,'1900-01-01','f');
SELECT col_date_key FROM t1
WHERE 5 IN (
SELECT SUBQUERY3_t1 .col_int_key
FROM t2 SUBQUERY3_t1
LEFT JOIN t1 SUBQUERY3_t2 ON SUBQUERY3_t1 .col_varchar_key
);
drop table t2, t1;
--echo #
--echo # No BUG#: Duplicate weedout check is not done for outer joins
--echo #
create table t1 (a int);
create table t2 (a int);
insert into t1 values (1),(1),(2),(2);
insert into t2 values (1);
create table t0 (a int);
insert into t0 values (1),(2);
set @tmp_20110622= @@optimizer_switch;
set optimizer_switch='firstmatch=off,loosescan=off,materialization=off';
--echo # Check DuplicateWeedout + join buffer
explain
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
--echo # Check DuplicateWeedout without join buffer
set @tmp_jcl_20110622= @@join_cache_level;
set join_cache_level= 0;
explain
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
--echo # Check FirstMatch without join buffer:
set optimizer_switch='firstmatch=on';
explain
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
select * from t0 where a in (select t1.a from t1 left join t2 on t1.a=t2.a);
--echo #
--echo # Now, check the same for multiple inner tables:
alter table t2 add b int;
update t2 set b=a;
create table t3 as select * from t2;
set optimizer_switch='firstmatch=off';
set join_cache_level= 0;
--echo # DuplicateWeedout without join buffer
explain
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
set @@join_cache_level=@tmp_jcl_20110622;
--echo # DuplicateWeedout + join buffer
explain
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
--echo # Now, let the inner join side have a 'partial' match
select * from t3;
insert into t3 values(2,2);
explain
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
select * from t0
where a in (select t1.a from t1 left join (t3 join t2 on t3.b=t2.b) on t1.a=t3.a);
set @@optimizer_switch=@tmp_20110622;
drop table t0, t1, t2;
# The following command must be the last one the file # The following command must be the last one the file
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
...@@ -1688,7 +1688,8 @@ class Item_equal: public Item_bool_func ...@@ -1688,7 +1688,8 @@ class Item_equal: public Item_bool_func
friend class Item_equal_fields_iterator; friend class Item_equal_fields_iterator;
friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
Item_equal *item_equal); Item_equal *item_equal);
friend bool setup_sj_materialization(struct st_join_table *tab); friend bool setup_sj_materialization_part1(struct st_join_table *tab);
friend bool setup_sj_materialization_part2(struct st_join_table *tab);
}; };
class COND_EQUAL: public Sql_alloc class COND_EQUAL: public Sql_alloc
......
...@@ -2840,9 +2840,8 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) ...@@ -2840,9 +2840,8 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
TRUE Error TRUE Error
*/ */
bool setup_sj_materialization(JOIN_TAB *sjm_tab) bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab)
{ {
uint i;
DBUG_ENTER("setup_sj_materialization"); DBUG_ENTER("setup_sj_materialization");
JOIN_TAB *tab= sjm_tab->bush_children->start; JOIN_TAB *tab= sjm_tab->bush_children->start;
TABLE_LIST *emb_sj_nest= tab->table->pos_in_table_list->embedding; TABLE_LIST *emb_sj_nest= tab->table->pos_in_table_list->embedding;
...@@ -2851,6 +2850,7 @@ bool setup_sj_materialization(JOIN_TAB *sjm_tab) ...@@ -2851,6 +2850,7 @@ bool setup_sj_materialization(JOIN_TAB *sjm_tab)
/* First the calls come to the materialization function */ /* First the calls come to the materialization function */
List<Item> &item_list= emb_sj_nest->sj_subq_pred->unit->first_select()->item_list; List<Item> &item_list= emb_sj_nest->sj_subq_pred->unit->first_select()->item_list;
DBUG_ASSERT(sjm->is_used);
/* /*
Set up the table to write to, do as select_union::create_result_table does Set up the table to write to, do as select_union::create_result_table does
*/ */
...@@ -2878,6 +2878,22 @@ bool setup_sj_materialization(JOIN_TAB *sjm_tab) ...@@ -2878,6 +2878,22 @@ bool setup_sj_materialization(JOIN_TAB *sjm_tab)
sjm->materialized= FALSE; sjm->materialized= FALSE;
sjm_tab->table= sjm->table; sjm_tab->table= sjm->table;
sjm->table->pos_in_table_list= emb_sj_nest;//???? psergey ???
DBUG_RETURN(FALSE);
}
bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab)
{
DBUG_ENTER("setup_sj_materialization_part2");
JOIN_TAB *tab= sjm_tab->bush_children->start;
TABLE_LIST *emb_sj_nest= tab->table->pos_in_table_list->embedding;
SJ_MATERIALIZATION_INFO *sjm= emb_sj_nest->sj_mat_info;
THD *thd= tab->join->thd;
uint i;
List<Item> &item_list= emb_sj_nest->sj_subq_pred->unit->first_select()->item_list;
List_iterator<Item> it(item_list);
if (!sjm->is_sj_scan) if (!sjm->is_sj_scan)
{ {
...@@ -2992,7 +3008,7 @@ bool setup_sj_materialization(JOIN_TAB *sjm_tab) ...@@ -2992,7 +3008,7 @@ bool setup_sj_materialization(JOIN_TAB *sjm_tab)
in the record buffers for the source tables. in the record buffers for the source tables.
*/ */
sjm->copy_field= new Copy_field[sjm->sjm_table_cols.elements]; sjm->copy_field= new Copy_field[sjm->sjm_table_cols.elements];
it.rewind(); //it.rewind();
for (uint i=0; i < sjm->sjm_table_cols.elements; i++) for (uint i=0; i < sjm->sjm_table_cols.elements; i++)
{ {
bool dummy; bool dummy;
......
...@@ -285,7 +285,9 @@ void restore_prev_sj_state(const table_map remaining_tables, ...@@ -285,7 +285,9 @@ void restore_prev_sj_state(const table_map remaining_tables,
const JOIN_TAB *tab, uint idx); const JOIN_TAB *tab, uint idx);
void fix_semijoin_strategies_for_picked_join_order(JOIN *join); void fix_semijoin_strategies_for_picked_join_order(JOIN *join);
bool setup_sj_materialization(JOIN_TAB *tab);
bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab);
bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab);
TABLE *create_duplicate_weedout_tmp_table(THD *thd, uint uniq_tuple_length_arg, TABLE *create_duplicate_weedout_tmp_table(THD *thd, uint uniq_tuple_length_arg,
SJ_TMP_TABLE *sjtbl); SJ_TMP_TABLE *sjtbl);
......
...@@ -90,7 +90,7 @@ static store_key *get_store_key(THD *thd, ...@@ -90,7 +90,7 @@ static store_key *get_store_key(THD *thd,
KEYUSE *keyuse, table_map used_tables, KEYUSE *keyuse, table_map used_tables,
KEY_PART_INFO *key_part, uchar *key_buff, KEY_PART_INFO *key_part, uchar *key_buff,
uint maybe_null); uint maybe_null);
static void make_outerjoin_info(JOIN *join); static bool make_outerjoin_info(JOIN *join);
static Item* static Item*
make_cond_after_sjm(Item *root_cond, Item *cond, table_map tables, table_map sjm_tables); make_cond_after_sjm(Item *root_cond, Item *cond, table_map tables, table_map sjm_tables);
static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item); static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
...@@ -1165,7 +1165,10 @@ JOIN::optimize() ...@@ -1165,7 +1165,10 @@ JOIN::optimize()
} }
reset_nj_counters(this, join_list); reset_nj_counters(this, join_list);
make_outerjoin_info(this); if (make_outerjoin_info(this))
{
DBUG_RETURN(1);
}
/* /*
Among the equal fields belonging to the same multiple equality Among the equal fields belonging to the same multiple equality
...@@ -7625,6 +7628,12 @@ static void add_not_null_conds(JOIN *join) ...@@ -7625,6 +7628,12 @@ static void add_not_null_conds(JOIN *join)
nested outer join and so on until it reaches root_tab nested outer join and so on until it reaches root_tab
(root_tab can be 0). (root_tab can be 0).
In other words:
add_found_match_trig_cond(tab->first_inner_tab, y, 0) is the way one should
wrap parts of WHERE. The idea is that the part of WHERE should be only
evaluated after we've finished figuring out whether outer joins.
^^^ is the above correct?
@param tab the first inner table for most nested outer join @param tab the first inner table for most nested outer join
@param cond the predicate to be guarded (must be set) @param cond the predicate to be guarded (must be set)
@param root_tab the first inner table to stop @param root_tab the first inner table to stop
...@@ -7652,6 +7661,12 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) ...@@ -7652,6 +7661,12 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
} }
bool TABLE_LIST::is_active_sjm()
{
return sj_mat_info && sj_mat_info->is_used;
}
/** /**
Fill in outer join related info for the execution plan structure. Fill in outer join related info for the execution plan structure.
...@@ -7669,6 +7684,12 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) ...@@ -7669,6 +7684,12 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
corresponding first inner table through the field t0->on_expr_ref. corresponding first inner table through the field t0->on_expr_ref.
Here ti are structures of the JOIN_TAB type. Here ti are structures of the JOIN_TAB type.
In other words, for each join tab, set
- first_inner
- last_inner
- first_upper
- on_expr_ref, cond_equal
EXAMPLE. For the query: EXAMPLE. For the query:
@code @code
SELECT * FROM t1 SELECT * FROM t1
...@@ -7694,20 +7715,33 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) ...@@ -7694,20 +7715,33 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
has been chosen. has been chosen.
*/ */
static void static bool
make_outerjoin_info(JOIN *join) make_outerjoin_info(JOIN *join)
{ {
DBUG_ENTER("make_outerjoin_info"); DBUG_ENTER("make_outerjoin_info");
for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_CONST_TABLES); tab;
tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS))
{
TABLE *table=tab->table;
/* /*
psergey: The following is probably incorrect, fix it when we get Create temp. tables for merged SJ-Materialization nests. We need to do
semi+outer joins processing to work: this now, because further code relies on tab->table and
tab->table->pos_in_table_list being set.
*/ */
if (!table) JOIN_TAB *tab;
continue; for (tab= first_linear_tab(join, WITHOUT_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
if (tab->bush_children)
{
if (setup_sj_materialization_part1(tab))
DBUG_RETURN(TRUE);
tab->table->reginfo.join_tab= tab;
}
}
for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_CONST_TABLES); tab;
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
TABLE *table= tab->table;
TABLE_LIST *tbl= table->pos_in_table_list; TABLE_LIST *tbl= table->pos_in_table_list;
TABLE_LIST *embedding= tbl->embedding; TABLE_LIST *embedding= tbl->embedding;
...@@ -7721,11 +7755,16 @@ make_outerjoin_info(JOIN *join) ...@@ -7721,11 +7755,16 @@ make_outerjoin_info(JOIN *join)
tab->last_inner= tab->first_inner= tab; tab->last_inner= tab->first_inner= tab;
tab->on_expr_ref= &tbl->on_expr; tab->on_expr_ref= &tbl->on_expr;
tab->cond_equal= tbl->cond_equal; tab->cond_equal= tbl->cond_equal;
if (embedding) if (embedding && !embedding->is_active_sjm())
tab->first_upper= embedding->nested_join->first_nested; tab->first_upper= embedding->nested_join->first_nested;
} }
for ( ; embedding ; embedding= embedding->embedding) for ( ; embedding ; embedding= embedding->embedding)
{ {
if (embedding->is_active_sjm())
{
/* We're trying to walk out of an SJ-Materialization nest. Don't do this. */
break;
}
/* Ignore sj-nests: */ /* Ignore sj-nests: */
if (!(embedding->on_expr && embedding->outer_join)) if (!(embedding->on_expr && embedding->outer_join))
continue; continue;
...@@ -7757,7 +7796,7 @@ make_outerjoin_info(JOIN *join) ...@@ -7757,7 +7796,7 @@ make_outerjoin_info(JOIN *join)
} }
} }
} }
DBUG_VOID_RETURN; DBUG_RETURN(FALSE);
} }
...@@ -8132,10 +8171,25 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -8132,10 +8171,25 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
the null complemented row. the null complemented row.
*/ */
/* First push down constant conditions from on expressions */ /*
for (JOIN_TAB *join_tab= first_linear_tab(join, WITHOUT_CONST_TABLES); First push down constant conditions from ON expressions.
join_tab; - Each pushed-down condition is wrapped into trigger which is
join_tab= next_linear_tab(join, join_tab, WITH_BUSH_ROOTS)) enabled only for non-NULL-complemented record
- The condition is attached to the first_inner_table.
With regards to join nests:
- if we start at top level, don't walk into nests
- if we start inside a nest, stay within that nest.
*/
JOIN_TAB *start_from= tab->bush_root_tab?
tab->bush_root_tab->bush_children->start :
join->join_tab + join->const_tables;
JOIN_TAB *end_with= tab->bush_root_tab?
tab->bush_root_tab->bush_children->end :
join->join_tab + join->top_join_tab_count;
for (JOIN_TAB *join_tab= start_from;
join_tab != end_with;
join_tab++)
{ {
if (*join_tab->on_expr_ref) if (*join_tab->on_expr_ref)
{ {
...@@ -8160,9 +8214,14 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -8160,9 +8214,14 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
} }
} }
/* Push down non-constant conditions from ON expressions */ /* Push down non-constant conditions from ON expressions */
//JOIN_TAB *first_tab= join->join_tab+join->const_tables;
JOIN_TAB *last_tab= tab; JOIN_TAB *last_tab= tab;
/*
while we're inside of an outer join and last_tab is
the last of its tables ...
*/
while (first_inner_tab && first_inner_tab->last_inner == last_tab) while (first_inner_tab && first_inner_tab->last_inner == last_tab)
{ {
/* /*
...@@ -8173,19 +8232,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -8173,19 +8232,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
table_map used_tables2= (join->const_table_map | table_map used_tables2= (join->const_table_map |
OUTER_REF_TABLE_BIT | RAND_TABLE_BIT); OUTER_REF_TABLE_BIT | RAND_TABLE_BIT);
for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_CONST_TABLES);
tab; start_from= tab->bush_root_tab?
tab= (tab == last_tab)? NULL: next_linear_tab(join, tab, tab->bush_root_tab->bush_children->start :
WITH_BUSH_ROOTS)) join->join_tab + join->const_tables;
{ for (JOIN_TAB *tab= start_from; tab <= last_tab; tab++)
if (!tab->table)
{ {
/* DBUG_ASSERT(tab->table);
psergey-todo: this is probably incorrect, fix this when we get
correct processing for outer joins + semi joins
*/
continue;
}
current_map= tab->table->map; current_map= tab->table->map;
used_tables2|= current_map; used_tables2|= current_map;
/* /*
...@@ -9136,7 +9189,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) ...@@ -9136,7 +9189,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
{ {
if (tab->bush_children) if (tab->bush_children)
{ {
if (setup_sj_materialization(tab)) if (setup_sj_materialization_part2(tab))
return TRUE; return TRUE;
} }
...@@ -15186,6 +15239,26 @@ evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab) ...@@ -15186,6 +15239,26 @@ evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab)
/* /*
The row complemented by nulls satisfies all conditions The row complemented by nulls satisfies all conditions
attached to inner tables. attached to inner tables.
*/
if (join_tab->check_weed_out_table)
{
int res= do_sj_dups_weedout(join->thd, join_tab->check_weed_out_table);
if (res == -1)
return NESTED_LOOP_ERROR;
else if (res == 1)
return NESTED_LOOP_OK;
}
else if (join_tab->do_firstmatch)
{
/*
We should return to the join_tab->do_firstmatch after we have
enumerated all the suffixes for current prefix row combination
*/
if (join_tab->do_firstmatch < join->return_tab)
join->return_tab= join_tab->do_firstmatch;
}
/*
Send the row complemented by nulls to be joined with the Send the row complemented by nulls to be joined with the
remaining tables. remaining tables.
*/ */
...@@ -20566,8 +20639,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -20566,8 +20639,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
examined_rows= tab->limit; examined_rows= tab->limit;
else else
{ {
if (!tab->table->pos_in_table_list || if (tab->table->is_filled_at_execution())
tab->table->is_filled_at_execution()) // temporary, is_filled_at_execution
{ {
examined_rows= tab->records; examined_rows= tab->records;
} }
......
...@@ -204,7 +204,13 @@ typedef struct st_join_table { ...@@ -204,7 +204,13 @@ typedef struct st_join_table {
NULL means no index condition pushdown was performed. NULL means no index condition pushdown was performed.
*/ */
Item *pre_idx_push_select_cond; Item *pre_idx_push_select_cond;
Item **on_expr_ref; /**< pointer to the associated on expression */ /*
Pointer to the associated ON expression. on_expr_ref=!NULL except for
degenerate joins.
*on_expr_ref!=NULL for tables that are first inner tables within an outer
join.
*/
Item **on_expr_ref;
COND_EQUAL *cond_equal; /**< multiple equalities for the on expression */ COND_EQUAL *cond_equal; /**< multiple equalities for the on expression */
st_join_table *first_inner; /**< first inner table for including outerjoin */ st_join_table *first_inner; /**< first inner table for including outerjoin */
bool found; /**< true after all matches or null complement */ bool found; /**< true after all matches or null complement */
...@@ -478,6 +484,8 @@ typedef struct st_join_table { ...@@ -478,6 +484,8 @@ typedef struct st_join_table {
} }
double scan_time(); double scan_time();
bool preread_init(); bool preread_init();
bool is_sjm_nest() { return test(bush_children); }
} JOIN_TAB; } JOIN_TAB;
......
...@@ -5410,9 +5410,11 @@ bool st_table::is_children_attached(void) ...@@ -5410,9 +5410,11 @@ bool st_table::is_children_attached(void)
bool st_table::is_filled_at_execution() bool st_table::is_filled_at_execution()
{ {
return test(pos_in_table_list->jtbm_subselect); return test(pos_in_table_list->jtbm_subselect ||
pos_in_table_list->is_active_sjm());
} }
/* /*
Cleanup this table for re-execution. Cleanup this table for re-execution.
......
...@@ -1765,6 +1765,7 @@ struct TABLE_LIST ...@@ -1765,6 +1765,7 @@ struct TABLE_LIST
respectively. respectively.
*/ */
char *get_table_name() { return view != NULL ? view_name.str : table_name; } char *get_table_name() { return view != NULL ? view_name.str : table_name; }
bool is_active_sjm();
st_select_lex_unit *get_unit(); st_select_lex_unit *get_unit();
st_select_lex *get_single_select(); st_select_lex *get_single_select();
void wrap_into_nested_join(List<TABLE_LIST> &join_list); void wrap_into_nested_join(List<TABLE_LIST> &join_list);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment