| When building queries with con- and disjunctions in combination with treats on a SINGLE_TABLE inheritance, all types are collected in a single DTYPE IN ('SubType1', 'SubType2') regardless of the location in the original query. This results in queries that are semantically different from the original criteria or JPQL queries. The attached testcase contains two example queries that both should not return any records, but do return 1 or 2 records. Both testcases are built on the same, simple entity hierarchy: a BaseType with 2 SubTypes. All three types define a single column: basevalue, subvalue1 and subvalue2. 2 records are inserted: SubType1(basevalue=200, subvalue1=null) and SubType2(basevalue=100, subvalue2=null). The following JPQL query
select generatedAlias0 from BaseType as generatedAlias0 where
( ( treat(generatedAlias0 as org.hibernate.bugs.SubType1).basevalue=100 )
and ( treat(generatedAlias0 as org.hibernate.bugs.SubType1).subvalue1 is null ) ) or
( ( treat(generatedAlias0 as org.hibernate.bugs.SubType2).basevalue=200 )
and ( treat(generatedAlias0 as org.hibernate.bugs.SubType2).subvalue2 is null ) )
is translated to the following (simplified) SQL:
select * from BaseType basetype0_
where
basetype0_.DTYPE in (
'SubType2', 'SubType1'
)
and (
basetype0_.basevalue=100
and ( basetype0_.subvalue1 is null )
or basetype0_.basevalue=200
and ( basetype0_.subvalue2 is null )
)
The first expression in the disjunction is supposed to match SubType1 only, but now incorrectly matches the SubType2 record. The same holds for the second expression, with the types swapped. The restriction on DTYPE must be part of the sub-expressions inside the disjunction. Note that this example is very similar to one of the examples in the JPA 2.1 spec, section 4.4.9, and I therefore expect this example to also yield an invalid query (and invalid results if, for example, Exempt has an hours column with records > 100):
SELECT e FROM Employee e
WHERE TREAT(e AS Exempt).vacationDays > 10
OR TREAT(e AS Contractor).hours > 100
Changing the disjunction to a conjunction and using '100' for both restrictions on basevalue, results in the following SQL:
select * from BaseType basetype0_
where
basetype0_.DTYPE in (
'SubType2', 'SubType1'
)
and (
basetype0_.basevalue=100
and ( basetype0_.subvalue1 is null )
and basetype0_.basevalue=100
and ( basetype0_.subvalue2 is null )
)
Allthough this second example is a bit far-fetched, it should never return any results (a record can never be a SubTyp1 and SubType2 at the same time). As with the first example, the restrictions on DTYPE must be moved to the sub-expressions inside the conjunction. |