[JIRA] (HHH-16747) interpretation of queries with no 'select', multiple elements in 'from', and no explicit result class
by Gavin King (JIRA)
Gavin King ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... ) *updated* an issue
Hibernate ORM ( https://hibernate.atlassian.net/browse/HHH?atlOrigin=eyJpIjoiY2ZjYjA4MzY0... ) / Bug ( https://hibernate.atlassian.net/browse/HHH-16747?atlOrigin=eyJpIjoiY2ZjYj... ) HHH-16747 ( https://hibernate.atlassian.net/browse/HHH-16747?atlOrigin=eyJpIjoiY2ZjYj... ) interpretation of queries with no 'select', multiple elements in 'from', and no explicit result class ( https://hibernate.atlassian.net/browse/HHH-16747?atlOrigin=eyJpIjoiY2ZjYj... )
Change By: Gavin King ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... )
In Hibernate 6, Steve wanted to make a breaking change where a query like this:
{code:sql}from Author a join a.books b where b.title = :title{code}
would be interpreted as returning a single {{Author}} entity, rather than returning an array with an {{Author}} and a {{Book}}.
A priori, this is a completely legit and natural interpretation, but I was _very_ worried about breaking the semantics of existing code by changing something that has had a stable interpretation as far back as Hibernate 1.0.
After some discussion, we settled on what I think was an excellent compromise: to use the result type as a hint to how such queries should be interpreted. So:
{code:java}s.createSelectionQuery("from Author a join a.books b where b.title = :title", Author.class){code}
would have the interpretation Steve prefers, whereas:
{code:java}s.createSelectionQuery("from Author a join a.books b where b.title = :title", Object[].class){code}
would have the same interpretation as always.
I’m completely happy with this, because it doesn’t break old code, and simply turns a case which was previously an _error_ into something useful. Perfect. We released this change in Hibernate 6. I’ve continued along a similar line of thought in [https://hibernate.atlassian.net/browse/HHH-16710|https://hibernate.atlass...].
But, while working on 16710, I noticed a hole in what has actually been implemented. The issue is that we have an overload of {{createSelectionQuery()}} which does not accept a result class. (I’m not sure why we even need this.) There’s also a similar legacy {{createQuery()}} method required for JPA compatibility that is marked deprecated. (That’s the method old code is all using.)
And in this case, the current implementation does not the first thing, not the second thing, but a secret (i.e. undocumented) third thing in certain more complicated cases. Consider:
{code:java}s.createSelectionQuery("from Author a join a.books b, Author c"){code}
This is currently interpreted to return instances of {{Object[]}}containing two {{Author}}s. But if I were to _explicitly_ pass the result type {{Object[].class}} like so:
{code:java}s.createSelectionQuery("from Author a join a.books b, Author c", Object[].class){code}
Then I would get instances of {{Object[]}} with _three_ elements. That’s pretty inconsistent!
Furthermore, if I write the query with a {{cross join}} instead of a comma:
{code:java}s.createSelectionQuery("from Author a join a.books b cross join Author c"){code}
then now I get a single {{Author}} as the result. So {{cross join}} and {{,}} are suddenly pretty different things.
Now, this behavior is at best buglike, and since it has no tests asserting that it was _intentional,_ I’m going to go ahead and call it a bug.
Frankly, in light of all this, I would prefer that we threw an actual exception in the case of a query with no {{select}} clause, multiple identification variables, and no explicit result type. I don’t think there even is any “natural” interpretation there. So I would like to have some reasonable way to simply “deprecate” this usage. (But I can’t think of anything better than a damn {{WARN}}.)
Anyway, the only straightforward “fix” that I can see here that doesn’t make things worse is to revert to the behavior of H5 when there’s no explicit result class. That breaks no tests, ensures that old code continues to work, and eliminates the “secret third thing” interpretation that’s undocumented and quite buglike.
( https://hibernate.atlassian.net/browse/HHH-16747#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16747#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100225- sha1:4a1ccf9 )
2 years, 10 months
[JIRA] (HHH-16747) interpretation of queries with no 'select', multiple elements in 'from', and no explicit result class
by Gavin King (JIRA)
Gavin King ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... ) *created* an issue
Hibernate ORM ( https://hibernate.atlassian.net/browse/HHH?atlOrigin=eyJpIjoiZDdjY2JmMWRl... ) / Bug ( https://hibernate.atlassian.net/browse/HHH-16747?atlOrigin=eyJpIjoiZDdjY2... ) HHH-16747 ( https://hibernate.atlassian.net/browse/HHH-16747?atlOrigin=eyJpIjoiZDdjY2... ) interpretation of queries with no 'select', multiple elements in 'from', and no explicit result class ( https://hibernate.atlassian.net/browse/HHH-16747?atlOrigin=eyJpIjoiZDdjY2... )
Issue Type: Bug Assignee: Unassigned Components: query-hql Created: 05/Jun/2023 01:02 AM Priority: Major Reporter: Gavin King ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... )
In Hibernate 6, Steve wanted to make a breaking change where a query like this:
from Author a join a.books b where b.title = :title
would be interpreted as returning a single Author entity, rather than returning an array with an Author and a Book.
A priori, this is a completely legit and natural interpretation, but I was very worried about breaking the semantics of existing code by changing something that has had a stable interpretation as far back as Hibernate 1.0.
After some discussion, we settled on what I think was an excellent compromise: to use the result type as a hint to how such queries should be interpreted. So:
s.createSelectionQuery( "from Author a join a.books b where b.title = :title" , Author.class)
would have the interpretation Steve prefers, whereas:
s.createSelectionQuery( "from Author a join a.books b where b.title = :title" , Object [].class)
would have the same interpretation as always.
I’m completely happy with this, because it doesn’t break old code, and simply turns a case which was previously an error into something useful. Perfect. We released this change in Hibernate 6. I’ve continued along a similar line of thought in https://hibernate.atlassian.net/browse/HHH-16710.
But, while working on 16710, I noticed a hole in what has actually been implemented. The issue is that we have an overload of createSelectionQuery() which does not accept a result class. (I’m not sure why we even need this.) There’s also a similar legacy createQuery() method required for JPA compatibility. (That’s the method old code is all using.)
And in this case, the current implementation does not the first thing, not the second thing, but a secret (i.e. undocumented) third thing in certain more complicated cases. Consider:
s.createSelectionQuery( "from Author a join a.books b, Author c" )
This is currently interpreted to return instances of Object[]}}containing two {{Author}}s. But if I were to explicitly pass the result type {{Object[].class like so:
s.createSelectionQuery( "from Author a join a.books b, Author c" , Object [].class)
Then I would get instances of Object[] with three elements. That’s pretty inconsistent!
Furthermore, if I write the query with a cross join instead of a comma:
s.createSelectionQuery( "from Author a join a.books b cross join Author c" )
then now I get a single Author as the result. So cross join and , are suddenly pretty different things.
Now, this behavior is at best buglike, and since it has no tests asserting that it was intentional, I’m going to go ahead and call it a bug.
Frankly, in light of all this, I would prefer that we threw an actual exception in the case of a query with no select clause, multiple identification variables, and no explicit result type. I don’t think there even is any “natural” interpretation there. So I would like to have some reasonable way to simply “deprecate” this usage. (But I can’t think of anything better than a damn WARN.)
Anyway, the only straightforward “fix” that I can see here that doesn’t make things worse is to revert to the behavior of H5 when there’s no explicit result class. That breaks no tests, ensures that old code continues to work, and eliminates the “secret third thing” interpretation that’s undocumented and quite buglike.
( https://hibernate.atlassian.net/browse/HHH-16747#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16747#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100225- sha1:4a1ccf9 )
2 years, 10 months