HQL multi-table update failure when using a HQL function

Description

When updating a multi-tables entity (due to joined-subclass) with a concat expression, the IParameterSpecification.ExpectedType is left null which causes a null ref exception in the multi-table updater.

System.NullReferenceException : La référence d'objet n'est pas définie à une instance d'un objet. à NHibernate.Param.ParametersBackTrackExtensions.<>c__DisplayClass3_0.<GetQueryParameterTypes>b__7(IType t) dans E:\Projets\nhibernate\nhibernate-core\src\NHibernate\Param\ParametersBackTrackExtensions.cs:ligne 52 à System.Linq.Enumerable.<SelectManyIterator>d__16`2.MoveNext() à System.Linq.Buffer`1..ctor(IEnumerable`1 source) à System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) à NHibernate.Param.ParametersBackTrackExtensions.GetQueryParameterTypes(IEnumerable`1 parameterSpecs, IList`1 sqlQueryParametersList, ISessionFactoryImplementor factory) dans E:\Projets\nhibernate\nhibernate-core\src\NHibernate\Param\ParametersBackTrackExtensions.cs:ligne 52 à NHibernate.Hql.Ast.ANTLR.Exec.MultiTableUpdateExecutor.Execute(QueryParameters parameters, ISessionImplementor session) dans E:\Projets\nhibernate\nhibernate-core\src\NHibernate\Hql\Ast\ANTLR\Exec\MultiTableUpdateExecutor.cs:ligne 151 à NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.ExecuteUpdate(QueryParameters queryParameters, ISessionImplementor session) dans E:\Projets\nhibernate\nhibernate-core\src\NHibernate\Hql\Ast\ANTLR\QueryTranslatorImpl.cs:ligne 162 à NHibernate.Engine.Query.HQLQueryPlan.PerformExecuteUpdate(QueryParameters queryParameters, ISessionImplementor session) dans E:\Projets\nhibernate\nhibernate-core\src\NHibernate\Engine\Query\HQLQueryPlan.cs:ligne 183 à NHibernate.Impl.SessionImpl.ExecuteUpdate(IQueryExpression queryExpression, QueryParameters queryParameters) dans E:\Projets\nhibernate\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:ligne 2470 à NHibernate.Impl.AbstractQueryImpl2.ExecuteUpdate() dans E:\Projets\nhibernate\nhibernate-core\src\NHibernate\Impl\AbstractQueryImpl2.cs:ligne 36 à NHibernate.Test.LinqBulkManipulation.Fixture.MultiTableHqlUpdate() dans E:\Projets\nhibernate\nhibernate-core\src\NHibernate.Test\LinqBulkManipulation\Fixture.cs:ligne 550

This was found by attempting a Linq update. Here are the examples, failing if put in the linq bulk update fixture from PR.

[Test] public void MultiTableHqlUpdate() { using (var s = OpenSession()) using (s.BeginTransaction()) { s.CreateQuery("update Human h set h.Description = concat(h.Description, :p)") .SetParameter("p", " a") .ExecuteUpdate(); } } [Test] public void MultiTableUpdate() { using (var s = OpenSession()) using (s.BeginTransaction()) { var count = s .Query<Human>() .Update() .As(a => new Human { Description = a.Description + " a" }); } }

Environment

None

Activity

Show:

Frédéric Delaporte July 19, 2017 at 12:46 AM
Edited

The HQL case is easy to work around, just change concat by +. That is harder for Linq. The trouble may be more frequent with Linq. When we have a +, it is handled as a binary node in AST, and some custom logic attempts to set the expected type of any parameter in one side thanks to the type of the other side. When we have a concat, it is handled as a method, without any assumption about which type each argument could have, causing parameters inside the concat to stay without an `ExpectedType`.

Then the MultiTableUpdateExecutor fails when calling ParametersBackTrackExtensions.GetQueryParameterTypes, which mandates every parameter to have an expected type. A comment tell to call ResetEffectiveExpectedType before calling GetQueryParameterTypes, but I do not know all the implications, whether it is really the good fix for that case or not, ... And whether we should, instead of reseting all parameters, just "reset" the ones lacking an expected type, or not.

Details

Assignee

Reporter

Components

Affects versions

Priority

Who's Looking?

Open Who's Looking?

Created July 19, 2017 at 12:41 AM
Updated July 19, 2017 at 12:47 AM
Who's Looking?

Flag notifications