Bug #5896 Outer join with single row outer table ignores some on conditions
Submitted: 5 Oct 2004 3:35 Modified: 5 Oct 2004 15:52
Reporter: Igor Babaev Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:5.0.2 OS:Any (all)
Assigned to: Igor Babaev CPU Architecture:Any

[5 Oct 2004 3:35] Igor Babaev
Description:
If the outer table in an outer join operation of a query contains only 1 row and the on condition for this operation refers only to this table and is evaluated to false
for the row in the table then the query might return a wrong result.
E.g. if tables t1 and t2 is specified by the commands
CREATE TABLE t1(int a)
CREATE TABLE t2(int b)
and table t1 contain row (1), while ttable t2 contains two rows (1) and (2),
then we have:

mysql> SELECT * FROM t1 LEFT JOIN t2 ON a=0;
+----+------+
| a  | b    |
+----+------+
|  1 |    1 |
|  1 |    2 |
+----+------+

The expected result is:
mysql> SELECT * FROM t1 LEFT JOIN t2 ON a1=0;
+----+------+
| a1 | a2   |
+----+------+
|  1 | NULL |
+----+------+

The same is true if the selection for the outer table is guaranteed to return only 1 row.

How to repeat:
Create the and populate tables t0,t1,t2,t3 by the following commands:
CREATE TABLE t0 (a0 int PRIMARY KEY);
CREATE TABLE t1 (a1 int PRIMARY KEY);
CREATE TABLE t2 (a2 int);
CREATE TABLE t3 (a3 int);
INSERT INTO t0 VALUES (1);
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1), (2);
INSERT INTO t3 VALUES (1), (2);

The run the commands:
SELECT * FROM t1 LEFT JOIN t2 ON a1=0;
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON a1=0;
SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0;
EXPLAIN SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0;

Suggested fix:
SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1;
EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1;
INSERT INTO t0 VALUES (0);
INSERT INTO t1 VALUES (0);
SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;

You'll have the following results:
mysql> SELECT * FROM t1 LEFT JOIN t2 ON a1=0;
+----+------+
| a1 | a2   |
+----+------+
|  1 |    1 |
|  1 |    2 |
+----+------+
2 rows in set (7.40 sec)

mysql> EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON a1=0;
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
| id | select_type | table | type   | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | t1    | system | NULL          | NULL | NULL    | NULL |    1 |       |
|  1 | SIMPLE      | t2    | ALL    | NULL          | NULL | NULL    | NULL |    2 |       |
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0;
+----+------+------+
| a1 | a2   | a3   |
+----+------+------+
|  1 |    1 |    1 |
|  1 |    1 |    2 |
|  1 |    2 |    1 |
|  1 |    2 |    2 |
+----+------+------+
4 rows in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0;
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
| id | select_type | table | type   | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | t1    | system | NULL          | NULL | NULL    | NULL |    1 |       |
|  1 | SIMPLE      | t2    | ALL    | NULL          | NULL | NULL    | NULL |    2 |       |
|  1 | SIMPLE      | t3    | ALL    | NULL          | NULL | NULL    | NULL |    2 |       |
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
mysql> SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1;
+----+----+------+------+
| a0 | a1 | a2   | a3   |
+----+----+------+------+
|  1 |  1 |    1 |    1 |
|  1 |  1 |    1 |    2 |
|  1 |  1 |    2 |    1 |
|  1 |  1 |    2 |    2 |
+----+----+------+------+
4 rows in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1;
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
| id | select_type | table | type   | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | t0    | system | PRIMARY       | NULL | NULL    | NULL |    1 |       |
|  1 | SIMPLE      | t1    | system | PRIMARY       | NULL | NULL    | NULL |    1 |       |
|  1 | SIMPLE      | t2    | ALL    | NULL          | NULL | NULL    | NULL |    2 |       |
|  1 | SIMPLE      | t3    | ALL    | NULL          | NULL | NULL    | NULL |    2 |       |
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
+----+----+------+------+
| a0 | a1 | a2   | a3   |
+----+----+------+------+
|  1 |  1 |    1 |    1 |
|  1 |  1 |    1 |    2 |
|  1 |  1 |    2 |    1 |
|  1 |  1 |    2 |    2 |
+----+----+------+------+
4 rows in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
| id | select_type | table | type   | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | t0    | system | PRIMARY       | NULL | NULL    | NULL |    1 |       |
|  1 | SIMPLE      | t1    | system | PRIMARY       | NULL | NULL    | NULL |    1 |       |
|  1 | SIMPLE      | t2    | ALL    | NULL          | NULL | NULL    | NULL |    2 |       |
|  1 | SIMPLE      | t3    | ALL    | NULL          | NULL | NULL    | NULL |    2 |       |
+----+-------------+-------+--------+---------------+------+---------+------+------+-------+
4 rows in set (0.00 sec)

mysql> INSERT INTO t0 VALUES (0);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO t1 VALUES (0);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
+----+----+------+------+
| a0 | a1 | a2   | a3   |
+----+----+------+------+
|  1 |  1 |    1 |    1 |
|  1 |  1 |    1 |    2 |
|  1 |  1 |    2 |    1 |
|  1 |  1 |    2 |    2 |
+----+----+------+------+
4 rows in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | t0    | const | PRIMARY       | PRIMARY | 4       | const |    1 | Using index |
|  1 | SIMPLE      | t1    | const | PRIMARY       | PRIMARY | 4       | const |    1 | Using index |
|  1 | SIMPLE      | t2    | ALL   | NULL          | NULL    | NULL    | NULL  |    2 |             |
|  1 | SIMPLE      | t3    | ALL   | NULL          | NULL    | NULL    | NULL  |    2 |             |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
4 rows in set (0.00 sec)

All select statements above will return incorrect result sets.
[5 Oct 2004 15:52] Igor Babaev
I added a special handling of on expressions for system/const outer tables.

ChangeSet
  1.1634 04/10/04 22:26:36 igor@rurik.mysql.com +3 -0
  join_outer.result, join_outer.test:
    Added a test case for bug #5896.
  sql_select.cc:
    Fixed the problem of ignoring on expressions depending
    only on outer table when outer table either contains
    1 row or is guaranteed to return only 1 row (bug #5896).