Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inserting multiple associations of the same entity fails #3489

Conversation

mihaicodrean
Copy link
Contributor

This works in 5.3.3, for example, but not in 5.5.0.
Thoughts as to why / how to fix?

Here's the failing test message:

NHibernate.Hql.Ast.ANTLR.QuerySyntaxException : A recognition error occurred. [insert into Enrolment (Course, Student) select e.Course, e.Student from Enrolment e]
  ----> Antlr.Runtime.MismatchedTreeNodeException : A recognition error occurred.

And the stack trace:

ErrorCounter.ThrowQueryException() line 71
BasicExecutor.ctor(IStatement statement, IQueryable persister) line 36
QueryTranslatorImpl.BuildAppropriateStatementExecutor(IStatement statement) line 478
QueryTranslatorImpl.DoCompile(IDictionary`2 replacements, Boolean shallow, String collectionRole) line 430
QueryTranslatorImpl.Compile(IDictionary`2 replacements, Boolean shallow) line 116
ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, IASTNode ast, String queryIdentifier, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) line 53
ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) line 21
QueryExpressionPlan.CreateTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) line 37
QueryExpressionPlan.ctor(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) line 19
QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters) line 76
AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow) line 584
AbstractSessionImpl.CreateQuery(String queryString) line 563
HqlBulkOperations.InsertFromSelectWithMultipleAssociations() line 46
--MismatchedTreeNodeException
TreeParser.RecoverFromMismatchedToken(IIntStream input, Int32 ttype, BitSet follow)
BaseRecognizer.Match(IIntStream input, Int32 ttype, BitSet follow)
SqlGenerator.selectClause() line 2099

And the standard output:

13:24:05,570 ERROR Parser:199 - MismatchedTreeNodeException(151!=3)
13:24:05,680 ERROR Parser:199 - MismatchedTreeNodeException(3!=49)
13:24:05,683 ERROR Parser:199 - MismatchedTreeNodeException(49!=3)

@mihaicodrean
Copy link
Contributor Author

I have narrowed it down to this commit: 10393df for #2551.

@maca88 & @bahusoid, can I please bring your attention to this, maybe you have an idea on how to address it?

@mihaicodrean
Copy link
Contributor Author

@fredericDelaporte, I see that the "NHibernate (NHibernate Core)" check step in TeamCity is now failing as expected, for the contributed test. Is the merge just not possible in this case, e.g. can't really contribute failing tests?

@hazzik
Copy link
Member

hazzik commented Feb 16, 2024

Need to mark the test with [KnownBug] attribute

@mihaicodrean
Copy link
Contributor Author

mihaicodrean commented Feb 16, 2024

Need to mark the test with [KnownBug] attribute

Thanks Alex for pointing that out! Added.

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Feb 18, 2024

Squashed and rebased on 5.4.x (11984a0), it does fail too.
The same on the commit prior to #2551 succeeds, see 491e6da. So, it is confirmed it is a 5.4 regression. (And this has been introduced by #2551: I have checked it fails too when applying the test case onto 10393df.)

We should fix it on 5.4.x. As such, the test case needs to be rebased on 5.4.x and the PR needs to target the 5.4.x branch.

For fixing it, I think the troubles lies within SelectClause, but I am not knowledgeable about that code.

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Mar 17, 2024

I have narrowed it to this change, but have not yet devise a proper fix.

The above link points a comment in a long to load file in the review of the PR having introduced this change. Here is a direct link to current code involved in this bug:

if (processedElements.Add(fromElement))
{
combinedFromElements.Add(fromElement);
RenderNonScalarIdentifiers(fromElement, inheritedExpressions.ContainsKey(e) ? null : e, appender);
}
else if (!inheritedExpressions.ContainsKey(e) && node.Parent != null)
{
RemoveChildAndUnsetParent(node);
}

At the second column, the from is already added, causing the execution to go into the else and not rendering the second column.

In debug, forcing the execution to jump directly to RenderNonScalarIdentifiers (so, not adding again the from to combinedFromElements) allows the test to succeed.

fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Mar 17, 2024
@fredericDelaporte fredericDelaporte force-pushed the InsertFromSelectWithMultipleAssociations branch from 1df5de8 to 9265093 Compare March 17, 2024 21:22
@fredericDelaporte fredericDelaporte changed the base branch from master to 5.4.x March 17, 2024 21:22
@fredericDelaporte fredericDelaporte changed the title Added a failing test for the "InsertFromSelectWithMultipleAssociations" use case Inserting multiple associations of the same entity fails Mar 17, 2024
@fredericDelaporte
Copy link
Member

I have now overridden your branch in order to target 5.4.x for a potential fix I have added.

@mihaicodrean
Copy link
Contributor Author

In debug, forcing the execution to jump directly to RenderNonScalarIdentifiers (so, not adding again the from to combinedFromElements) allows the test to succeed.

Thanks much for identifying the root cause!

@@ -494,7 +494,7 @@ private void InitAliases(List<ISelectExpression> selectExpressions)
}

var node = (IASTNode) e;
if (processedElements.Add(fromElement))
if (Walker.IsShallowQuery && node.Type == SqlGenerator.DOT || processedElements.Add(fromElement))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The processedElements set serves a de-duplication purpose of selected entities. But, alone, it fails accounting for associations selected in shallow queries which will be seen as having the same fromElement although being actually different entities being selected.

Shallow queries may still have duplicated entities selected and cannot be entirely ignored for the de-duplication, if we want to keep the test HqlDuplicateEntitySelectionSubQuery as currently is. (I fail to understand why this tests is valid, why should we support the queries in this test, but I did not get answers about this here. And anyway, it has been release in 5.4, so, it is legacy.)

The DOT check allows to recognize cases in shallow queries where the same fromElement may be used by different expressions selecting different things, and a such, needing to be not falsely de-duplicated.

(I thought about checking if the expressions e where "the same" (having same Path) instead when sharing a common fromElement, but that would imply building a dictionary of sets instead of processedElements. I do not consider it is worth it.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fail to understand why this tests is valid, why should we support the queries in this test

To be honest, I don't remember why I've added such test. Looking back at it, I agree that the test shouldn't be added.

Perhaps we could add a TODO for removing test HqlDuplicateEntitySelectionSubQuery in version 5.5 and remove the node.Type == SqlGenerator.DOT part from the condition.

@fredericDelaporte
Copy link
Member

Hazzik and Maca, since the fix is actually from me, I will not approve this PR myself.

Copy link
Contributor

@maca88 maca88 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix looks good to me.

@fredericDelaporte fredericDelaporte merged commit 344b7f3 into nhibernate:5.4.x Mar 23, 2024
21 checks passed
@fredericDelaporte
Copy link
Member

fredericDelaporte commented Mar 24, 2024

An dev package is available here. See also Nighlty builds for more instructions.

@mihaicodrean, may you check this dev package solves the issue for your application, and that none other regression remains?

@mihaicodrean
Copy link
Contributor Author

@mihaicodrean, may you check this dev package solves the issue for your application, and that none other regression remains?

Thanks for the fix! I have applied the patch to my local 5.5.0 branch, and all works as expected for me.

@mihaicodrean mihaicodrean deleted the InsertFromSelectWithMultipleAssociations branch March 25, 2024 08:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants