Oracle is generating the transitive closure of predicates. i.e. it can see that:
a = b (+) and a = 10
then b(+) = 10
See MOS note 68979.1 for more details.
This means that Oracle transforms a query like:
create table t (
x int
);
insert into t values (1);
select * from t t1
left join t t2
on t1.x = t2.x
and t2.x > 2
where t1.x < 2;
To:
select "T1"."X" "X","T2"."X" "X"
from "CHRIS"."T" "T1","CHRIS"."T" "T2"
where "T1"."X" <2
and "T1"."X" ="T2"."X"(+)
and "T2"."X"(+)>2
and "T2"."X"(+)<2;
This gives a plan like:
---------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
---------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 1 | |
| 1 | FILTER | | | | | |
| 2 | HASH JOIN OUTER | | 1 | 26 | 5 | 00:00:01 |
| 3 | TABLE ACCESS FULL | T | 1 | 13 | 2 | 00:00:01 |
| 4 | TABLE ACCESS FULL | T | 1 | 13 | 2 | 00:00:01 |
---------------------------------------+-----------------------------------+
Predicate Information:
----------------------
1 - filter(NULL IS NOT NULL)
2 - access("T1"."X"="T2"."X")
3 - filter("T1"."X"<2)
Note the "NULL IS NOT NULL" filter at the start. This is always false. The optimizer uses this to bypass the execution tree below it. Which is why there's no result!
So, yes this looks like a bug. I've raised it internally.
But!
Your query makes little sense! You have conflicting conditions on the outer joined table. Notice that the transformed query checks whether X is < 2 and > 2. This is impossible. So you'll never get any values from this. You may as well write:
select x, null from t
where x < 2
Either that, or change your queries so you don't have conflicting conditions on the join column(s)!
So really you need to fix your SQL.