From: <ric...@us...> - 2011-07-23 19:32:05
|
Revision: 5991 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5991&view=rev Author: ricbrown Date: 2011-07-23 19:31:58 +0000 (Sat, 23 Jul 2011) Log Message: ----------- NH-2792: Using a named parameter multiple times in a native SQL query results in invalid parameter binding (exception in some drivers - Oracle) Fixes the following tests on Oracle: NHibernate.Test.Component.Basic.ComponentTest.TestNamedQuery NHibernate.Test.FilterTest.DynamicFilterTest.CriteriaQueryFilters NHibernate.Test.FilterTest.DynamicFilterTest.HqlFilters NHibernate.Test.FilterTest.DynamicFilterTest.ManyToManyFilterOnCriteria NHibernate.Test.FilterTest.DynamicFilterTest.ManyToManyFilterOnQuery NHibernate.Test.FilterTest.DynamicFilterTest.ManyToManyOnCollectionLoadAfterHQL NHibernate.Test.Hql.HQLFunctions.Cast NHibernate.Test.Legacy.FooBarTest.NamedParams NHibernate.Test.NHSpecificTest.ManyToOneFilters20Behaviour.Fixture.ExplicitFiltersOnCollectionsShouldBeActiveWithEagerLoad NHibernate.Test.NHSpecificTest.NH1098.FilterParameterOrderFixture.CriteriaParameterOrder NHibernate.Test.NHSpecificTest.NH1098.FilterParameterOrderFixture.QueryWithNamedParameters NHibernate.Test.NHSpecificTest.NH1098.FilterParameterOrderFixture.QueryWithPositionalParameter NHibernate.Test.NHSpecificTest.NH1293.Fixture.Criteria_Does_Not_Equal_To_HQL NHibernate.Test.NHSpecificTest.NH1490.Fixture.Incorrect_SQL_Translated_Params_Bug NHibernate.Test.NHSpecificTest.NH1864.Fixture.Bug NHibernate.Test.NHSpecificTest.NH1864.Fixture.FilterOnOffOn NHibernate.Test.NHSpecificTest.NH1864.Fixture.FilterQueryTwice NHibernate.Test.NHSpecificTest.NH1868.Fixture.Bug NHibernate.Test.NHSpecificTest.NH1868.Fixture.FilterOnOffOn NHibernate.Test.NHSpecificTest.NH1868.Fixture.FilterQuery3 NHibernate.Test.NHSpecificTest.NH1868.Fixture.FilterQueryTwice NHibernate.Test.NHSpecificTest.NH1908.Fixture.QueryPropertyInBothFilterAndQuery NHibernate.Test.NHSpecificTest.NH1908.Fixture.QueryPropertyInBothFilterAndQueryUsingWith NHibernate.Test.NHSpecificTest.NH1908ThreadSafety.Fixture.UsingFiltersIsThreadSafe NHibernate.Test.NHSpecificTest.NH1920.Fixture.Can_Query_With_Collection_Size_Condition NHibernate.Test.NHSpecificTest.NH1927.Fixture.CriteriaWithEagerFetch NHibernate.Test.NHSpecificTest.NH1927.Fixture.HqlWithEagerFetch NHibernate.Test.NHSpecificTest.NH1990.Fixture.FetchingBySubqueryFilterParameters NHibernate.Test.NHSpecificTest.NH1990.Fixture.FetchingBySubqueryFilterParametersAndPositionalParameters NHibernate.Test.NHSpecificTest.NH1990.Fixture.FetchingBySubqueryFilterParametersAndPositionalParametersAndNamedParameters NHibernate.Test.NHSpecificTest.NH2318.Fixture.HqlTrimFunctionsWithParameters NHibernate.Test.QueryTest.DetachedQueryFixture.ExecutableNamedQuery NHibernate.Test.SqlTest.Query.SelfReferencingCollectionLoadTest.LoadCollection NHibernate.Test.SubclassFilterTest.DiscrimSubclassFilterTest.FiltersWithSubclass Modified Paths: -------------- trunk/nhibernate/src/NHibernate/AdoNet/AbstractBatcher.cs trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs trunk/nhibernate/src/NHibernate/Driver/IDriver.cs trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs trunk/nhibernate/src/NHibernate/Engine/IBatcher.cs trunk/nhibernate/src/NHibernate/Loader/Loader.cs Modified: trunk/nhibernate/src/NHibernate/AdoNet/AbstractBatcher.cs =================================================================== --- trunk/nhibernate/src/NHibernate/AdoNet/AbstractBatcher.cs 2011-07-23 15:29:50 UTC (rev 5990) +++ trunk/nhibernate/src/NHibernate/AdoNet/AbstractBatcher.cs 2011-07-23 19:31:58 UTC (rev 5991) @@ -222,6 +222,11 @@ } } + public void RemoveUnusedCommandParameters(IDbCommand cmd, SqlString sqlString) + { + Driver.RemoveUnusedCommandParameters(cmd, sqlString); + } + public void ExpandQueryParameters(IDbCommand cmd, SqlString sqlString) { Driver.ExpandQueryParameters(cmd, sqlString); Modified: trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs 2011-07-23 15:29:50 UTC (rev 5990) +++ trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs 2011-07-23 19:31:58 UTC (rev 5991) @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Linq; using NHibernate.Engine; using NHibernate.SqlCommand; using NHibernate.SqlTypes; @@ -213,6 +214,22 @@ return dbParam; } + public void RemoveUnusedCommandParameters(IDbCommand cmd, SqlString sqlString) + { + var formatter = GetSqlStringFormatter(); + formatter.Format(sqlString); + + cmd.Parameters + .Cast<IDbDataParameter>() + .Select(p => p.ParameterName) + .Except(formatter.AssignedParameterNames) + .ToList() + .ForEach(ununsedParameterName => + { + cmd.Parameters.RemoveAt(ununsedParameterName); + }); + } + public virtual void ExpandQueryParameters(IDbCommand cmd, SqlString sqlString) { if (UseNamedPrefixInSql) Modified: trunk/nhibernate/src/NHibernate/Driver/IDriver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Driver/IDriver.cs 2011-07-23 15:29:50 UTC (rev 5990) +++ trunk/nhibernate/src/NHibernate/Driver/IDriver.cs 2011-07-23 19:31:58 UTC (rev 5991) @@ -87,6 +87,14 @@ IDbDataParameter GenerateParameter(IDbCommand command, string name, SqlType sqlType); /// <summary> + /// Remove 'extra' parameters from the IDbCommand + /// </summary> + /// <remarks> + /// We sometimes create more parameters than necessary (see NH-2792 & also comments in SqlStringFormatter.ISqlStringVisitor.Parameter) + /// </remarks> + void RemoveUnusedCommandParameters(IDbCommand cmd, SqlString sqlString); + + /// <summary> /// Expand the parameters of the cmd to have a single parameter for each parameter in the /// sql string /// </summary> Modified: trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs 2011-07-23 15:29:50 UTC (rev 5990) +++ trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs 2011-07-23 19:31:58 UTC (rev 5991) @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using NHibernate.SqlCommand; using NHibernate.Engine.Query; @@ -12,12 +13,9 @@ private int parameterIndex = 0; private readonly ISqlParameterFormatter formatter; private readonly string multipleQueriesSeparator; - - private readonly Dictionary<int, int> queryIndexToNumberOfPreceedingParameters = new Dictionary<int, int>(); - private readonly Dictionary<int, int> parameterIndexToQueryIndex = new Dictionary<int, int>(); - - private bool hasReturnParameter = false; + private bool hasReturnParameter; private bool foundReturnParameter = false; + private IList<string> assignedParameterNames = new List<string>(); public SqlStringFormatter(ISqlParameterFormatter formatter, string multipleQueriesSeparator) { @@ -27,8 +25,7 @@ public void Format(SqlString text) { - DetermineNumberOfPreceedingParametersForEachQuery(text); - foundReturnParameter = false; + hasReturnParameter = DetermineIfSqlStringHasReturnParameter(text); text.Visit(this); } @@ -52,6 +49,7 @@ if (hasReturnParameter && !foundReturnParameter) { result.Append(parameter); + assignedParameterNames.Add(String.Empty); foundReturnParameter = true; return; } @@ -63,50 +61,25 @@ // A candidateplace is making DriverBase.SetCommandParameters a little bit more intelligent... perhaps SqlString aware (see also DriverBase.SetCommandText, DriverBase.GenerateCommand) string name = formatter.GetParameterName(parameter.ParameterPosition ?? parameterIndex); + assignedParameterNames.Add(name); parameterIndex++; result.Append(name); } - private void DetermineNumberOfPreceedingParametersForEachQuery(SqlString text) + private bool DetermineIfSqlStringHasReturnParameter(SqlString text) { - // NH: this code smell very bad. It look like specific for ORACLE and probably unused even for ORACLE - int currentParameterIndex = 0; - int currentQueryParameterCount = 0; - int currentQueryIndex = 0; - hasReturnParameter = false; - foundReturnParameter = false; - CallableParser.Detail callableDetail = CallableParser.Parse(text.ToString()); + return (callableDetail.IsCallable && callableDetail.HasReturn); + } - if (callableDetail.IsCallable && callableDetail.HasReturn) - hasReturnParameter = true; + public bool HasReturnParameter + { + get { return foundReturnParameter; } + } - foreach (object part in text.Parts) - { - if (part.ToString().Equals(multipleQueriesSeparator)) - { - queryIndexToNumberOfPreceedingParameters[currentQueryIndex] = currentParameterIndex - currentQueryParameterCount; - currentQueryParameterCount = 0; - currentQueryIndex++; - continue; - } - - Parameter parameter = part as Parameter; - - if (parameter != null) - { - if (hasReturnParameter && !foundReturnParameter) - { - foundReturnParameter = true; - } - else - { - parameterIndexToQueryIndex[currentParameterIndex] = currentQueryIndex; - } - currentQueryParameterCount++; - currentParameterIndex++; - } - } + public string[] AssignedParameterNames + { + get { return assignedParameterNames.ToArray(); } } } } Modified: trunk/nhibernate/src/NHibernate/Engine/IBatcher.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/IBatcher.cs 2011-07-23 15:29:50 UTC (rev 5990) +++ trunk/nhibernate/src/NHibernate/Engine/IBatcher.cs 2011-07-23 19:31:58 UTC (rev 5991) @@ -132,6 +132,14 @@ int ExecuteNonQuery(IDbCommand cmd); /// <summary> + /// Remove 'extra' parameters from the IDbCommand + /// </summary> + /// <remarks> + /// We sometimes create more parameters than necessary (see NH-2792 & also comments in SqlStringFormatter.ISqlStringVisitor.Parameter) + /// </remarks> + void RemoveUnusedCommandParameters(IDbCommand cmd, SqlString sqlString); + + /// <summary> /// Expand the parameters of the cmd to have a single parameter for each parameter in the /// sql string /// </summary> Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2011-07-23 15:29:50 UTC (rev 5990) +++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2011-07-23 19:31:58 UTC (rev 5991) @@ -1148,6 +1148,7 @@ sqlCommand.Bind(command, session); + session.Batcher.RemoveUnusedCommandParameters(command, sqlString); session.Batcher.ExpandQueryParameters(command, sqlString); } catch (HibernateException) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |