mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 12:32:27 +01:00
Automatic merge.
This commit is contained in:
commit
06fb641c0b
7 changed files with 788 additions and 119 deletions
|
@ -1190,6 +1190,54 @@ set @@optimizer_switch='materialization=off,semijoin=on';
|
|||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
drop table t1, t2;
|
||||
#
|
||||
# LP BUG#777691 Wrong result with subqery in select list and subquery cache=off in maria-5.3
|
||||
#
|
||||
CREATE TABLE t1 ( f1 varchar(32)) ;
|
||||
INSERT INTO t1 VALUES ('b'),('x'),('c'),('x');
|
||||
CREATE TABLE t2 ( f2 int, f3 varchar(32)) ;
|
||||
INSERT INTO t2 VALUES (1,'x');
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch='materialization=off,in_to_exists=on,subquery_cache=off';
|
||||
EXPLAIN
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 4
|
||||
2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
f1 max_f2
|
||||
b NULL
|
||||
x 1
|
||||
c NULL
|
||||
x 1
|
||||
set @@optimizer_switch='materialization=on,in_to_exists=off,subquery_cache=off';
|
||||
EXPLAIN
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 4
|
||||
2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
f1 max_f2
|
||||
b NULL
|
||||
x 1
|
||||
c NULL
|
||||
x 1
|
||||
set @@optimizer_switch='materialization=off,in_to_exists=on,subquery_cache=off';
|
||||
Even when t2 is not constant table, the result must be the same.
|
||||
INSERT INTO t2 VALUES (2,'y');
|
||||
EXPLAIN
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 4
|
||||
2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
f1 max_f2
|
||||
b NULL
|
||||
x 1
|
||||
c NULL
|
||||
x 1
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
drop table t1, t2;
|
||||
#
|
||||
# LP BUG#641203 Query returns rows where no result is expected (impossible WHERE)
|
||||
#
|
||||
CREATE TABLE t1 (c1 varchar(1) DEFAULT NULL);
|
||||
|
|
|
@ -1,8 +1,210 @@
|
|||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
-------------------------------
|
||||
Part 1: Feature tests.
|
||||
-------------------------------
|
||||
Default for all tests.
|
||||
set @@optimizer_switch="materialization=on,in_to_exists=off,semijoin=off,subquery_cache=off";
|
||||
|
||||
Schema requires partial matching, but data analysis discoveres there is
|
||||
no need. This is possible only if all outer columns are not NULL.
|
||||
|
||||
create table t1 (a1 char(8) not null, a2 char(8) not null);
|
||||
create table t2 (b1 char(8), b2 char(8));
|
||||
insert into t1 values ('1 - 00', '2 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01');
|
||||
insert into t2 values ('1 - 00', '2 - 00');
|
||||
insert into t2 values ('1 - 01', NULL );
|
||||
insert into t2 values (NULL , '2 - 02');
|
||||
insert into t2 values (NULL , NULL );
|
||||
insert into t2 values ('1 - 02', '2 - 02');
|
||||
select * from t1
|
||||
where (a1, a2) not in (select * from t2 where b1 is not null and b2 is not null);
|
||||
a1 a2
|
||||
1 - 01 2 - 01
|
||||
select a1, a2, (a1, a2) not in (select * from t2) as in_res from t1;
|
||||
a1 a2 in_res
|
||||
1 - 00 2 - 00 0
|
||||
1 - 01 2 - 01 NULL
|
||||
drop table t1, t2;
|
||||
|
||||
NULLs in the outer columns, no NULLs in the suqbuery
|
||||
|
||||
create table t1 (a1 char(8), a2 char(8));
|
||||
create table t2 (b1 char(8) not null, b2 char(8) not null);
|
||||
insert into t1 values (NULL , '2 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01');
|
||||
insert into t1 values (NULL , NULL );
|
||||
insert into t2 values ('1 - 00', '2 - 00');
|
||||
insert into t2 values ('1 - 01', '2 - 01');
|
||||
insert into t2 values ('1 - 02', '2 - 00');
|
||||
select * from t1
|
||||
where (a1, a2) not in (select * from t2 where b1 is not null and b2 is not null);
|
||||
a1 a2
|
||||
select a1, a2, (a1, a2) not in (select * from t2) as in_res from t1;
|
||||
a1 a2 in_res
|
||||
NULL 2 - 00 NULL
|
||||
1 - 01 2 - 01 0
|
||||
NULL NULL NULL
|
||||
select * from t1
|
||||
where (a1, a2) in (select * from t2 where b1 is not null and b2 is not null);
|
||||
a1 a2
|
||||
1 - 01 2 - 01
|
||||
select a1, a2, (a1, a2) in (select * from t2) as in_res from t1;
|
||||
a1 a2 in_res
|
||||
NULL 2 - 00 NULL
|
||||
1 - 01 2 - 01 1
|
||||
NULL NULL NULL
|
||||
drop table t1, t2;
|
||||
|
||||
All columns require partial matching (no non-null columns)
|
||||
|
||||
TODO
|
||||
|
||||
Both non-NULL columns and columns with NULLs
|
||||
|
||||
TODO
|
||||
|
||||
Covering NULL rows
|
||||
|
||||
create table t1 (a1 char(8), a2 char(8));
|
||||
create table t2 (b1 char(8), b2 char(8));
|
||||
insert into t1 values ('1 - 00', '2 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01');
|
||||
insert into t2 values ('1 - 01', NULL );
|
||||
insert into t2 values (NULL , '2 - 02');
|
||||
insert into t2 values (NULL , NULL );
|
||||
insert into t2 values ('1 - 02', '2 - 02');
|
||||
select * from t1
|
||||
where (a1, a2) not in (select * from t2);
|
||||
a1 a2
|
||||
select a1, a2, (a1, a2) not in (select * from t2) as in_res from t1;
|
||||
a1 a2 in_res
|
||||
1 - 00 2 - 00 NULL
|
||||
1 - 01 2 - 01 NULL
|
||||
insert into t2 values ('1 - 01', '2 - 01');
|
||||
select * from t1
|
||||
where (a1, a2) not in (select * from t2);
|
||||
a1 a2
|
||||
select a1, a2, (a1, a2) not in (select * from t2) as in_res from t1;
|
||||
a1 a2 in_res
|
||||
1 - 00 2 - 00 NULL
|
||||
1 - 01 2 - 01 0
|
||||
select * from t1
|
||||
where (a1, a2) in (select * from t2);
|
||||
a1 a2
|
||||
1 - 01 2 - 01
|
||||
select a1, a2, (a1, a2) in (select * from t2) as in_res from t1;
|
||||
a1 a2 in_res
|
||||
1 - 00 2 - 00 NULL
|
||||
1 - 01 2 - 01 1
|
||||
drop table t1, t2;
|
||||
|
||||
Covering NULL columns
|
||||
|
||||
this case affects only the rowid-merge algorithm
|
||||
set @@optimizer_switch="partial_match_rowid_merge=on,partial_match_table_scan=off";
|
||||
create table t1 (a1 char(8) not null, a2 char(8), a3 char(8) not null);
|
||||
create table t2 (b1 char(8) not null, b2 char(8), b3 char(8) not null);
|
||||
insert into t1 values ('1 - 00', '2 - 00', '3 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01', '3 - 01');
|
||||
insert into t2 values ('1 - 01', NULL, '3 - x1');
|
||||
insert into t2 values ('1 - 02', NULL, '3 - 02');
|
||||
insert into t2 values ('1 - 00', NULL, '3 - 00');
|
||||
select * from t1
|
||||
where (a1, a2, a3) not in (select * from t2);
|
||||
a1 a2 a3
|
||||
1 - 01 2 - 01 3 - 01
|
||||
select *, (a1, a2, a3) not in (select * from t2) as in_res from t1;
|
||||
a1 a2 a3 in_res
|
||||
1 - 00 2 - 00 3 - 00 NULL
|
||||
1 - 01 2 - 01 3 - 01 1
|
||||
select * from t1
|
||||
where (a1, a2, a3) in (select * from t2);
|
||||
a1 a2 a3
|
||||
select *, (a1, a2, a3) in (select * from t2) as in_res from t1;
|
||||
a1 a2 a3 in_res
|
||||
1 - 00 2 - 00 3 - 00 NULL
|
||||
1 - 01 2 - 01 3 - 01 0
|
||||
drop table t1, t2;
|
||||
create table t1 (a1 char(8), a2 char(8), a3 char(8) not null);
|
||||
create table t2 (b1 char(8), b2 char(8), b3 char(8) not null);
|
||||
insert into t1 values ('1 - 00', '2 - 00', '3 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01', '3 - 01');
|
||||
insert into t2 values (NULL, NULL, '3 - x1');
|
||||
insert into t2 values (NULL, NULL, '3 - 02');
|
||||
insert into t2 values (NULL, NULL, '3 - 00');
|
||||
select * from t1
|
||||
where (a1, a2, a3) not in (select * from t2);
|
||||
a1 a2 a3
|
||||
1 - 01 2 - 01 3 - 01
|
||||
select *, (a1, a2, a3) not in (select * from t2) as in_res from t1;
|
||||
a1 a2 a3 in_res
|
||||
1 - 00 2 - 00 3 - 00 NULL
|
||||
1 - 01 2 - 01 3 - 01 1
|
||||
select * from t1
|
||||
where (a1, a2, a3) in (select * from t2);
|
||||
a1 a2 a3
|
||||
select *, (a1, a2, a3) in (select * from t2) as in_res from t1;
|
||||
a1 a2 a3 in_res
|
||||
1 - 00 2 - 00 3 - 00 NULL
|
||||
1 - 01 2 - 01 3 - 01 0
|
||||
drop table t1, t2;
|
||||
|
||||
Covering NULL row, and a NULL column
|
||||
|
||||
create table t1 (a1 char(8) not null, a2 char(8), a3 char(8));
|
||||
create table t2 (b1 char(8), b2 char(8), b3 char(8));
|
||||
insert into t1 values ('1 - 00', '2 - 00', '3 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01', '3 - 01');
|
||||
insert into t2 values ('1 - 01', NULL, '3 - x1');
|
||||
insert into t2 values (NULL , NULL, NULL );
|
||||
insert into t2 values ('1 - 00', NULL, '3 - 00');
|
||||
select * from t1
|
||||
where (a1, a2, a3) not in (select * from t2);
|
||||
a1 a2 a3
|
||||
select *, (a1, a2, a3) not in (select * from t2) as in_res from t1;
|
||||
a1 a2 a3 in_res
|
||||
1 - 00 2 - 00 3 - 00 NULL
|
||||
1 - 01 2 - 01 3 - 01 NULL
|
||||
select * from t1
|
||||
where (a1, a2, a3) in (select * from t2);
|
||||
a1 a2 a3
|
||||
select *, (a1, a2, a3) in (select * from t2) as in_res from t1;
|
||||
a1 a2 a3 in_res
|
||||
1 - 00 2 - 00 3 - 00 NULL
|
||||
1 - 01 2 - 01 3 - 01 NULL
|
||||
drop table t1, t2;
|
||||
|
||||
Covering NULL row, and covering NULL columns
|
||||
|
||||
create table t1 (a1 char(8) not null, a2 char(8), a3 char(8));
|
||||
create table t2 (b1 char(8), b2 char(8), b3 char(8));
|
||||
insert into t1 values ('1 - 00', '2 - 00', '3 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01', '3 - 01');
|
||||
insert into t2 values (NULL, NULL, NULL);
|
||||
insert into t2 values (NULL, NULL, NULL);
|
||||
select * from t1
|
||||
where (a1, a2, a3) not in (select * from t2);
|
||||
a1 a2 a3
|
||||
select *, (a1, a2, a3) not in (select * from t2) as in_res from t1;
|
||||
a1 a2 a3 in_res
|
||||
1 - 00 2 - 00 3 - 00 NULL
|
||||
1 - 01 2 - 01 3 - 01 NULL
|
||||
select * from t1
|
||||
where (a1, a2, a3) in (select * from t2);
|
||||
a1 a2 a3
|
||||
select *, (a1, a2, a3) in (select * from t2) as in_res from t1;
|
||||
a1 a2 a3 in_res
|
||||
1 - 00 2 - 00 3 - 00 NULL
|
||||
1 - 01 2 - 01 3 - 01 NULL
|
||||
drop table t1, t2;
|
||||
-------------------------------
|
||||
Part 2: Test cases for bugs.
|
||||
-------------------------------
|
||||
drop table if exists t1, t2;
|
||||
#
|
||||
# LP BUG#608744
|
||||
#
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off";
|
||||
create table t1 (a1 char(1), a2 char(1));
|
||||
insert into t1 values (NULL, 'b');
|
||||
|
@ -11,7 +213,6 @@ insert into t2 values ('a','b'), ('c', 'd');
|
|||
select * from t1 where (a1, a2) NOT IN (select b1, b2 from t2);
|
||||
a1 a2
|
||||
drop table t1,t2;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
#
|
||||
# LP BUG#601156
|
||||
#
|
||||
|
@ -21,7 +222,6 @@ INSERT INTO t1 VALUES (4,NULL);
|
|||
CREATE TABLE t2 (b1 int DEFAULT NULL, b2 int DEFAULT NULL);
|
||||
INSERT INTO t2 VALUES (6,NULL);
|
||||
INSERT INTO t2 VALUES (NULL,0);
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on';
|
||||
EXPLAIN EXTENDED
|
||||
SELECT * FROM (SELECT * FROM t1 WHERE a1 NOT IN (SELECT b2 FROM t2)) table1;
|
||||
|
@ -31,11 +231,9 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
|||
Warnings:
|
||||
Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( <materialize> (select `test`.`t2`.`b2` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `<subquery3>`.`b2`)))))))
|
||||
DROP TABLE t1, t2;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
#
|
||||
# LP BUG#613009 Crash in Ordered_key::get_field_idx
|
||||
#
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off';
|
||||
create table t1 (a1 char(3) DEFAULT NULL, a2 char(3) DEFAULT NULL);
|
||||
insert into t1 values (NULL, 'a21'), (NULL, 'a22');
|
||||
|
@ -46,7 +244,6 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||
select * from t1 where (a1, a2) not in (select a1, a2 from t1);
|
||||
a1 a2
|
||||
drop table t1;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
#
|
||||
# LP BUG#680058 void Ordered_key::add_key(rownum_t):
|
||||
# Assertion `key_buff_elements && cur_key_idx < key_buff_elements' failed
|
||||
|
@ -55,10 +252,99 @@ create table t1 (f1 char(1), f2 char(1));
|
|||
insert into t1 values ('t', '0'), ('0', 't');
|
||||
create table t2 (f3 char(1), f4 char(1));
|
||||
insert into t2 values ('t', NULL), ('t', NULL), ('d', 'y');
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
SET @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,semijoin=off';
|
||||
set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,semijoin=off';
|
||||
select * from t1 where (f1, f2) not in (select * from t2);
|
||||
f1 f2
|
||||
0 t
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
drop table t1, t2;
|
||||
#
|
||||
# LP BUG#809245 Second assertion `bit < (map)->n_bits' with partial_match_merge
|
||||
#
|
||||
CREATE TABLE t1 (d varchar(32)) ;
|
||||
INSERT INTO t1 VALUES ('r');
|
||||
CREATE TABLE t2 ( a int, c varchar(32)) ;
|
||||
INSERT INTO t2 VALUES (5,'r');
|
||||
CREATE TABLE t3 ( a int NOT NULL , d varchar(32)) ;
|
||||
INSERT INTO t3 VALUES (10,'g');
|
||||
set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,in_to_exists=off';
|
||||
EXPLAIN SELECT *
|
||||
FROM t1
|
||||
WHERE (t1.d , t1.d) NOT IN (
|
||||
SELECT t3.d , t2.c
|
||||
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 system NULL NULL NULL NULL 1
|
||||
2 SUBQUERY t3 system NULL NULL NULL NULL 1
|
||||
2 SUBQUERY t2 system NULL NULL NULL NULL 1
|
||||
SELECT *
|
||||
FROM t1
|
||||
WHERE (t1.d , t1.d) NOT IN (
|
||||
SELECT t3.d , t2.c
|
||||
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
|
||||
d
|
||||
r
|
||||
set @@optimizer_switch='materialization=off,in_to_exists=on';
|
||||
EXPLAIN SELECT *
|
||||
FROM t1
|
||||
WHERE (t1.d , t1.d) NOT IN (
|
||||
SELECT t3.d , t2.c
|
||||
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 system NULL NULL NULL NULL 1
|
||||
2 DEPENDENT SUBQUERY t3 system NULL NULL NULL NULL 1
|
||||
2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1
|
||||
SELECT *
|
||||
FROM t1
|
||||
WHERE (t1.d , t1.d) NOT IN (
|
||||
SELECT t3.d , t2.c
|
||||
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
|
||||
d
|
||||
r
|
||||
drop table t1, t2, t3;
|
||||
#
|
||||
# LP BUG#809266 Diverging results with partial_match_rowid_merge=on
|
||||
#
|
||||
CREATE TABLE t1 (c int) ;
|
||||
INSERT INTO t1 VALUES (0),(0);
|
||||
CREATE TABLE t2 (a int, b int) ;
|
||||
INSERT INTO t2 VALUES (6,3), (9,NULL);
|
||||
set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,in_to_exists=off';
|
||||
EXPLAIN
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
|
||||
2 SUBQUERY t2 ALL NULL NULL NULL NULL 2
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2);
|
||||
c
|
||||
0
|
||||
0
|
||||
EXPLAIN
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
|
||||
2 SUBQUERY t2 ALL NULL NULL NULL NULL 2
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2);
|
||||
c
|
||||
0
|
||||
0
|
||||
set @@optimizer_switch='materialization=off,in_to_exists=on';
|
||||
EXPLAIN
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
|
||||
2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2);
|
||||
c
|
||||
0
|
||||
0
|
||||
EXPLAIN
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
|
||||
2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2);
|
||||
c
|
||||
0
|
||||
0
|
||||
drop table t1, t2;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
|
|
@ -964,6 +964,40 @@ WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1);
|
|||
-- echo set @@optimizer_switch='materialization=off,semijoin=on';
|
||||
|
||||
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # LP BUG#777691 Wrong result with subqery in select list and subquery cache=off in maria-5.3
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 ( f1 varchar(32)) ;
|
||||
INSERT INTO t1 VALUES ('b'),('x'),('c'),('x');
|
||||
|
||||
CREATE TABLE t2 ( f2 int, f3 varchar(32)) ;
|
||||
INSERT INTO t2 VALUES (1,'x');
|
||||
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch='materialization=off,in_to_exists=on,subquery_cache=off';
|
||||
|
||||
EXPLAIN
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
|
||||
set @@optimizer_switch='materialization=on,in_to_exists=off,subquery_cache=off';
|
||||
EXPLAIN
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
|
||||
set @@optimizer_switch='materialization=off,in_to_exists=on,subquery_cache=off';
|
||||
--echo Even when t2 is not constant table, the result must be the same.
|
||||
INSERT INTO t2 VALUES (2,'y');
|
||||
EXPLAIN
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
SELECT t1.f1, ( SELECT MAX( f2 ) FROM t2 WHERE t2.f3 = t1.f1 ) as max_f2 FROM t1;
|
||||
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
drop table t1, t2;
|
||||
|
|
|
@ -3,6 +3,221 @@
|
|||
# MWL#68: Subquery optimization: Efficient NOT IN execution with NULLs
|
||||
#
|
||||
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
|
||||
--echo -------------------------------
|
||||
--echo Part 1: Feature tests.
|
||||
--echo -------------------------------
|
||||
|
||||
--echo Default for all tests.
|
||||
set @@optimizer_switch="materialization=on,in_to_exists=off,semijoin=off,subquery_cache=off";
|
||||
|
||||
--echo
|
||||
--echo Schema requires partial matching, but data analysis discoveres there is
|
||||
--echo no need. This is possible only if all outer columns are not NULL.
|
||||
--echo
|
||||
|
||||
create table t1 (a1 char(8) not null, a2 char(8) not null);
|
||||
create table t2 (b1 char(8), b2 char(8));
|
||||
|
||||
insert into t1 values ('1 - 00', '2 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01');
|
||||
|
||||
insert into t2 values ('1 - 00', '2 - 00');
|
||||
insert into t2 values ('1 - 01', NULL );
|
||||
insert into t2 values (NULL , '2 - 02');
|
||||
insert into t2 values (NULL , NULL );
|
||||
insert into t2 values ('1 - 02', '2 - 02');
|
||||
|
||||
select * from t1
|
||||
where (a1, a2) not in (select * from t2 where b1 is not null and b2 is not null);
|
||||
|
||||
select a1, a2, (a1, a2) not in (select * from t2) as in_res from t1;
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
--echo
|
||||
--echo NULLs in the outer columns, no NULLs in the suqbuery
|
||||
--echo
|
||||
|
||||
create table t1 (a1 char(8), a2 char(8));
|
||||
create table t2 (b1 char(8) not null, b2 char(8) not null);
|
||||
|
||||
insert into t1 values (NULL , '2 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01');
|
||||
insert into t1 values (NULL , NULL );
|
||||
|
||||
insert into t2 values ('1 - 00', '2 - 00');
|
||||
insert into t2 values ('1 - 01', '2 - 01');
|
||||
insert into t2 values ('1 - 02', '2 - 00');
|
||||
|
||||
select * from t1
|
||||
where (a1, a2) not in (select * from t2 where b1 is not null and b2 is not null);
|
||||
|
||||
select a1, a2, (a1, a2) not in (select * from t2) as in_res from t1;
|
||||
|
||||
select * from t1
|
||||
where (a1, a2) in (select * from t2 where b1 is not null and b2 is not null);
|
||||
|
||||
select a1, a2, (a1, a2) in (select * from t2) as in_res from t1;
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
--echo
|
||||
--echo All columns require partial matching (no non-null columns)
|
||||
--echo
|
||||
|
||||
--echo TODO
|
||||
|
||||
--echo
|
||||
--echo Both non-NULL columns and columns with NULLs
|
||||
--echo
|
||||
|
||||
--echo TODO
|
||||
|
||||
--echo
|
||||
--echo Covering NULL rows
|
||||
--echo
|
||||
|
||||
create table t1 (a1 char(8), a2 char(8));
|
||||
create table t2 (b1 char(8), b2 char(8));
|
||||
|
||||
insert into t1 values ('1 - 00', '2 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01');
|
||||
|
||||
insert into t2 values ('1 - 01', NULL );
|
||||
insert into t2 values (NULL , '2 - 02');
|
||||
insert into t2 values (NULL , NULL );
|
||||
insert into t2 values ('1 - 02', '2 - 02');
|
||||
|
||||
select * from t1
|
||||
where (a1, a2) not in (select * from t2);
|
||||
|
||||
select a1, a2, (a1, a2) not in (select * from t2) as in_res from t1;
|
||||
|
||||
insert into t2 values ('1 - 01', '2 - 01');
|
||||
|
||||
select * from t1
|
||||
where (a1, a2) not in (select * from t2);
|
||||
|
||||
select a1, a2, (a1, a2) not in (select * from t2) as in_res from t1;
|
||||
|
||||
select * from t1
|
||||
where (a1, a2) in (select * from t2);
|
||||
|
||||
select a1, a2, (a1, a2) in (select * from t2) as in_res from t1;
|
||||
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
--echo
|
||||
--echo Covering NULL columns
|
||||
--echo
|
||||
|
||||
--echo this case affects only the rowid-merge algorithm
|
||||
set @@optimizer_switch="partial_match_rowid_merge=on,partial_match_table_scan=off";
|
||||
|
||||
create table t1 (a1 char(8) not null, a2 char(8), a3 char(8) not null);
|
||||
create table t2 (b1 char(8) not null, b2 char(8), b3 char(8) not null);
|
||||
|
||||
insert into t1 values ('1 - 00', '2 - 00', '3 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01', '3 - 01');
|
||||
|
||||
insert into t2 values ('1 - 01', NULL, '3 - x1');
|
||||
insert into t2 values ('1 - 02', NULL, '3 - 02');
|
||||
insert into t2 values ('1 - 00', NULL, '3 - 00');
|
||||
|
||||
select * from t1
|
||||
where (a1, a2, a3) not in (select * from t2);
|
||||
|
||||
select *, (a1, a2, a3) not in (select * from t2) as in_res from t1;
|
||||
|
||||
select * from t1
|
||||
where (a1, a2, a3) in (select * from t2);
|
||||
|
||||
select *, (a1, a2, a3) in (select * from t2) as in_res from t1;
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
create table t1 (a1 char(8), a2 char(8), a3 char(8) not null);
|
||||
create table t2 (b1 char(8), b2 char(8), b3 char(8) not null);
|
||||
|
||||
insert into t1 values ('1 - 00', '2 - 00', '3 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01', '3 - 01');
|
||||
|
||||
insert into t2 values (NULL, NULL, '3 - x1');
|
||||
insert into t2 values (NULL, NULL, '3 - 02');
|
||||
insert into t2 values (NULL, NULL, '3 - 00');
|
||||
|
||||
select * from t1
|
||||
where (a1, a2, a3) not in (select * from t2);
|
||||
|
||||
select *, (a1, a2, a3) not in (select * from t2) as in_res from t1;
|
||||
|
||||
select * from t1
|
||||
where (a1, a2, a3) in (select * from t2);
|
||||
|
||||
select *, (a1, a2, a3) in (select * from t2) as in_res from t1;
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
--echo
|
||||
--echo Covering NULL row, and a NULL column
|
||||
--echo
|
||||
|
||||
create table t1 (a1 char(8) not null, a2 char(8), a3 char(8));
|
||||
create table t2 (b1 char(8), b2 char(8), b3 char(8));
|
||||
|
||||
insert into t1 values ('1 - 00', '2 - 00', '3 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01', '3 - 01');
|
||||
|
||||
insert into t2 values ('1 - 01', NULL, '3 - x1');
|
||||
insert into t2 values (NULL , NULL, NULL );
|
||||
insert into t2 values ('1 - 00', NULL, '3 - 00');
|
||||
|
||||
select * from t1
|
||||
where (a1, a2, a3) not in (select * from t2);
|
||||
|
||||
select *, (a1, a2, a3) not in (select * from t2) as in_res from t1;
|
||||
|
||||
select * from t1
|
||||
where (a1, a2, a3) in (select * from t2);
|
||||
|
||||
select *, (a1, a2, a3) in (select * from t2) as in_res from t1;
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
|
||||
--echo
|
||||
--echo Covering NULL row, and covering NULL columns
|
||||
--echo
|
||||
|
||||
create table t1 (a1 char(8) not null, a2 char(8), a3 char(8));
|
||||
create table t2 (b1 char(8), b2 char(8), b3 char(8));
|
||||
|
||||
insert into t1 values ('1 - 00', '2 - 00', '3 - 00');
|
||||
insert into t1 values ('1 - 01', '2 - 01', '3 - 01');
|
||||
|
||||
insert into t2 values (NULL, NULL, NULL);
|
||||
insert into t2 values (NULL, NULL, NULL);
|
||||
|
||||
select * from t1
|
||||
where (a1, a2, a3) not in (select * from t2);
|
||||
|
||||
select *, (a1, a2, a3) not in (select * from t2) as in_res from t1;
|
||||
|
||||
select * from t1
|
||||
where (a1, a2, a3) in (select * from t2);
|
||||
|
||||
select *, (a1, a2, a3) in (select * from t2) as in_res from t1;
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
|
||||
--echo -------------------------------
|
||||
--echo Part 2: Test cases for bugs.
|
||||
--echo -------------------------------
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
|
@ -10,7 +225,6 @@ drop table if exists t1, t2;
|
|||
--echo #
|
||||
--echo # LP BUG#608744
|
||||
--echo #
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch="materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off";
|
||||
create table t1 (a1 char(1), a2 char(1));
|
||||
insert into t1 values (NULL, 'b');
|
||||
|
@ -18,7 +232,6 @@ create table t2 (b1 char(1), b2 char(2));
|
|||
insert into t2 values ('a','b'), ('c', 'd');
|
||||
select * from t1 where (a1, a2) NOT IN (select b1, b2 from t2);
|
||||
drop table t1,t2;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
|
||||
--echo #
|
||||
|
@ -32,20 +245,17 @@ CREATE TABLE t2 (b1 int DEFAULT NULL, b2 int DEFAULT NULL);
|
|||
INSERT INTO t2 VALUES (6,NULL);
|
||||
INSERT INTO t2 VALUES (NULL,0);
|
||||
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on';
|
||||
|
||||
EXPLAIN EXTENDED
|
||||
SELECT * FROM (SELECT * FROM t1 WHERE a1 NOT IN (SELECT b2 FROM t2)) table1;
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
--echo #
|
||||
--echo # LP BUG#613009 Crash in Ordered_key::get_field_idx
|
||||
--echo #
|
||||
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off';
|
||||
|
||||
create table t1 (a1 char(3) DEFAULT NULL, a2 char(3) DEFAULT NULL);
|
||||
|
@ -53,7 +263,6 @@ insert into t1 values (NULL, 'a21'), (NULL, 'a22');
|
|||
explain select * from t1 where (a1, a2) not in (select a1, a2 from t1);
|
||||
select * from t1 where (a1, a2) not in (select a1, a2 from t1);
|
||||
drop table t1;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
--echo #
|
||||
--echo # LP BUG#680058 void Ordered_key::add_key(rownum_t):
|
||||
|
@ -65,8 +274,84 @@ insert into t1 values ('t', '0'), ('0', 't');
|
|||
create table t2 (f3 char(1), f4 char(1));
|
||||
insert into t2 values ('t', NULL), ('t', NULL), ('d', 'y');
|
||||
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
SET @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,semijoin=off';
|
||||
set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,semijoin=off';
|
||||
select * from t1 where (f1, f2) not in (select * from t2);
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
drop table t1, t2;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # LP BUG#809245 Second assertion `bit < (map)->n_bits' with partial_match_merge
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (d varchar(32)) ;
|
||||
INSERT INTO t1 VALUES ('r');
|
||||
|
||||
CREATE TABLE t2 ( a int, c varchar(32)) ;
|
||||
INSERT INTO t2 VALUES (5,'r');
|
||||
|
||||
CREATE TABLE t3 ( a int NOT NULL , d varchar(32)) ;
|
||||
INSERT INTO t3 VALUES (10,'g');
|
||||
|
||||
set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,in_to_exists=off';
|
||||
|
||||
EXPLAIN SELECT *
|
||||
FROM t1
|
||||
WHERE (t1.d , t1.d) NOT IN (
|
||||
SELECT t3.d , t2.c
|
||||
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
|
||||
|
||||
SELECT *
|
||||
FROM t1
|
||||
WHERE (t1.d , t1.d) NOT IN (
|
||||
SELECT t3.d , t2.c
|
||||
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
|
||||
|
||||
set @@optimizer_switch='materialization=off,in_to_exists=on';
|
||||
|
||||
EXPLAIN SELECT *
|
||||
FROM t1
|
||||
WHERE (t1.d , t1.d) NOT IN (
|
||||
SELECT t3.d , t2.c
|
||||
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
|
||||
|
||||
SELECT *
|
||||
FROM t1
|
||||
WHERE (t1.d , t1.d) NOT IN (
|
||||
SELECT t3.d , t2.c
|
||||
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
|
||||
|
||||
drop table t1, t2, t3;
|
||||
|
||||
--echo #
|
||||
--echo # LP BUG#809266 Diverging results with partial_match_rowid_merge=on
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (c int) ;
|
||||
INSERT INTO t1 VALUES (0),(0);
|
||||
|
||||
CREATE TABLE t2 (a int, b int) ;
|
||||
INSERT INTO t2 VALUES (6,3), (9,NULL);
|
||||
|
||||
set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,in_to_exists=off';
|
||||
|
||||
EXPLAIN
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2);
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2);
|
||||
|
||||
EXPLAIN
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2);
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2);
|
||||
|
||||
set @@optimizer_switch='materialization=off,in_to_exists=on';
|
||||
|
||||
EXPLAIN
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2);
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT b, a FROM t2);
|
||||
|
||||
EXPLAIN
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2);
|
||||
SELECT * FROM t1 WHERE (6, 4 ) NOT IN (SELECT a, b FROM t2);
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
|
|
@ -1406,9 +1406,9 @@ String *Item_in_subselect::val_str(String *str)
|
|||
bool Item_in_subselect::val_bool()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
null_value= was_null= FALSE;
|
||||
if (forced_const)
|
||||
return value;
|
||||
null_value= was_null= FALSE;
|
||||
if (exec())
|
||||
{
|
||||
reset();
|
||||
|
@ -3864,8 +3864,7 @@ subselect_hash_sj_engine::get_strategy_using_data()
|
|||
bitmap_set_bit(&non_null_key_parts, i);
|
||||
--count_partial_match_columns;
|
||||
}
|
||||
if (result_sink->get_null_count_of_col(i) ==
|
||||
tmp_table->file->stats.records)
|
||||
if (result_sink->get_null_count_of_col(i) == tmp_table->file->stats.records)
|
||||
++count_null_only_columns;
|
||||
}
|
||||
|
||||
|
@ -4573,29 +4572,50 @@ int subselect_hash_sj_engine::exec()
|
|||
if (strategy == PARTIAL_MATCH)
|
||||
{
|
||||
uint count_pm_keys; /* Total number of keys needed for partial matching. */
|
||||
MY_BITMAP *nn_key_parts; /* The key parts of the only non-NULL index. */
|
||||
uint covering_null_row_width;
|
||||
MY_BITMAP *nn_key_parts= NULL; /* Key parts of the only non-NULL index. */
|
||||
uint count_non_null_columns= 0; /* Number of columns in nn_key_parts. */
|
||||
bool has_covering_null_row;
|
||||
bool has_covering_null_columns;
|
||||
select_materialize_with_stats *result_sink=
|
||||
(select_materialize_with_stats *) result;
|
||||
uint field_count= tmp_table->s->fields;
|
||||
|
||||
nn_key_parts= (count_partial_match_columns < tmp_table->s->fields) ?
|
||||
&non_null_key_parts : NULL;
|
||||
if (count_partial_match_columns < field_count)
|
||||
{
|
||||
nn_key_parts= &non_null_key_parts;
|
||||
count_non_null_columns= bitmap_bits_set(nn_key_parts);
|
||||
}
|
||||
has_covering_null_row= (result_sink->get_max_nulls_in_row() == field_count);
|
||||
has_covering_null_columns= (count_non_null_columns +
|
||||
count_null_only_columns == field_count);
|
||||
|
||||
if (result_sink->get_max_nulls_in_row() ==
|
||||
tmp_table->s->fields -
|
||||
(nn_key_parts ? bitmap_bits_set(nn_key_parts) : 0))
|
||||
covering_null_row_width= result_sink->get_max_nulls_in_row();
|
||||
else
|
||||
covering_null_row_width= 0;
|
||||
if (has_covering_null_row && has_covering_null_columns)
|
||||
{
|
||||
/*
|
||||
The whole table consist of only NULL values. The result of IN is
|
||||
a constant UNKNOWN.
|
||||
*/
|
||||
DBUG_ASSERT(tmp_table->file->stats.records == 1);
|
||||
item_in->value= 0;
|
||||
item_in->null_value= 1;
|
||||
item_in->make_const();
|
||||
item_in->set_first_execution();
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
if (covering_null_row_width)
|
||||
count_pm_keys= nn_key_parts ? 1 : 0;
|
||||
if (has_covering_null_row)
|
||||
{
|
||||
DBUG_ASSERT(count_partial_match_columns = field_count);
|
||||
count_pm_keys= 0;
|
||||
}
|
||||
else if (has_covering_null_columns)
|
||||
count_pm_keys= 1;
|
||||
else
|
||||
count_pm_keys= count_partial_match_columns - count_null_only_columns +
|
||||
(nn_key_parts ? 1 : 0);
|
||||
(nn_key_parts ? 1 : 0);
|
||||
|
||||
choose_partial_match_strategy(test(nn_key_parts),
|
||||
test(covering_null_row_width),
|
||||
has_covering_null_row,
|
||||
&partial_match_key_parts);
|
||||
DBUG_ASSERT(strategy == PARTIAL_MATCH_MERGE ||
|
||||
strategy == PARTIAL_MATCH_SCAN);
|
||||
|
@ -4605,7 +4625,8 @@ int subselect_hash_sj_engine::exec()
|
|||
new subselect_rowid_merge_engine(thd, (subselect_uniquesubquery_engine*)
|
||||
lookup_engine, tmp_table,
|
||||
count_pm_keys,
|
||||
covering_null_row_width,
|
||||
has_covering_null_row,
|
||||
has_covering_null_columns,
|
||||
item, result,
|
||||
semi_join_conds->argument_list());
|
||||
if (!pm_engine ||
|
||||
|
@ -4630,7 +4651,8 @@ int subselect_hash_sj_engine::exec()
|
|||
lookup_engine, tmp_table,
|
||||
item, result,
|
||||
semi_join_conds->argument_list(),
|
||||
covering_null_row_width)))
|
||||
has_covering_null_row,
|
||||
has_covering_null_columns)))
|
||||
{
|
||||
/* This is an irrecoverable error. */
|
||||
res= 1;
|
||||
|
@ -5066,11 +5088,13 @@ subselect_partial_match_engine::subselect_partial_match_engine(
|
|||
TABLE *tmp_table_arg, Item_subselect *item_arg,
|
||||
select_result_interceptor *result_arg,
|
||||
List<Item> *equi_join_conds_arg,
|
||||
uint covering_null_row_width_arg)
|
||||
bool has_covering_null_row_arg,
|
||||
bool has_covering_null_columns_arg)
|
||||
:subselect_engine(thd_arg, item_arg, result_arg),
|
||||
tmp_table(tmp_table_arg), lookup_engine(engine_arg),
|
||||
equi_join_conds(equi_join_conds_arg),
|
||||
covering_null_row_width(covering_null_row_width_arg)
|
||||
has_covering_null_row(has_covering_null_row_arg),
|
||||
has_covering_null_columns(has_covering_null_columns_arg)
|
||||
{}
|
||||
|
||||
|
||||
|
@ -5108,7 +5132,7 @@ int subselect_partial_match_engine::exec()
|
|||
}
|
||||
}
|
||||
|
||||
if (covering_null_row_width == tmp_table->s->fields)
|
||||
if (has_covering_null_row)
|
||||
{
|
||||
/*
|
||||
If there is a NULL-only row that coveres all columns the result of IN
|
||||
|
@ -5172,7 +5196,6 @@ void subselect_partial_match_engine::print(String *str,
|
|||
/*
|
||||
@param non_null_key_parts
|
||||
@param partial_match_key_parts A union of all single-column NULL key parts.
|
||||
@param count_partial_match_columns Number of NULL keyparts (set bits above).
|
||||
|
||||
@retval FALSE the engine was initialized successfully
|
||||
@retval TRUE there was some (memory allocation) error during initialization,
|
||||
|
@ -5193,20 +5216,26 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
|
|||
Item_in_subselect *item_in= (Item_in_subselect*) item;
|
||||
int error;
|
||||
|
||||
if (keys_count == 0)
|
||||
if (merge_keys_count == 0)
|
||||
{
|
||||
DBUG_ASSERT(bitmap_bits_set(partial_match_key_parts) == 0 ||
|
||||
has_covering_null_row);
|
||||
/* There is nothing to initialize, we will only do regular lookups. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(!covering_null_row_width || (covering_null_row_width &&
|
||||
keys_count == 1 &&
|
||||
non_null_key_parts));
|
||||
/*
|
||||
If all nullable columns contain only NULLs, there must be one index
|
||||
over all non-null columns.
|
||||
*/
|
||||
DBUG_ASSERT(!has_covering_null_columns ||
|
||||
(has_covering_null_columns &&
|
||||
merge_keys_count == 1 && non_null_key_parts));
|
||||
/*
|
||||
Allocate buffers to hold the merged keys and the mapping between rowids and
|
||||
row numbers.
|
||||
*/
|
||||
if (!(merge_keys= (Ordered_key**) thd->alloc(keys_count *
|
||||
if (!(merge_keys= (Ordered_key**) thd->alloc(merge_keys_count *
|
||||
sizeof(Ordered_key*))) ||
|
||||
!(row_num_to_rowid= (uchar*) my_malloc((size_t)(row_count * rowid_length),
|
||||
MYF(MY_WME))))
|
||||
|
@ -5225,15 +5254,13 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
|
|||
}
|
||||
|
||||
/*
|
||||
If there is a covering NULL row, the only key that is needed is the
|
||||
only non-NULL key that is already created above. We create keys on
|
||||
NULL-able columns only if there is no covering NULL row.
|
||||
If all nullable columns contain NULLs, the only key that is needed is the
|
||||
only non-NULL key that is already created above.
|
||||
*/
|
||||
if (!covering_null_row_width)
|
||||
if (!has_covering_null_columns)
|
||||
{
|
||||
if (bitmap_init_memroot(&matching_keys, keys_count, thd->mem_root) ||
|
||||
bitmap_init_memroot(&matching_outer_cols, keys_count, thd->mem_root) ||
|
||||
bitmap_init_memroot(&null_only_columns, keys_count, thd->mem_root))
|
||||
if (bitmap_init_memroot(&matching_keys, merge_keys_count, thd->mem_root) ||
|
||||
bitmap_init_memroot(&matching_outer_cols, merge_keys_count, thd->mem_root))
|
||||
return TRUE;
|
||||
|
||||
/*
|
||||
|
@ -5242,31 +5269,25 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
|
|||
*/
|
||||
for (uint i= 0; i < partial_match_key_parts->n_bits; i++)
|
||||
{
|
||||
if (!bitmap_is_set(partial_match_key_parts, i))
|
||||
/* Skip columns that have no NULLs, or contain only NULLs. */
|
||||
if (!bitmap_is_set(partial_match_key_parts, i) ||
|
||||
result_sink->get_null_count_of_col(i) == row_count)
|
||||
continue;
|
||||
|
||||
if (result_sink->get_null_count_of_col(i) == row_count)
|
||||
{
|
||||
bitmap_set_bit(&null_only_columns, cur_keyid);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
merge_keys[cur_keyid]= new Ordered_key(
|
||||
merge_keys[cur_keyid]= new Ordered_key(
|
||||
cur_keyid, tmp_table,
|
||||
item_in->left_expr->element_index(i),
|
||||
result_sink->get_null_count_of_col(i),
|
||||
result_sink->get_min_null_of_col(i),
|
||||
result_sink->get_max_null_of_col(i),
|
||||
row_num_to_rowid);
|
||||
if (merge_keys[cur_keyid]->init(i))
|
||||
return TRUE;
|
||||
merge_keys[cur_keyid]->first();
|
||||
}
|
||||
if (merge_keys[cur_keyid]->init(i))
|
||||
return TRUE;
|
||||
merge_keys[cur_keyid]->first();
|
||||
++cur_keyid;
|
||||
}
|
||||
}
|
||||
DBUG_ASSERT(cur_keyid == keys_count);
|
||||
DBUG_ASSERT(cur_keyid == merge_keys_count);
|
||||
|
||||
/* Populate the indexes with data from the temporary table. */
|
||||
if (tmp_table->file->ha_rnd_init_with_error(1))
|
||||
|
@ -5307,7 +5328,7 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
|
|||
non_null_key->add_key(cur_rownum);
|
||||
}
|
||||
|
||||
for (uint i= (non_null_key ? 1 : 0); i < keys_count; i++)
|
||||
for (uint i= (non_null_key ? 1 : 0); i < merge_keys_count; i++)
|
||||
{
|
||||
/*
|
||||
Check if the first and only indexed column contains NULL in the curent
|
||||
|
@ -5324,14 +5345,14 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
|
|||
tmp_table->file->ha_rnd_end();
|
||||
|
||||
/* Sort all the keys by their NULL selectivity. */
|
||||
my_qsort(merge_keys, keys_count, sizeof(Ordered_key*),
|
||||
my_qsort(merge_keys, merge_keys_count, sizeof(Ordered_key*),
|
||||
(qsort_cmp) cmp_keys_by_null_selectivity);
|
||||
|
||||
/* Sort the keys in each of the indexes. */
|
||||
for (uint i= 0; i < keys_count; i++)
|
||||
for (uint i= 0; i < merge_keys_count; i++)
|
||||
merge_keys[i]->sort_keys();
|
||||
|
||||
if (init_queue(&pq, keys_count, 0, FALSE,
|
||||
if (init_queue(&pq, merge_keys_count, 0, FALSE,
|
||||
subselect_rowid_merge_engine::cmp_keys_by_cur_rownum, NULL,
|
||||
0, 0))
|
||||
return TRUE;
|
||||
|
@ -5343,10 +5364,10 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
|
|||
subselect_rowid_merge_engine::~subselect_rowid_merge_engine()
|
||||
{
|
||||
/* None of the resources below is allocated if there are no ordered keys. */
|
||||
if (keys_count)
|
||||
if (merge_keys_count)
|
||||
{
|
||||
my_free((char*) row_num_to_rowid, MYF(0));
|
||||
for (uint i= 0; i < keys_count; i++)
|
||||
for (uint i= 0; i < merge_keys_count; i++)
|
||||
delete merge_keys[i];
|
||||
delete_queue(&pq);
|
||||
if (tmp_table->file->inited == handler::RND)
|
||||
|
@ -5404,6 +5425,10 @@ subselect_rowid_merge_engine::cmp_keys_by_cur_rownum(void *arg,
|
|||
Check if certain table row contains a NULL in all columns for which there is
|
||||
no match in the corresponding value index.
|
||||
|
||||
@note
|
||||
There is no need to check the columns that contain only NULLs, because
|
||||
those are guaranteed to match.
|
||||
|
||||
@retval TRUE if a NULL row exists
|
||||
@retval FALSE otherwise
|
||||
*/
|
||||
|
@ -5411,16 +5436,14 @@ subselect_rowid_merge_engine::cmp_keys_by_cur_rownum(void *arg,
|
|||
bool subselect_rowid_merge_engine::test_null_row(rownum_t row_num)
|
||||
{
|
||||
Ordered_key *cur_key;
|
||||
uint cur_id;
|
||||
for (uint i = 0; i < keys_count; i++)
|
||||
for (uint i = 0; i < merge_keys_count; i++)
|
||||
{
|
||||
cur_key= merge_keys[i];
|
||||
cur_id= cur_key->get_keyid();
|
||||
if (bitmap_is_set(&matching_keys, cur_id))
|
||||
if (bitmap_is_set(&matching_keys, cur_key->get_keyid()))
|
||||
{
|
||||
/*
|
||||
The key 'i' (with id 'cur_keyid') already matches a value in row 'row_num',
|
||||
thus we skip it as it can't possibly match a NULL.
|
||||
The key 'i' (with id 'cur_keyid') already matches a value in row
|
||||
'row_num', thus we skip it as it can't possibly match a NULL.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
@ -5465,11 +5488,10 @@ bool subselect_rowid_merge_engine::partial_match()
|
|||
}
|
||||
|
||||
/*
|
||||
If there is a NULL (sub)row that covers all NULL-able columns,
|
||||
then there is a guranteed partial match, and we don't need to search
|
||||
for the matching row.
|
||||
*/
|
||||
if (covering_null_row_width)
|
||||
If all nullable columns contain only NULLs, then there is a guranteed
|
||||
partial match, and we don't need to search for a matching row.
|
||||
*/
|
||||
if (has_covering_null_columns)
|
||||
{
|
||||
res= TRUE;
|
||||
goto end;
|
||||
|
@ -5481,7 +5503,7 @@ bool subselect_rowid_merge_engine::partial_match()
|
|||
Do not add the non_null_key, since it was already processed above.
|
||||
*/
|
||||
bitmap_clear_all(&matching_outer_cols);
|
||||
for (uint i= test(non_null_key); i < keys_count; i++)
|
||||
for (uint i= test(non_null_key); i < merge_keys_count; i++)
|
||||
{
|
||||
DBUG_ASSERT(merge_keys[i]->get_column_count() == 1);
|
||||
if (merge_keys[i]->get_search_key(0)->null_value)
|
||||
|
@ -5519,7 +5541,6 @@ bool subselect_rowid_merge_engine::partial_match()
|
|||
|
||||
min_key= (Ordered_key*) queue_remove_top(&pq);
|
||||
min_row_num= min_key->current();
|
||||
bitmap_copy(&matching_keys, &null_only_columns);
|
||||
bitmap_set_bit(&matching_keys, min_key->get_keyid());
|
||||
bitmap_union(&matching_keys, &matching_outer_cols);
|
||||
if (min_key->next_same())
|
||||
|
@ -5555,7 +5576,6 @@ bool subselect_rowid_merge_engine::partial_match()
|
|||
{
|
||||
min_key= cur_key;
|
||||
min_row_num= cur_row_num;
|
||||
bitmap_copy(&matching_keys, &null_only_columns);
|
||||
bitmap_set_bit(&matching_keys, min_key->get_keyid());
|
||||
bitmap_union(&matching_keys, &matching_outer_cols);
|
||||
}
|
||||
|
@ -5588,10 +5608,12 @@ subselect_table_scan_engine::subselect_table_scan_engine(
|
|||
Item_subselect *item_arg,
|
||||
select_result_interceptor *result_arg,
|
||||
List<Item> *equi_join_conds_arg,
|
||||
uint covering_null_row_width_arg)
|
||||
bool has_covering_null_row_arg,
|
||||
bool has_covering_null_columns_arg)
|
||||
:subselect_partial_match_engine(thd_arg, engine_arg, tmp_table_arg, item_arg,
|
||||
result_arg, equi_join_conds_arg,
|
||||
covering_null_row_width_arg)
|
||||
has_covering_null_row_arg,
|
||||
has_covering_null_columns_arg)
|
||||
{}
|
||||
|
||||
|
||||
|
@ -5630,10 +5652,6 @@ bool subselect_table_scan_engine::partial_match()
|
|||
|
||||
tmp_table->file->extra_opt(HA_EXTRA_CACHE,
|
||||
current_thd->variables.read_buff_size);
|
||||
/*
|
||||
TIMOUR:
|
||||
scan_table() also calls "table->null_row= 0;", why, do we need it?
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
error= tmp_table->file->ha_rnd_next(tmp_table->record[0]);
|
||||
|
|
|
@ -1131,11 +1131,18 @@ protected:
|
|||
/* A list of equalities between each pair of IN operands. */
|
||||
List<Item> *equi_join_conds;
|
||||
/*
|
||||
If there is a row, such that all its NULL-able components are NULL, this
|
||||
member is set to the number of covered columns. If there is no covering
|
||||
row, then this is 0.
|
||||
True if there is an all NULL row in tmp_table. If so, then if there is
|
||||
no complete match, there is a guaranteed partial match.
|
||||
*/
|
||||
uint covering_null_row_width;
|
||||
bool has_covering_null_row;
|
||||
|
||||
/*
|
||||
True if all nullable columns of tmp_table consist of only NULL values.
|
||||
If so, then if there is a match in the non-null columns, there is a
|
||||
guaranteed partial match.
|
||||
*/
|
||||
bool has_covering_null_columns;
|
||||
|
||||
protected:
|
||||
virtual bool partial_match()= 0;
|
||||
public:
|
||||
|
@ -1144,7 +1151,8 @@ public:
|
|||
TABLE *tmp_table_arg, Item_subselect *item_arg,
|
||||
select_result_interceptor *result_arg,
|
||||
List<Item> *equi_join_conds_arg,
|
||||
uint covering_null_row_width_arg);
|
||||
bool has_covering_null_row_arg,
|
||||
bool has_covering_null_columns_arg);
|
||||
int prepare() { return 0; }
|
||||
int exec();
|
||||
void fix_length_and_dec(Item_cache**) {}
|
||||
|
@ -1191,11 +1199,6 @@ protected:
|
|||
outer reference.
|
||||
*/
|
||||
MY_BITMAP matching_outer_cols;
|
||||
/*
|
||||
Columns that consist of only NULLs. Such columns match any value.
|
||||
Computed once per query execution.
|
||||
*/
|
||||
MY_BITMAP null_only_columns;
|
||||
/*
|
||||
Indexes of row numbers, sorted by <column_value, row_number>. If an
|
||||
index may contain NULLs, the NULLs are stored efficiently in a bitmap.
|
||||
|
@ -1205,13 +1208,13 @@ protected:
|
|||
non-NULL columns, it is contained in keys[0].
|
||||
*/
|
||||
Ordered_key **merge_keys;
|
||||
/* The number of elements in keys. */
|
||||
uint keys_count;
|
||||
/* The number of elements in merge_keys. */
|
||||
uint merge_keys_count;
|
||||
/*
|
||||
An index on all non-NULL columns of 'tmp_table'. The index has the
|
||||
logical form: <[v_i1 | ... | v_ik], rownum>. It allows to find the row
|
||||
number where the columns c_i1,...,c1_k contain the values v_i1,...,v_ik.
|
||||
If such an index exists, it is always the first element of 'keys'.
|
||||
If such an index exists, it is always the first element of 'merge_keys'.
|
||||
*/
|
||||
Ordered_key *non_null_key;
|
||||
/*
|
||||
|
@ -1236,15 +1239,17 @@ protected:
|
|||
public:
|
||||
subselect_rowid_merge_engine(THD *thd_arg,
|
||||
subselect_uniquesubquery_engine *engine_arg,
|
||||
TABLE *tmp_table_arg, uint keys_count_arg,
|
||||
uint covering_null_row_width_arg,
|
||||
TABLE *tmp_table_arg, uint merge_keys_count_arg,
|
||||
bool has_covering_null_row_arg,
|
||||
bool has_covering_null_columns_arg,
|
||||
Item_subselect *item_arg,
|
||||
select_result_interceptor *result_arg,
|
||||
List<Item> *equi_join_conds_arg)
|
||||
:subselect_partial_match_engine(thd_arg, engine_arg, tmp_table_arg,
|
||||
item_arg, result_arg, equi_join_conds_arg,
|
||||
covering_null_row_width_arg),
|
||||
keys_count(keys_count_arg), non_null_key(NULL)
|
||||
has_covering_null_row_arg,
|
||||
has_covering_null_columns_arg),
|
||||
merge_keys_count(merge_keys_count_arg), non_null_key(NULL)
|
||||
{}
|
||||
~subselect_rowid_merge_engine();
|
||||
bool init(MY_BITMAP *non_null_key_parts, MY_BITMAP *partial_match_key_parts);
|
||||
|
@ -1263,7 +1268,8 @@ public:
|
|||
TABLE *tmp_table_arg, Item_subselect *item_arg,
|
||||
select_result_interceptor *result_arg,
|
||||
List<Item> *equi_join_conds_arg,
|
||||
uint covering_null_row_width_arg);
|
||||
bool has_covering_null_row_arg,
|
||||
bool has_covering_null_columns_arg);
|
||||
void cleanup();
|
||||
virtual enum_engine_type engine_type() { return TABLE_SCAN_ENGINE; }
|
||||
};
|
||||
|
|
|
@ -14651,14 +14651,6 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
|
|||
{
|
||||
List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
|
||||
fields);
|
||||
/*
|
||||
With implicit grouping all fields of special row produced for an
|
||||
empty result are NULL. See return_zero_rows() for the same behavior.
|
||||
*/
|
||||
TABLE_LIST *table;
|
||||
List_iterator_fast<TABLE_LIST> li(join->select_lex->leaf_tables);
|
||||
while ((table= li++))
|
||||
mark_as_null_row(table->table);
|
||||
rc= join->result->send_data(*columns_list) > 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue