Bug #79194 Wrong result on outer join with uncorrelated subquery, derived_merge
Submitted: 9 Nov 2015 21:37 Modified: 6 Jan 2016 17:01
Reporter: Elena Stepanova Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S3 (Non-critical)
Version:5.7.9 OS:Any
Assigned to: CPU Architecture:Any
Tags: regression

[9 Nov 2015 21:37] Elena Stepanova
Description:
For the test case provided in 'How to repeat' section:

MySQL [test]> SELECT * FROM t1 LEFT JOIN ( 
    ->   SELECT t3.* FROM t2 INNER JOIN t3 ON (b = c) 
    -> ) AS sq ON (a <= sq.c);
+------+------+
| a    | c    |
+------+------+
| NULL | NULL |
|    1 | NULL |
+------+------+
2 rows in set (0.00 sec)

Expected result:

MySQL [test]> SELECT * FROM t1 LEFT JOIN ( 
    ->   SELECT t3.* FROM t2 INNER JOIN t3 ON (b = c) 
    -> ) AS sq ON (a <= sq.c);
+------+------+
| a    | c    |
+------+------+
|    1 |    1 |
|    1 |    5 |
| NULL | NULL |
+------+------+
3 rows in set (0.00 sec)

Switching off derived_merge makes the problem go away.
The subquery produces the expected result:

MySQL [test]> SELECT t3.* FROM t2 INNER JOIN t3 ON (b = c);
+------+
| c    |
+------+
|    1 |
|    5 |
+------+
2 rows in set (0.00 sec)

How to repeat:
CREATE TABLE t1 (a INT, KEY(a));
INSERT INTO t1 VALUES  (1), (NULL);

CREATE TABLE t2 (b INT, KEY(b));
INSERT INTO t2 VALUES (7), (NULL), (1), (5), (8), (6), (4), (0), (3), (NULL);

CREATE TABLE t3 (c INT);
INSERT INTO t3 VALUES (NULL), (1), (5);

# The inner join returns a correct result
SELECT t3.* FROM t2 INNER JOIN t3 ON (b = c);

SELECT * FROM t1 LEFT JOIN ( 
  SELECT t3.* FROM t2 INNER JOIN t3 ON (b = c) 
) AS sq ON (a <= sq.c);

DROP TABLE t1, t2, t3;
[9 Nov 2015 21:56] MySQL Verification Team
Thank you for the bug report. Only 5.7 affected:

C:\dbs>c:\dbs\5.7\bin\mysql -uroot -p --port=3570 --prompt="mysql 5.7 > "
Enter password: ******
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.10 Source distribution PULL: 2015-NOV-07

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql 5.7 > USE test
Database changed
mysql 5.7 > CREATE TABLE t1 (a INT, KEY(a));
Query OK, 0 rows affected (0.03 sec)

mysql 5.7 > INSERT INTO t1 VALUES  (1), (NULL);
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql 5.7 >
mysql 5.7 > CREATE TABLE t2 (b INT, KEY(b));
Query OK, 0 rows affected (0.03 sec)

mysql 5.7 > INSERT INTO t2 VALUES (7), (NULL), (1), (5), (8), (6), (4), (0), (3), (NULL);
Query OK, 10 rows affected (0.01 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql 5.7 >
mysql 5.7 > CREATE TABLE t3 (c INT);
Query OK, 0 rows affected (0.03 sec)

mysql 5.7 > INSERT INTO t3 VALUES (NULL), (1), (5);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql 5.7 >
mysql 5.7 > # The inner join returns a correct result
mysql 5.7 > SELECT t3.* FROM t2 INNER JOIN t3 ON (b = c);
+------+
| c    |
+------+
|    1 |
|    5 |
+------+
2 rows in set (0.00 sec)

mysql 5.7 >
mysql 5.7 > SELECT * FROM t1 LEFT JOIN (
    ->   SELECT t3.* FROM t2 INNER JOIN t3 ON (b = c)
    -> ) AS sq ON (a <= sq.c);
+------+------+
| a    | c    |
+------+------+
| NULL | NULL |
|    1 | NULL |
+------+------+
2 rows in set (0.00 sec)
====================================================================
5.6:

C:\dbs>5.6\bin\mysql -uroot -p test
Enter password: ******
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 33
Server version: 5.6.27-log MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT * FROM t1 LEFT JOIN (
    ->   SELECT t3.* FROM t2 INNER JOIN t3 ON (b = c)
    -> ) AS sq ON (a <= sq.c);
+------+------+
| a    | c    |
+------+------+
|    1 |    1 |
|    1 |    5 |
| NULL | NULL |
+------+------+
3 rows in set (0.00 sec)
[6 Jan 2016 17:01] Paul DuBois
Noted in 5.7.11, 5.8.0 changelogs.

With the derived_merge flag of the optimizer_switch system variable
enabled, queries that used a derived table on the inner side of an
outer join could return incorrect results.