[hibernate-dev] Treat support
Christian Beikov
christian.beikov at gmail.com
Tue Aug 23 05:07:22 EDT 2016
Hi,
so I finished my work on the testsuite
<https://github.com/beikov/jpa-treat-variations> for the treat operator.
I also started a forum topic for this discussion:
https://forum.hibernate.org/viewtopic.php?f=1&t=1043553
If anyone is interested, I also started a discussion in the EclipeLink
forum about that:
https://www.eclipse.org/forums/index.php/mn/msg/1080319/1/on/0/?SQ=5ddc74f601d6750e4794121738a57076
I hope we can all agree on an interpretation of how treat should work
and hopefully get a clarification into the spec. Or at least some TCK
tests, as it doesn't seem to assert anything useful right now.
Regards,
Christian
Am 09.08.2016 um 13:14 schrieb Christian Beikov:
> Hello again,
>
> I finished the first part of the test cases for root treats and
> many-to-one treats. I also tried to explain how I would expect treat
> to work and present a reduction/translation strategy to be able to
> reduce thinking just about the base cases.
> Could you comment on that?
> https://github.com/beikov/jpa-treat-variations/blob/master/src/test/java/jpa/test/TreatVariationsTest.java
> The tests show various problems with Hibernate as well as EclipseLink.
> I will add findings from Datanucleus as soon as the relation mapping
> for table per class is supported.
>
> Here is a collection of JIRAs for treat problems
>
> * https://hibernate.atlassian.net/browse/HHH-10988
> * https://hibernate.atlassian.net/browse/HHH-9345
> * https://hibernate.atlassian.net/browse/HHH-9862
> * https://hibernate.atlassian.net/browse/HHH-10768
> * https://hibernate.atlassian.net/browse/HHH-9594
>
> The definition of the semantics according to JPA spec 4.4.9 are a bit
> strange as it does not distinguish between FROM and WHERE clause when
> mentioning filtering on the subtype.
> It specifically says "Use of the TREAT operator therefore also has the
> effect of filtering on the specified type (and its subtypes) as well
> as performing the downcast" and I think this is only relevant for
> treats in the FROM clause.
> Treats in the WHERE clause should not result in filtering. Depending
> on the join type which is used for the treat path, the result of the
> treat is either the subtype instance, or may be NULL in case of a left
> join.
> Since any comparison(except NULL aware operations) with NULL will
> eventually result in FALSE according to the SQL spec, the requirement
> for the treat operator in the WHERE clause to result in FALSE for
> instances that are not a subtype is also fulfilled.
> The section "... and in the case of a restriction, the associated
> predicate is false." didn't consider NULL aware operations so I think
> this is an oversight.
>
> 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).
>>
>> 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"
>>
>> 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?
>>
>>
>> * 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?
>>
>> * 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.
>>
>> 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.
>>
>> 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