Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upHHH-12885 - Selecting inverse OneToOne with additional selects in query wrongly produces null #2480
Conversation
6350a38
to
181c43f
@beikov do we agree that this bug is probably also in 5.1? AFAICS, the code is identical. I'm not very fond of how we fix this as it feels a bit like dark magic but I suspect it's the best we can do right now. And it's going to be easier to backport. Good catch, it's puzzling how long this issue stayed hidden. |
resultRow = new Object[queryCols]; | ||
for ( int i = 0; i < queryCols; i++ ) { | ||
resultRow[i] = queryReturnTypes[i].nullSafeGet( rs, scalarColumns[i], session, null ); | ||
// The scalar column names can only be empty if this is a managed type which was already materialized by it's persister |
This comment has been minimized.
This comment has been minimized.
gsmet
Aug 6, 2018
Member
Minor nitpicking: s/it's/its/
.
Maybe I would have gone for When the column is a managed type, the scalar column names array is empty and we have to get the result from the rows array.
.
Yeah and IMO this is critical enough to be backported. I guess not everyone uses inverse one to ones in projections I amended the commit to use your wording. You can go ahead and merge it when you are ok with it. |
@beikov you're insisting about it concerning inverse one to ones but don't you have the issue in any case if you mix scalar and entities for any type of relations? Considering the fix, I would expect the issue to exist with any type of associations. And even with no associations (e.g. wouldn't something like |
AFAICT this only concerns inverse one-to-ones as these are special. Object of that type are constructed by their owners id rather than a dedicated key contained in the result set. |
@beikov I rebased and force pushed. I told you I found it a bit too dark magic for my taste and I broke your fix with a subsequent commit. The issue is that you cannot consider that I think one idea would be to track more info in the |
Hmm, I'll have a look in the next days, but it looks like the |
What I'm wondering is if we are not doing the work twice in the case of the first item of my updated test: it is present in I think that, if possible, we should exploit the elements coming from |
@gsmet I think the fix is doing the right thing now. |
// Types for inverse relationships have a zero column span in which case we have to get the | ||
// result from the row array. | ||
Type queryReturnType = queryReturnTypes[i]; | ||
if ( queryReturnType.getColumnSpan( factory ) == 0 ) { |
This comment has been minimized.
This comment has been minimized.
jwgmeligmeyling
Aug 8, 2018
Contributor
Sure that you don't have to account for includeInSelect
here? Perhaps because this is a scalar query? What happens when you ie. add a FETCH JOIN
to the query?
} | ||
// The row array contains entity objects, we have to count up the index to access inverse relationship | ||
// entities from the row array | ||
if ( queryReturnType.isEntityType() ) { |
This comment has been minimized.
This comment has been minimized.
jwgmeligmeyling
Aug 8, 2018
Contributor
What about other managed types? I.e. selecting an embeddable in a scalar query? Is that even possible?
).list(); | ||
|
||
List<Object[]> tupleList = session.createQuery( | ||
"select b, b.id, a from EntityB b left join b.a a", |
This comment has been minimized.
This comment has been minimized.
jwgmeligmeyling
Aug 8, 2018
Contributor
Perhaps we should add 1 or 2 more cases with reordering the scalars a bit and gather some more confidence regarding the assumptions on the ordering of the arrays. What about select b, b.id, a, a.id from EntityB b left join b.a a
?
Looks good, but initially I had the same worries as Guillaume. Left a couple of comments that might need some explanation. |
…oOne selects
Taking a step back here as I think the issue is larger than what Christian first suspected. I think Christian got the biggest failure we can have with this issue: the expected element not being there at all but I think we make more work than we should in the other cases too. There are two methods contributing to Note that it's either one or the other. Think of both methods as different constructors of a
|
@jwgmeligmeyling looks like a good issue for you if you're interested (and my suggestions make sense to you). I think we might be able to find a working solution this time and commit something :). |
@gsmet I'd happily have another look at it, but I have limited availability for the next two weeks. I might get to it earlier, but probably not before then. Furthermore I might have another look at HHH-12842 first as it is a pretty nasty blocker for me personally (as I am limited to use not much earlier but certainly no newer than 5.2.12, which basically prevents migration to WF12 and WF13, WF12 because I can't get its Infinispan to work with Hibernate 5.2). I'd really like to get that out of the way and move to WF13 (or at that time 14) with Hibernate 5.3. Also, I'd like to hear @beikov 's opinion regarding your findings as well. He seemed pretty adamant that his fix was sufficient. |
About HHH-12842, I think you said Gail had a fix for it as part of other fixes. The patch will eventually get into 5.3. It's on the pending list for inclusion once Gail can finish working on the patch she initiated. Unfortunately, I doubt it will make it for WF 14, considering the feature freeze in on Wednesday.
For now, I'm -1 on including the patch as is. It's too fragile as relying on an unrelated source of information to deal with the elements in |
@gbadner the issue seems unrelated to me. The problem is that this side of the one to one association is mapped by a After looking at the code in Regarding your two concerns about the core assumptions from @beikov :
The approach that @beikov suggests seem to work on the supplied test cases, and the implementation seems to be valid based on the current implementation of |
@jwgmeligmeyling your two points exactly summarizes my issue with this patch as it is (and tbh this remark is not limited to this work but concerns a lot of the code base):
I don't say Christian's reasoning is wrong or the patch in itself is wrong but it relies on assumptions, assumptions that could change with the life of the code. That's why I wanted us to tie closely the creation of the information to the fact that we get it from there. I'm not sure I'll have the time to write some code before 5.4.0.CR1 though so if someone wants to try my suggestion and see how it goes, I don't think it's that much work. |
Hi @gsmet , I understand your concern, and agree with your reasoning. Obviously I prefer a clean, proper solution too. My point was that even if the assumptions change, it would only break the case that is currently already broken (that is, as long as there are no other types besides inverse true one to ones that ever return a column span of 0). I had started to implement your suggested approach prior to my previous commit, but I didnt get it to finish it yet. |
@jwgmeligmeyling is it a large change? I didn't think it would be to be honest so I'm wondering if we're on the same page or if I missed something? Maybe you could share your progress? Thanks! |
Is there anything I can do to make progress on this PR @gsmet ? |
EugenMayer
commented
May 6, 2020
We just ran into this very same bug and thanks to @beikov we were lucky to identify the cause and work arround using Blaze Persistence EntityViews. Still i would love to see this one getting fixed - offering testing capacities :) |
beikov commentedAug 5, 2018
•
edited
Test and fix for https://hibernate.atlassian.net/browse/HHH-12885