Possible wrong results when using outer join for sub-selects

Details

Detail name Value
Changelog Number 5601
Type Bug
Status Resolved
Affected Versions
Fix Versions EXASOL 6.0.7
Resolution Date 2018-01-31

Problem Description

Due to a bug in filter propagation optimization, filters may be pushed down to incorrect sub-selects which leads to incorrect results being produced.

This issue was reproducible in the following example.

create table t1 (i1 int, d1 decimal);
insert into t1 values (1, 100), (2, 200), (3, 300);

create table t2 (i2 int, d2 decimal);
insert into t2 values (1, 100), (2, 200), (3, 300);

create table t3 (i3 int, d3 decimal);
insert into t3 values (2, 200), (3, 300);

create view v1 as
    (select * from t1 group by 1, 2);
create view v2 as
    (select * from t2 group by 1, 2);
create view v3 as
    (select * from t3 group by 1, 2);

select *
    from v1
    left join v2 on v1.i1 = v2.i2
    left join v3 on v1.i1 = v3.i3 and v3.i3 = 3;

The query gives the following incorrect result where the filter v3.i3 = 3 is wrongly propagated to v2.i2.

I1 D1 I2 D2 I3 D3
1 100        
2 200        
3 300 3 300 3 300
4 400        

The expected result is,

I1 D1 I2 D2 I3 D3
1 100 1 100    
2 200 2 200    
3 300 3 300 3 300
4 400        

Circumstances

This error may occur in a relatively rare scenario where all of the following conditions apply:

  • When sub-selects are used. Views which are not materialized are also transformed into sub-select expressions by the compiler.
  • The optimizer is unable to eliminate such sub-select expressions. This happens for many reasons, one of which is that the sub-select expression uses GROUP BY clause.
  • When left or right outer joins are used and at least one sub-select occurs in the inner table.
  • When outer join conditions contain local filters on join conditions that lead to other tables.

Workaround

As a workaround, it should be possible enforce pre-materializion of the offending table using a subselect containing the problematic local filter:

select *
    from v1
    left join v2 on v1.i1 = v2.i2
    left join (
		select * from v3
		where i3 = 3 -- problematic filter
		order by false -- enforce metarialization
	) v3 on v1.i1 = v3.i3;