Skip to content

Commit 4fcdb29

Browse files
committed
Bug#21574933 Extra rows with derived table in subquery + XOR
This problem stems from the transformation of IN subqueries in Item_in_subselect::single_value_in_to_exists_transformer(). The source of the regression is the fix for bug no. 14358878, which wrapped all selected columns from a derived table that was on the inner side of an outer join in Item_direct_view_ref objects. The purpose of the wrapping was to make the columns nullable and nullability depending on some table from the derived table. single_value_in_to_exists_transformer() calculated orig_item from one such column. Prior to the wrapping, nullability information was present in orig_item. But after the bugfix, real_item() would pass the Item_direct_view_ref object and return the underlying Item object, which is not necessarily nullable. real_item() was originally used so that we do not build a permanent subquery transformation on top of a runtime item. The wrapped Item_direct_view_ref objects are runtime objects, meaning that they cannot be used in a permanent transformation. The solution is a kludge: If the Item_direct_view_ref object is nullable, we set the item being pointed to from the Item_direct_view_ref as nullable as well. This means that we pick up correct nullability, but the item does not correctly reflect the nullability of the datum. However, we have not been able to identify a situation where this causes erroneous or non-optimal execution. Further on, this means that NULL values from outer joined tables are included in the query result, meaning that the IN subquery can return NULL instead of FALSE in cases like this.
1 parent 5147ad3 commit 4fcdb29

12 files changed

+581
-1
lines changed

mysql-test/include/subquery.inc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6528,3 +6528,58 @@ SELECT
65286528
FROM t1 AS x3;
65296529

65306530
DROP TABLE t1,t2;
6531+
6532+
--echo # Bug#21574933 Extra rows with derived table in subquery + XOR
6533+
6534+
CREATE TABLE t1 (
6535+
pk INT NOT NULL,
6536+
col_date DATE,
6537+
PRIMARY KEY (pk)
6538+
);
6539+
6540+
INSERT INTO t1 VALUES (1,'2008-06-18'), (4,NULL);
6541+
6542+
CREATE TABLE t2 (
6543+
col_date DATE,
6544+
pk INT NOT NULL,
6545+
PRIMARY KEY (pk)
6546+
);
6547+
6548+
INSERT INTO t2 VALUES ('2002-02-02',1);
6549+
6550+
CREATE TABLE t3 (
6551+
pk INT NOT NULL,
6552+
col_varchar VARCHAR(1),
6553+
col_int_key INT,
6554+
col_int INT,
6555+
PRIMARY KEY (pk),
6556+
KEY col_int_key (col_int_key)
6557+
);
6558+
6559+
INSERT INTO t3 VALUES (4,'l',2,2);
6560+
6561+
let $query=
6562+
SELECT pk,
6563+
col_int IN
6564+
(SELECT innr1.pk
6565+
FROM t1 AS innr2
6566+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
6567+
ON innr2.col_date <> innr1.col_date
6568+
WHERE outr.col_int_key < 6) AS x
6569+
FROM t3 AS outr;
6570+
6571+
eval explain $query;
6572+
eval $query;
6573+
6574+
let $query=
6575+
SELECT pk,
6576+
col_int IN
6577+
(SELECT innr1.pk
6578+
FROM t1 AS innr2
6579+
LEFT JOIN (SELECT pk, date'2015-01-01' AS d FROM t2) AS innr1
6580+
ON innr2.col_date <> innr1.d
6581+
WHERE outr.col_int_key < 6) AS x
6582+
FROM t3 AS outr;
6583+
eval $query;
6584+
6585+
DROP TABLE t1, t2, t3;

mysql-test/r/subquery_all.result

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8009,4 +8009,62 @@ FROM t1 AS x3;
80098009
result
80108010
0
80118011
DROP TABLE t1,t2;
8012+
# Bug#21574933 Extra rows with derived table in subquery + XOR
8013+
CREATE TABLE t1 (
8014+
pk INT NOT NULL,
8015+
col_date DATE,
8016+
PRIMARY KEY (pk)
8017+
);
8018+
INSERT INTO t1 VALUES (1,'2008-06-18'), (4,NULL);
8019+
CREATE TABLE t2 (
8020+
col_date DATE,
8021+
pk INT NOT NULL,
8022+
PRIMARY KEY (pk)
8023+
);
8024+
INSERT INTO t2 VALUES ('2002-02-02',1);
8025+
CREATE TABLE t3 (
8026+
pk INT NOT NULL,
8027+
col_varchar VARCHAR(1),
8028+
col_int_key INT,
8029+
col_int INT,
8030+
PRIMARY KEY (pk),
8031+
KEY col_int_key (col_int_key)
8032+
);
8033+
INSERT INTO t3 VALUES (4,'l',2,2);
8034+
explain SELECT pk,
8035+
col_int IN
8036+
(SELECT innr1.pk
8037+
FROM t1 AS innr2
8038+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8039+
ON innr2.col_date <> innr1.col_date
8040+
WHERE outr.col_int_key < 6) AS x
8041+
FROM t3 AS outr;
8042+
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
8043+
1 PRIMARY outr NULL ALL NULL NULL NULL NULL 1 100.00 NULL
8044+
2 DEPENDENT SUBQUERY innr2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
8045+
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (Block Nested Loop)
8046+
Warnings:
8047+
Note 1276 Field or reference 'test.outr.col_int_key' of SELECT #2 was resolved in SELECT #1
8048+
Note 1003 /* select#1 */ select `test`.`outr`.`pk` AS `pk`,<in_optimizer>(`test`.`outr`.`col_int`,<exists>(/* select#2 */ select 1 from `test`.`t1` `innr2` left join (`test`.`t2`) on((`test`.`innr2`.`col_date` <> `test`.`t2`.`col_date`)) where ((`test`.`outr`.`col_int_key` < 6) and <if>(outer_field_is_not_null, ((<cache>(`test`.`outr`.`col_int`) = `test`.`t2`.`pk`) or isnull(`test`.`t2`.`pk`)), true)) having <if>(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`pk`), true))) AS `x` from `test`.`t3` `outr`
8049+
SELECT pk,
8050+
col_int IN
8051+
(SELECT innr1.pk
8052+
FROM t1 AS innr2
8053+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8054+
ON innr2.col_date <> innr1.col_date
8055+
WHERE outr.col_int_key < 6) AS x
8056+
FROM t3 AS outr;
8057+
pk x
8058+
4 NULL
8059+
SELECT pk,
8060+
col_int IN
8061+
(SELECT innr1.pk
8062+
FROM t1 AS innr2
8063+
LEFT JOIN (SELECT pk, date'2015-01-01' AS d FROM t2) AS innr1
8064+
ON innr2.col_date <> innr1.d
8065+
WHERE outr.col_int_key < 6) AS x
8066+
FROM t3 AS outr;
8067+
pk x
8068+
4 NULL
8069+
DROP TABLE t1, t2, t3;
80128070
set optimizer_switch=default;

mysql-test/r/subquery_all_bka.result

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8010,5 +8010,63 @@ FROM t1 AS x3;
80108010
result
80118011
0
80128012
DROP TABLE t1,t2;
8013+
# Bug#21574933 Extra rows with derived table in subquery + XOR
8014+
CREATE TABLE t1 (
8015+
pk INT NOT NULL,
8016+
col_date DATE,
8017+
PRIMARY KEY (pk)
8018+
);
8019+
INSERT INTO t1 VALUES (1,'2008-06-18'), (4,NULL);
8020+
CREATE TABLE t2 (
8021+
col_date DATE,
8022+
pk INT NOT NULL,
8023+
PRIMARY KEY (pk)
8024+
);
8025+
INSERT INTO t2 VALUES ('2002-02-02',1);
8026+
CREATE TABLE t3 (
8027+
pk INT NOT NULL,
8028+
col_varchar VARCHAR(1),
8029+
col_int_key INT,
8030+
col_int INT,
8031+
PRIMARY KEY (pk),
8032+
KEY col_int_key (col_int_key)
8033+
);
8034+
INSERT INTO t3 VALUES (4,'l',2,2);
8035+
explain SELECT pk,
8036+
col_int IN
8037+
(SELECT innr1.pk
8038+
FROM t1 AS innr2
8039+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8040+
ON innr2.col_date <> innr1.col_date
8041+
WHERE outr.col_int_key < 6) AS x
8042+
FROM t3 AS outr;
8043+
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
8044+
1 PRIMARY outr NULL ALL NULL NULL NULL NULL 1 100.00 NULL
8045+
2 DEPENDENT SUBQUERY innr2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
8046+
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (Block Nested Loop)
8047+
Warnings:
8048+
Note 1276 Field or reference 'test.outr.col_int_key' of SELECT #2 was resolved in SELECT #1
8049+
Note 1003 /* select#1 */ select `test`.`outr`.`pk` AS `pk`,<in_optimizer>(`test`.`outr`.`col_int`,<exists>(/* select#2 */ select 1 from `test`.`t1` `innr2` left join (`test`.`t2`) on((`test`.`innr2`.`col_date` <> `test`.`t2`.`col_date`)) where ((`test`.`outr`.`col_int_key` < 6) and <if>(outer_field_is_not_null, ((<cache>(`test`.`outr`.`col_int`) = `test`.`t2`.`pk`) or isnull(`test`.`t2`.`pk`)), true)) having <if>(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`pk`), true))) AS `x` from `test`.`t3` `outr`
8050+
SELECT pk,
8051+
col_int IN
8052+
(SELECT innr1.pk
8053+
FROM t1 AS innr2
8054+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8055+
ON innr2.col_date <> innr1.col_date
8056+
WHERE outr.col_int_key < 6) AS x
8057+
FROM t3 AS outr;
8058+
pk x
8059+
4 NULL
8060+
SELECT pk,
8061+
col_int IN
8062+
(SELECT innr1.pk
8063+
FROM t1 AS innr2
8064+
LEFT JOIN (SELECT pk, date'2015-01-01' AS d FROM t2) AS innr1
8065+
ON innr2.col_date <> innr1.d
8066+
WHERE outr.col_int_key < 6) AS x
8067+
FROM t3 AS outr;
8068+
pk x
8069+
4 NULL
8070+
DROP TABLE t1, t2, t3;
80138071
set optimizer_switch=default;
80148072
set optimizer_switch=default;

mysql-test/r/subquery_all_bka_nixbnl.result

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8010,5 +8010,63 @@ FROM t1 AS x3;
80108010
result
80118011
0
80128012
DROP TABLE t1,t2;
8013+
# Bug#21574933 Extra rows with derived table in subquery + XOR
8014+
CREATE TABLE t1 (
8015+
pk INT NOT NULL,
8016+
col_date DATE,
8017+
PRIMARY KEY (pk)
8018+
);
8019+
INSERT INTO t1 VALUES (1,'2008-06-18'), (4,NULL);
8020+
CREATE TABLE t2 (
8021+
col_date DATE,
8022+
pk INT NOT NULL,
8023+
PRIMARY KEY (pk)
8024+
);
8025+
INSERT INTO t2 VALUES ('2002-02-02',1);
8026+
CREATE TABLE t3 (
8027+
pk INT NOT NULL,
8028+
col_varchar VARCHAR(1),
8029+
col_int_key INT,
8030+
col_int INT,
8031+
PRIMARY KEY (pk),
8032+
KEY col_int_key (col_int_key)
8033+
);
8034+
INSERT INTO t3 VALUES (4,'l',2,2);
8035+
explain SELECT pk,
8036+
col_int IN
8037+
(SELECT innr1.pk
8038+
FROM t1 AS innr2
8039+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8040+
ON innr2.col_date <> innr1.col_date
8041+
WHERE outr.col_int_key < 6) AS x
8042+
FROM t3 AS outr;
8043+
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
8044+
1 PRIMARY outr NULL ALL NULL NULL NULL NULL 1 100.00 NULL
8045+
2 DEPENDENT SUBQUERY innr2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
8046+
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 1 100.00 Using where
8047+
Warnings:
8048+
Note 1276 Field or reference 'test.outr.col_int_key' of SELECT #2 was resolved in SELECT #1
8049+
Note 1003 /* select#1 */ select `test`.`outr`.`pk` AS `pk`,<in_optimizer>(`test`.`outr`.`col_int`,<exists>(/* select#2 */ select 1 from `test`.`t1` `innr2` left join (`test`.`t2`) on((`test`.`innr2`.`col_date` <> `test`.`t2`.`col_date`)) where ((`test`.`outr`.`col_int_key` < 6) and <if>(outer_field_is_not_null, ((<cache>(`test`.`outr`.`col_int`) = `test`.`t2`.`pk`) or isnull(`test`.`t2`.`pk`)), true)) having <if>(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`pk`), true))) AS `x` from `test`.`t3` `outr`
8050+
SELECT pk,
8051+
col_int IN
8052+
(SELECT innr1.pk
8053+
FROM t1 AS innr2
8054+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8055+
ON innr2.col_date <> innr1.col_date
8056+
WHERE outr.col_int_key < 6) AS x
8057+
FROM t3 AS outr;
8058+
pk x
8059+
4 NULL
8060+
SELECT pk,
8061+
col_int IN
8062+
(SELECT innr1.pk
8063+
FROM t1 AS innr2
8064+
LEFT JOIN (SELECT pk, date'2015-01-01' AS d FROM t2) AS innr1
8065+
ON innr2.col_date <> innr1.d
8066+
WHERE outr.col_int_key < 6) AS x
8067+
FROM t3 AS outr;
8068+
pk x
8069+
4 NULL
8070+
DROP TABLE t1, t2, t3;
80138071
set optimizer_switch=default;
80148072
set optimizer_switch=default;

mysql-test/r/subquery_nomat_nosj.result

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8009,4 +8009,62 @@ FROM t1 AS x3;
80098009
result
80108010
0
80118011
DROP TABLE t1,t2;
8012+
# Bug#21574933 Extra rows with derived table in subquery + XOR
8013+
CREATE TABLE t1 (
8014+
pk INT NOT NULL,
8015+
col_date DATE,
8016+
PRIMARY KEY (pk)
8017+
);
8018+
INSERT INTO t1 VALUES (1,'2008-06-18'), (4,NULL);
8019+
CREATE TABLE t2 (
8020+
col_date DATE,
8021+
pk INT NOT NULL,
8022+
PRIMARY KEY (pk)
8023+
);
8024+
INSERT INTO t2 VALUES ('2002-02-02',1);
8025+
CREATE TABLE t3 (
8026+
pk INT NOT NULL,
8027+
col_varchar VARCHAR(1),
8028+
col_int_key INT,
8029+
col_int INT,
8030+
PRIMARY KEY (pk),
8031+
KEY col_int_key (col_int_key)
8032+
);
8033+
INSERT INTO t3 VALUES (4,'l',2,2);
8034+
explain SELECT pk,
8035+
col_int IN
8036+
(SELECT innr1.pk
8037+
FROM t1 AS innr2
8038+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8039+
ON innr2.col_date <> innr1.col_date
8040+
WHERE outr.col_int_key < 6) AS x
8041+
FROM t3 AS outr;
8042+
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
8043+
1 PRIMARY outr NULL ALL NULL NULL NULL NULL 1 100.00 NULL
8044+
2 DEPENDENT SUBQUERY innr2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
8045+
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (Block Nested Loop)
8046+
Warnings:
8047+
Note 1276 Field or reference 'test.outr.col_int_key' of SELECT #2 was resolved in SELECT #1
8048+
Note 1003 /* select#1 */ select `test`.`outr`.`pk` AS `pk`,<in_optimizer>(`test`.`outr`.`col_int`,<exists>(/* select#2 */ select 1 from `test`.`t1` `innr2` left join (`test`.`t2`) on((`test`.`innr2`.`col_date` <> `test`.`t2`.`col_date`)) where ((`test`.`outr`.`col_int_key` < 6) and <if>(outer_field_is_not_null, ((<cache>(`test`.`outr`.`col_int`) = `test`.`t2`.`pk`) or isnull(`test`.`t2`.`pk`)), true)) having <if>(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`pk`), true))) AS `x` from `test`.`t3` `outr`
8049+
SELECT pk,
8050+
col_int IN
8051+
(SELECT innr1.pk
8052+
FROM t1 AS innr2
8053+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8054+
ON innr2.col_date <> innr1.col_date
8055+
WHERE outr.col_int_key < 6) AS x
8056+
FROM t3 AS outr;
8057+
pk x
8058+
4 NULL
8059+
SELECT pk,
8060+
col_int IN
8061+
(SELECT innr1.pk
8062+
FROM t1 AS innr2
8063+
LEFT JOIN (SELECT pk, date'2015-01-01' AS d FROM t2) AS innr1
8064+
ON innr2.col_date <> innr1.d
8065+
WHERE outr.col_int_key < 6) AS x
8066+
FROM t3 AS outr;
8067+
pk x
8068+
4 NULL
8069+
DROP TABLE t1, t2, t3;
80128070
set optimizer_switch=default;

mysql-test/r/subquery_nomat_nosj_bka.result

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8010,5 +8010,63 @@ FROM t1 AS x3;
80108010
result
80118011
0
80128012
DROP TABLE t1,t2;
8013+
# Bug#21574933 Extra rows with derived table in subquery + XOR
8014+
CREATE TABLE t1 (
8015+
pk INT NOT NULL,
8016+
col_date DATE,
8017+
PRIMARY KEY (pk)
8018+
);
8019+
INSERT INTO t1 VALUES (1,'2008-06-18'), (4,NULL);
8020+
CREATE TABLE t2 (
8021+
col_date DATE,
8022+
pk INT NOT NULL,
8023+
PRIMARY KEY (pk)
8024+
);
8025+
INSERT INTO t2 VALUES ('2002-02-02',1);
8026+
CREATE TABLE t3 (
8027+
pk INT NOT NULL,
8028+
col_varchar VARCHAR(1),
8029+
col_int_key INT,
8030+
col_int INT,
8031+
PRIMARY KEY (pk),
8032+
KEY col_int_key (col_int_key)
8033+
);
8034+
INSERT INTO t3 VALUES (4,'l',2,2);
8035+
explain SELECT pk,
8036+
col_int IN
8037+
(SELECT innr1.pk
8038+
FROM t1 AS innr2
8039+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8040+
ON innr2.col_date <> innr1.col_date
8041+
WHERE outr.col_int_key < 6) AS x
8042+
FROM t3 AS outr;
8043+
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
8044+
1 PRIMARY outr NULL ALL NULL NULL NULL NULL 1 100.00 NULL
8045+
2 DEPENDENT SUBQUERY innr2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
8046+
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (Block Nested Loop)
8047+
Warnings:
8048+
Note 1276 Field or reference 'test.outr.col_int_key' of SELECT #2 was resolved in SELECT #1
8049+
Note 1003 /* select#1 */ select `test`.`outr`.`pk` AS `pk`,<in_optimizer>(`test`.`outr`.`col_int`,<exists>(/* select#2 */ select 1 from `test`.`t1` `innr2` left join (`test`.`t2`) on((`test`.`innr2`.`col_date` <> `test`.`t2`.`col_date`)) where ((`test`.`outr`.`col_int_key` < 6) and <if>(outer_field_is_not_null, ((<cache>(`test`.`outr`.`col_int`) = `test`.`t2`.`pk`) or isnull(`test`.`t2`.`pk`)), true)) having <if>(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`pk`), true))) AS `x` from `test`.`t3` `outr`
8050+
SELECT pk,
8051+
col_int IN
8052+
(SELECT innr1.pk
8053+
FROM t1 AS innr2
8054+
LEFT JOIN (SELECT pk, col_date FROM t2) AS innr1
8055+
ON innr2.col_date <> innr1.col_date
8056+
WHERE outr.col_int_key < 6) AS x
8057+
FROM t3 AS outr;
8058+
pk x
8059+
4 NULL
8060+
SELECT pk,
8061+
col_int IN
8062+
(SELECT innr1.pk
8063+
FROM t1 AS innr2
8064+
LEFT JOIN (SELECT pk, date'2015-01-01' AS d FROM t2) AS innr1
8065+
ON innr2.col_date <> innr1.d
8066+
WHERE outr.col_int_key < 6) AS x
8067+
FROM t3 AS outr;
8068+
pk x
8069+
4 NULL
8070+
DROP TABLE t1, t2, t3;
80138071
set optimizer_switch=default;
80148072
set optimizer_switch=default;

0 commit comments

Comments
 (0)