[hibernate-dev] Treat support

Christian Beikov christian.beikov at gmail.com
Fri Aug 5 10:23:48 EDT 2016

Hey Steve,

Am 04.08.2016 um 15:52 schrieb Steve Ebersole:
> Hey Christian,
> In general terms, one of the items on the docket for SQM is better 
> TREAT support; but there is a lot that goes into that statement.  One 
> aspect is what we support in the parser properly in terms of 
> recognition.  Another is how this translates into the generates SQL 
> query.  All of this is being looked at with SQM.
> Also, relatedly, better support for switching on/off JPQL-compliance 
> checking is a goal.
> <background>
> TREAT is an explicit downcast operator.  It allows you to down cast a 
> type reference in order to reference one of its subclass attributes.  
> HQL actually supports implicit downcasting (subclass attribute 
> references).  In a way you can think of HQL as offering TREAT support 
> implicitly.
> </background>
> With all that in mind, see my comments inline...
> On Wed, Aug 3, 2016 at 9:43 PM Christian Beikov 
> <christian.beikov at gmail.com <mailto:christian.beikov at gmail.com>> wrote:
>       * Missing support for treated paths like "TREAT(...).property"
>     in the
>         parser. This is more or less workaroundable for non-root path
>         treats. Since root paths can't be treat joined to my
>     knowledge, some
>         treated paths simple can't be used. Maybe in 90% of the cases
>         hibernate will just resolve to the right property without needing
>         the treat?
> I'm not sure what you mean by "root paths can't be treated".  You mean 
> literally the query root?  As in "MyEntity e" in "select e from 
> MyEntity e"?  If so, yes JPA does not allow for that to be TREAT'ed; 
> but really it makes no sense to allow TREAT there, if you step back 
> and look at it.  A query like "select e from TREAT(MyEntity as MySub) 
> e" makes no sense; its ultimately just the same as "select e from 
> MySub e".  Arguably I guess it *could* make some sense *if* MySub is a 
> sub MappedSuperclass since technically JPA also allows only entities 
> as query roots (HQL does not have this restriction).
What I meant by that is what is shown in the test "selectTreatedRoot" 
which would be a query like "SELECT TREAT(e AS SubEntity).subProperty 
FROM MyEntity e". JPA does not specifically allow TREAT in the SELECT 
clause but in the WHERE clause, and Hibernate does not seem seem to 
support either. Also see: https://hibernate.atlassian.net/browse/HHH-10988
> As discussed above, assuming that "someProp" is a persistent property 
> defined on MySub, this is a perfectly valid HQL: "select e.someProp 
> from MyEntity e".  It is not however valid JPQL; in JPQL you'd have to 
> say: "select treat( e as MySub).someProp from MyEntity e"
That's what I mean with 90% of the cases.
> All that said, the inability to dereference a TREAT'ed path (the 
> ".property" part) would be a bug, and tbh I am surprised that you say 
> this does not work with Hibernate. Which of your tests show this not 
> working?  Is there a related Jira?
See above. There are tests for the select clause in my test project but 
I'd expect treat to work for all clauses.
>       * Missing support for a special case of treat join which apparently
>         was overseen by the JPA spec which would be
>     "TREAT(TREAT(rootPath AS
>         Subtype).relation AS RelationSubtype)". Eclipselink not only
>     allows
>         this syntax but for inner joins also implements the appropriate
>         logic. I am thinking that this might even work in hibernate
>     without
>         the inner treat, but would fail for attributes with same names.
> Do you mean specifically the nesting of TREAT operators? Again, I am 
> surprised that this would not work.  Tests? Jira?
The test "treatJoinTreatedRoot" would show that it's not working. Also 
see the issue: https://hibernate.atlassian.net/browse/HHH-9345
>       * Joins for supertypes and conditions on discriminators are not
>     aware
>         of the join type actually used in the treated join => left join
>         should cascade up the type hierarchy and discriminator checks
>     should
>         contain OR DTYPE IS NULL for left join semantics. If treats are in
>         subconditions the DTYPE checks might even be wrong
> This "restriction" aspect is honestly Hibernate's biggest shortcoming 
> in its TREAT support. Hibernate's "SQL generation machinery" simply 
> was not built to support this.  At all. I hacked together some support 
> for TREAT on top of that legacy "SQL generation machinery", but it is 
> very limited.
A test case that shows a problem is "selectTreatJoinedRelation" which 
does an inner join on Sub1 but left join on Sub2 although the join is a 
left join treated with Sub1. Apart from not expecting Sub2 to be joined 
in that case, the join type is wrong for Sub1. I will formulate how I 
think treat should be translated to SQL and let you know about that.
> This aspect is specifically what we have discussed in terms of TREAT 
> support improvements in SQM.  Keeping track of where the TREAT occurs 
> so that we can later know how to properly handle it, whether that 
> means we can skip parts of the inheritance join tree or maybe need to 
> render some extra WHERE-clause restrictions...
>       * Joins are generated for the whole hierarchy not only the types
>     that
>         are treated => this might seem to be "just" a performance problem,
>         but IMO actually is a correctness problem as it makes a difference
>         if you get e.g. 2 rows or 2 * TYPES rows especially for count
>     queries.
> Generating the joins for the whole hierarchy is important for HQL's 
> implicit downcasting support.  However, that said, there are attempts 
> to restrict that already in place.  IIRC this only works for TREATs 
> that occur in the FROM-clause specifically.  However, I thought that 
> other TREAT operations were still handled in terms of adding 
> restrictions when dictated.  So this might be specific to certain 
> circumstances.
To be honest, I rethought the whole treat support and actually I think 
treat shouldn't result in filtering at all. I will give you a short 
update on this regard when I formulated what I would expect from treat 
exactly as the JPA spec is IMO quite ambiguous.
> Again, which specific tests show this?  Jira?
> ----
> Some specifics of the plan...
> First, internally within the query AST I want to make sure that we 
> model *all* downcasts whether they are implicit or explicit.  In other 
> words, in terms of AST both of these queries would result in the same 
> structure:
>  1. select e.someProp from MyEntity
>  2. select treat(e as MySub).someProp from MyEntity
> Secondly, we need to keep track of various pieces of information 
> pertaining to a downcast 
> (see org.hibernate.sqm.query.from.Downcast/org.hibernate.sqm.query.from.Downcastable). 
> This includes info like:
>  1. The downcast "target"
>  2. The context in which the downcast occurred
>  3. Any/all contexts in which the downcast is used.
> The last 2 items there would specifically lead to:
>   * Which specific inheritance joins are needed - and may indicate
>     join type
>   * Any extra restrictions we may need to add

More information about the hibernate-dev mailing list