Bug #121538 Wrong result: RIGHT JOIN of two derived tables followed by LEFT JOIN drops the RIGHT JOIN's ON condition and filters the
Submitted: 18 Oct 13:39 Modified: 18 Oct 21:23
Reporter: Ann Calla Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:9.7.2, 26.07 OS:Ubuntu (24.04)
Assigned to: CPU Architecture:x86 (x86_64)

[18 Oct 13:39] Ann Calla
Description:
A query of the form

  (SELECT * FROM t1) l RIGHT JOIN (SELECT * FROM t0) r ON r.c0 = 1 LEFT JOIN t0 z ON l.c0 = r.c0

returns 7 rows instead of 11. The same query with the base tables instead of the derived tables returns the correct 11 rows, and the RIGHT JOIN alone returns the correct 7 rows.

The result contains a row that cannot exist: (l.c0 = 1, r.c0 = 5). r.c0 = 5 does not satisfy the ON condition r.c0 = 1, so l must be NULL-extended for that row. At the same time the rows of l with c0 = 2 and 3 are missing for r.c0 = 1.

EXPLAIN FORMAT=TREE shows the reason: the first join is "Left hash join (no condition)" and the inner table l gets "Filter: (t1.c0 = 1)". The ON condition r.c0 = 1 has been replaced by l.c0 = 1, apparently through the equality l.c0 = r.c0 of the following LEFT JOIN, which belongs to z's ON clause and must not be used to rewrite the earlier ON clause.

It is not specific to RIGHT JOIN: written as "(SELECT * FROM t0) r LEFT JOIN (SELECT * FROM t1) l ON r.c0 = 1 LEFT JOIN t0 z ON l.c0 = r.c0" the query also returns 7. A derived table on the outer side (r) is enough; with only l as a derived table the result is correct.

MariaDB 13.1 returns 11 rows for both forms. Reproduced on 26.7.1 and 9.7.2.

How to repeat:
CREATE TABLE t1 (c0 INT);
INSERT INTO t1 VALUES (1), (2), (3);
CREATE TABLE t0 (c0 INT);
INSERT INTO t0 VALUES (1), (1), (5);

SELECT COUNT(*) FROM t1 l RIGHT JOIN t0 r ON r.c0 = 1 LEFT JOIN t0 z ON l.c0 = r.c0;
-- 11   correct

SELECT COUNT(*) FROM (SELECT * FROM t1) l RIGHT JOIN (SELECT * FROM t0) r ON r.c0 = 1 LEFT JOIN t0 z ON l.c0 = r.c0;
-- expected: 11
-- actual:   7

SELECT l.c0, r.c0, z.c0
FROM (SELECT * FROM t1) l RIGHT JOIN (SELECT * FROM t0) r ON r.c0 = 1 LEFT JOIN t0 z ON l.c0 = r.c0
ORDER BY 1, 2, 3;
-- expected (as with base tables):
--   (NULL,5,NULL), (1,1,1) x4, (1,1,5) x2, (2,1,NULL) x2, (3,1,NULL) x2
-- actual:
--   (1,1,1) x4, (1,1,5) x2, (1,5,NULL)

EXPLAIN FORMAT=TREE
SELECT COUNT(*) FROM (SELECT * FROM t1) l RIGHT JOIN (SELECT * FROM t0) r ON r.c0 = 1 LEFT JOIN t0 z ON l.c0 = r.c0;
-- -> Aggregate: count(0)
--     -> Left hash join (no condition), extra conditions: (t1.c0 = t0.c0)
--         -> Left hash join (no condition)
--             -> Table scan on t0
--             -> Hash
--                 -> Filter: (t1.c0 = 1)
--                     -> Table scan on t1
--         -> Hash
--             -> Table scan on z
[18 Oct 21:23] Roy Lyseng
Thank you for the bug report.
Verified as described.