|
From: <fab...@us...> - 2009-03-28 19:07:13
|
Revision: 4158
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4158&view=rev
Author: fabiomaulo
Date: 2009-03-28 19:07:03 +0000 (Sat, 28 Mar 2009)
Log Message:
-----------
Fix NH-1693 and one more step to fix NH-1098
Thanks to Richard Brown
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs
trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs
trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs
trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs
trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs
trunk/nhibernate/src/NHibernate/Loader/Collection/SubselectCollectionLoader.cs
trunk/nhibernate/src/NHibernate/Loader/Collection/SubselectOneToManyLoader.cs
trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs
trunk/nhibernate/src/NHibernate/Loader/Loader.cs
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
Added Paths:
-----------
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Fixture.cs
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Mappings.hbm.xml
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Model.cs
Modified: trunk/nhibernate/src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -57,58 +57,6 @@
}
}
- /// <summary>
- /// Bind positional parameter values to the <tt>PreparedStatement</tt>
- /// (these are parameters specified by a JDBC-style ?).
- /// </summary>
- private static int BindPositionalParameters(IDbCommand st, QueryParameters queryParameters, int start, ISessionImplementor session)
- {
- object[] values = queryParameters.FilteredPositionalParameterValues;
- IType[] types = queryParameters.FilteredPositionalParameterTypes;
- int span = 0;
- for (int i = 0; i < values.Length; i++)
- {
- types[i].NullSafeSet(st, values[i], start + span, session);
- span += types[i].GetColumnSpan(session.Factory);
- }
- return span;
- }
-
- /// <summary>
- /// Bind named parameters to the <tt>PreparedStatement</tt>. This has an
- /// empty implementation on this superclass and should be implemented by
- /// subclasses (queries) which allow named parameters.
- /// </summary>
- private void BindNamedParameters(IDbCommand ps, IEnumerable<KeyValuePair<string, TypedValue>> namedParams, int start, ISessionImplementor session)
- {
- if (namedParams != null)
- {
- // assumes that types are all of span 1
- int result = 0;
- foreach (KeyValuePair<string, TypedValue> param in namedParams)
- {
- string name = param.Key;
- TypedValue typedval = param.Value;
-
- int[] locs = GetNamedParameterLocs(name);
- for (int i = 0; i < locs.Length; i++)
- {
- if (log.IsDebugEnabled)
- {
- log.Debug(string.Format("BindNamedParameters() {0} -> {1} [{2}]", typedval.Value, name, (locs[i] + start)));
- }
- typedval.Type.NullSafeSet(ps, typedval.Value, locs[i] + start, session);
- }
- result += locs.Length;
- }
- return;
- }
- else
- {
- return;
- }
- }
-
private void CoordinateSharedCacheCleanup(ISessionImplementor session)
{
BulkOperationCleanupAction action = new BulkOperationCleanupAction(session, CustomQuery.QuerySpaces);
@@ -149,9 +97,12 @@
// NH Difference : set Timeout for native query
ps.CommandTimeout = selection.Timeout;
}
- int col = 0; // NH Different (initialized to 1 in JAVA)
- col += BindPositionalParameters(ps, queryParameters, col, session);
- BindNamedParameters(ps, queryParameters.NamedParameters, col, session);
+ // NH Different behavior:
+ // The inital value is 0 (initialized to 1 in JAVA)
+ // The responsibility of parameter binding was entirely moved to QueryParameters
+ // to deal with positionslParameter+NamedParameter+ParameterOfFilters
+
+ queryParameters.BindParameters(ps, GetNamedParameterLocs, 0, session);
result = session.Batcher.ExecuteNonQuery(ps);
}
finally
@@ -180,7 +131,7 @@
List<IType> paramTypeList = new List<IType>();
int span = 0;
- foreach (IType type in parameters.FilteredPositionalParameterTypes)
+ foreach (IType type in parameters.PositionalParameterTypes)
{
paramTypeList.Add(type);
span += type.GetColumnSpan(session.Factory);
Modified: trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -1,5 +1,7 @@
using System;
using System.Collections;
+using System.Collections.Generic;
+using System.Data;
using log4net;
using NHibernate.Hql.Classic;
using NHibernate.Impl;
@@ -7,7 +9,6 @@
using NHibernate.Transform;
using NHibernate.Type;
using NHibernate.Util;
-using System.Collections.Generic;
namespace NHibernate.Engine
{
@@ -17,45 +18,39 @@
[Serializable]
public sealed class QueryParameters
{
- private static readonly ILog log = LogManager.GetLogger(typeof(QueryParameters));
+ public delegate int[] GetNamedParameterLocations(string parameterName);
+ private static readonly ILog log = LogManager.GetLogger(typeof (QueryParameters));
+
private IType[] _positionalParameterTypes;
private object[] _positionalParameterValues;
+ private int[] _positionalParameterLocations;
private IDictionary<string, TypedValue> _namedParameters;
private IDictionary<string, LockMode> _lockModes;
+ private IList<IType> filteredParameterTypes;
+ private IList<object> filteredParameterValues;
+ private IList<int> filteredParameterLocations;
private RowSelection _rowSelection;
private bool _cacheable;
private string _cacheRegion;
- private bool _forceCacheRefresh;
private object[] _collectionKeys;
private object _optionalObject;
private string _optionalEntityName;
private object _optionalId;
private string _comment;
- private bool _naturalKeyLookup;
private bool _readOnly;
- private bool _callable;
- private bool autoDiscoverTypes;
private SqlString processedSQL;
- private IType[] processedPositionalParameterTypes;
- private object[] processedPositionalParameterValues;
private readonly IResultTransformer _resultTransformer;
// not implemented: private ScrollMode _scrollMode;
- public QueryParameters()
- : this(ArrayHelper.EmptyTypeArray, ArrayHelper.EmptyObjectArray)
- {
- }
+ public QueryParameters() : this(ArrayHelper.EmptyTypeArray, ArrayHelper.EmptyObjectArray) {}
- public QueryParameters(IType type, object value)
- : this(new IType[] { type }, new object[] { value })
- {
- }
+ public QueryParameters(IType type, object value) : this(new[] {type}, new[] {value}) {}
- public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues,
- object optionalObject, string optionalEntityName, object optionalObjectId)
+ public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues, object optionalObject,
+ string optionalEntityName, object optionalObjectId)
: this(positionalParameterTypes, postionalParameterValues)
{
_optionalObject = optionalObject;
@@ -64,33 +59,31 @@
}
public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues)
- : this(positionalParameterTypes, postionalParameterValues, null, null, false, null, null, false, null)
- {
- }
+ : this(positionalParameterTypes, postionalParameterValues, null, null, false, null, null, false, null) {}
- public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues,
- object[] collectionKeys)
- : this(positionalParameterTypes, postionalParameterValues, null, collectionKeys)
- {
- }
+ public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues, object[] collectionKeys)
+ : this(positionalParameterTypes, postionalParameterValues, null, collectionKeys) {}
public QueryParameters(IType[] positionalParameterTypes, object[] postionalParameterValues,
- IDictionary<string, TypedValue> namedParameters, object[] collectionKeys)
- : this(positionalParameterTypes, postionalParameterValues, namedParameters, null, null, false, false, null, null, collectionKeys, null)
- {
- }
+ IDictionary<string, TypedValue> namedParameters, object[] collectionKeys)
+ : this(
+ positionalParameterTypes, postionalParameterValues, namedParameters, null, null, false, false, null, null,
+ collectionKeys, null) {}
public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues,
- IDictionary<string, LockMode> lockModes, RowSelection rowSelection, bool cacheable, string cacheRegion, string comment, bool isLookupByNaturalKey, IResultTransformer transformer)
- : this(positionalParameterTypes, positionalParameterValues, null, lockModes, rowSelection, false, cacheable, cacheRegion, comment, null, transformer)
+ IDictionary<string, LockMode> lockModes, RowSelection rowSelection, bool cacheable,
+ string cacheRegion, string comment, bool isLookupByNaturalKey, IResultTransformer transformer)
+ : this(
+ positionalParameterTypes, positionalParameterValues, null, lockModes, rowSelection, false, cacheable, cacheRegion,
+ comment, null, transformer)
{
- _naturalKeyLookup = isLookupByNaturalKey;
+ NaturalKeyLookup = isLookupByNaturalKey;
}
public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues,
- IDictionary<string, TypedValue> namedParameters, IDictionary<string, LockMode> lockModes, RowSelection rowSelection,
- bool readOnly, bool cacheable, string cacheRegion, string comment,
- object[] collectionKeys, IResultTransformer transformer)
+ IDictionary<string, TypedValue> namedParameters, IDictionary<string, LockMode> lockModes,
+ RowSelection rowSelection, bool readOnly, bool cacheable, string cacheRegion, string comment,
+ object[] collectionKeys, IResultTransformer transformer)
{
_positionalParameterTypes = positionalParameterTypes;
_positionalParameterValues = positionalParameterValues;
@@ -103,13 +96,21 @@
_collectionKeys = collectionKeys;
_readOnly = readOnly;
_resultTransformer = transformer;
+
+ if (_positionalParameterLocations == null)
+ {
+ CreatePositionalParameterLocations();
+ }
}
public QueryParameters(IType[] positionalParameterTypes, object[] positionalParameterValues,
- IDictionary<string, TypedValue> namedParameters, IDictionary<string, LockMode> lockModes, RowSelection rowSelection,
- bool readOnly, bool cacheable, string cacheRegion, string comment, object[] collectionKeys,
- object optionalObject, string optionalEntityName, object optionalId, IResultTransformer transformer)
- : this(positionalParameterTypes, positionalParameterValues, namedParameters, lockModes, rowSelection, readOnly, cacheable, cacheRegion, comment, collectionKeys, transformer)
+ IDictionary<string, TypedValue> namedParameters, IDictionary<string, LockMode> lockModes,
+ RowSelection rowSelection, bool readOnly, bool cacheable, string cacheRegion, string comment,
+ object[] collectionKeys, object optionalObject, string optionalEntityName, object optionalId,
+ IResultTransformer transformer)
+ : this(
+ positionalParameterTypes, positionalParameterValues, namedParameters, lockModes, rowSelection, readOnly, cacheable,
+ cacheRegion, comment, collectionKeys, transformer)
{
_optionalEntityName = optionalEntityName;
_optionalId = optionalId;
@@ -141,6 +142,11 @@
set { _positionalParameterTypes = value; }
}
+ public int[] PositionalParameterLocations
+ {
+ get { return _positionalParameterLocations; }
+ }
+
/// <summary>
/// Gets or sets an array of <see cref="object"/> objects that is stored at the index
/// of the Parameter.
@@ -171,6 +177,18 @@
set { _lockModes = value; }
}
+ private void CreatePositionalParameterLocations()
+ {
+ if (_positionalParameterTypes != null)
+ {
+ _positionalParameterLocations = new int[_positionalParameterTypes.Length];
+ for (int i = 0; i < _positionalParameterLocations.Length; i++)
+ {
+ _positionalParameterLocations[i] = i;
+ }
+ }
+ }
+
private int SafeLength(Array array)
{
if (array == null)
@@ -183,11 +201,10 @@
/// <summary></summary>
public void LogParameters(ISessionFactoryImplementor factory)
{
- Printer print = new Printer(factory);
+ var print = new Printer(factory);
if (_positionalParameterValues.Length != 0)
{
- log.Debug("parameters: "
- + print.ToString(_positionalParameterTypes, _positionalParameterValues));
+ log.Debug("parameters: " + print.ToString(_positionalParameterTypes, _positionalParameterValues));
}
if (_namedParameters != null)
@@ -228,16 +245,12 @@
if (typesLength != valuesLength)
{
- throw new QueryException("Number of positional parameter types (" + typesLength +
- ") does not match number of positional parameter values (" + valuesLength + ")");
+ throw new QueryException("Number of positional parameter types (" + typesLength
+ + ") does not match number of positional parameter values (" + valuesLength + ")");
}
}
- public bool ForceCacheRefresh
- {
- get { return _forceCacheRefresh; }
- set { _forceCacheRefresh = value; }
- }
+ public bool ForceCacheRefresh { get; set; }
public string OptionalEntityName
{
@@ -263,11 +276,7 @@
set { _collectionKeys = value; }
}
- public bool Callable
- {
- get { return _callable; }
- set { _callable = value; }
- }
+ public bool Callable { get; set; }
public bool ReadOnly
{
@@ -277,100 +286,178 @@
/************** Filters ********************************/
+ private void AdjustPostionalParameterLocations(int parameterIndex)
+ {
+ for (int i = 0; i < _positionalParameterLocations.Length; i++)
+ {
+ if (_positionalParameterLocations[i] >= parameterIndex)
+ {
+ _positionalParameterLocations[i]++;
+ }
+ }
+ }
+
public void ProcessFilters(SqlString sql, ISessionImplementor session)
{
+ filteredParameterValues = new List<object>();
+ filteredParameterTypes = new List<IType>();
+ filteredParameterLocations = new List<int>();
+
if (session.EnabledFilters.Count == 0 || sql.ToString().IndexOf(ParserHelper.HqlVariablePrefix) < 0)
{
- processedPositionalParameterValues = PositionalParameterValues;
- processedPositionalParameterTypes = PositionalParameterTypes;
processedSQL = sql;
+ return;
}
- else
- {
- Dialect.Dialect dialect = session.Factory.Dialect;
- string symbols = ParserHelper.HqlSeparators + dialect.OpenQuote + dialect.CloseQuote;
- SqlStringBuilder result = new SqlStringBuilder();
+ Dialect.Dialect dialect = session.Factory.Dialect;
+ string symbols = ParserHelper.HqlSeparators + dialect.OpenQuote + dialect.CloseQuote;
- List<object> parameters = new List<object>();
- List<IType> parameterTypes = new List<IType>();
- int parameterCount = 0; // keep track of the positional parameter
+ var result = new SqlStringBuilder();
- foreach (object part in sql.Parts)
+ int parameterIndex = 0; // keep track of the positional parameter
+
+ foreach (var part in sql.Parts)
+ {
+ if (part is Parameter)
{
- if (part is Parameter)
- {
- result.AddParameter();
+ result.AddParameter();
- // (?) can be a position parameter or a named parameter (already substituted by (?),
- // but only the positional parameters are available at this point. Adding them in the
- // order of appearance is best that can be done at this point of time, but if they
- // are mixed with named parameters, the order is still wrong, because values and
- // types for the named parameters are added later to the end of the list.
- // see test fixture NH-1098
- if (parameterCount < PositionalParameterValues.Length)
- {
- parameters.Add(PositionalParameterValues[parameterCount]);
- parameterTypes.Add(PositionalParameterTypes[parameterCount]);
- parameterCount++;
- }
+ // (?) can be a position parameter or a named parameter (already substituted by (?),
+ // but only the positional parameters are available at this point. Adding them in the
+ // order of appearance is best that can be done at this point of time, but if they
+ // are mixed with named parameters, the order is still wrong, because values and
+ // types for the named parameters are added later to the end of the list.
+ // see test fixture NH-1098
- continue;
- }
+ parameterIndex++;
+ continue;
+ }
- StringTokenizer tokenizer = new StringTokenizer((string)part, symbols, true);
+ var tokenizer = new StringTokenizer((string) part, symbols, true);
- foreach (string token in tokenizer)
+ foreach (var token in tokenizer)
+ {
+ if (token.StartsWith(ParserHelper.HqlVariablePrefix))
{
- if (token.StartsWith(ParserHelper.HqlVariablePrefix))
+ string filterParameterName = token.Substring(1);
+ object value = session.GetFilterParameterValue(filterParameterName);
+ IType type = session.GetFilterParameterType(filterParameterName);
+
+ // If the value is not a value of the type but a collection of values...
+ if (value != null && !type.ReturnedClass.IsAssignableFrom(value.GetType()) && // Added to fix NH-882
+ typeof (ICollection).IsAssignableFrom(value.GetType()))
{
- string filterParameterName = token.Substring(1);
- object value = session.GetFilterParameterValue(filterParameterName);
- IType type = session.GetFilterParameterType(filterParameterName);
-
- // If the value is not a value of the type but a collection of values...
- if (value != null &&
- !type.ReturnedClass.IsAssignableFrom(value.GetType()) && // Added to fix NH-882
- typeof(ICollection).IsAssignableFrom(value.GetType()))
+ var coll = (ICollection) value;
+ int i = 0;
+ foreach (var elementValue in coll)
{
- ICollection coll = (ICollection)value;
- int i = 0;
- foreach (object elementValue in coll)
- {
- i++;
- int span = type.GetColumnSpan(session.Factory);
- if (span > 0)
- {
- result.AddParameter();
- parameters.Add(elementValue);
- parameterTypes.Add(type);
- if (i < coll.Count)
- result.Add(", ");
- }
- }
- }
- else
- {
+ i++;
int span = type.GetColumnSpan(session.Factory);
if (span > 0)
{
result.AddParameter();
- parameters.Add(value);
- parameterTypes.Add(type);
+ filteredParameterTypes.Add(type);
+ filteredParameterValues.Add(elementValue);
+ filteredParameterLocations.Add(parameterIndex);
+ AdjustPostionalParameterLocations(parameterIndex);
+ parameterIndex++;
+ if (i < coll.Count)
+ {
+ result.Add(", ");
+ }
}
}
}
else
{
- result.Add(token);
+ int span = type.GetColumnSpan(session.Factory);
+ if (span > 0)
+ {
+ result.AddParameter();
+ filteredParameterTypes.Add(type);
+ filteredParameterValues.Add(value);
+ filteredParameterLocations.Add(parameterIndex);
+ AdjustPostionalParameterLocations(parameterIndex);
+ parameterIndex++;
+ }
}
}
+ else
+ {
+ result.Add(token);
+ }
}
+ }
- processedPositionalParameterValues = parameters.ToArray();
- processedPositionalParameterTypes = parameterTypes.ToArray();
- processedSQL = result.ToSqlString();
+ processedSQL = result.ToSqlString();
+ }
+
+ public int BindParameters(IDbCommand command, GetNamedParameterLocations getNamedParameterLocations, int start,
+ ISessionImplementor session)
+ {
+ var values = new List<object>();
+ var types = new List<IType>();
+ var sources = new List<string>();
+
+ for (int i = 0; i < _positionalParameterLocations.Length; i++)
+ {
+ int location = _positionalParameterLocations[i];
+ object value = _positionalParameterValues[i];
+ IType type = _positionalParameterTypes[i];
+ ArrayHelper.SafeSetValue(values, location, value);
+ ArrayHelper.SafeSetValue(types, location, type);
+ ArrayHelper.SafeSetValue(sources, location, "Positional" + i);
}
+
+ for (int i = 0; i < filteredParameterLocations.Count; i++)
+ {
+ int location = filteredParameterLocations[i];
+ object value = filteredParameterValues[i];
+ IType type = filteredParameterTypes[i];
+ ArrayHelper.SafeSetValue(values, location, value);
+ ArrayHelper.SafeSetValue(types, location, type);
+ ArrayHelper.SafeSetValue(sources, location, "Filter" + i);
+ }
+
+ if ((_namedParameters != null) && (_namedParameters.Count > 0))
+ {
+ foreach (var namedParameter in _namedParameters)
+ {
+ string name = namedParameter.Key;
+ TypedValue typedval = namedParameter.Value;
+ int[] locations = getNamedParameterLocations(name);
+ for (int i = 0; i < locations.Length; i++)
+ {
+ int location = locations[i];
+
+ // can still clash with positional parameters
+ // could consider throwing an exception to locate problem (NH-1098)
+ while ((location < types.Count) && (types[location] != null))
+ {
+ location++;
+ }
+
+ ArrayHelper.SafeSetValue(values, location, typedval.Value);
+ ArrayHelper.SafeSetValue(types, location, typedval.Type);
+ ArrayHelper.SafeSetValue(sources, location, "name" + i);
+ }
+ }
+ }
+
+ int span = 0;
+ for (int i = 0; i < values.Count; i++)
+ {
+ IType type = types[i];
+ object value = values[i];
+ if (log.IsDebugEnabled)
+ {
+ log.Debug(string.Format("BindParameters({0}:{1}) {2} -> [{3}]", "Named", type, value, i));
+ }
+ type.NullSafeSet(command, value, start + span, session);
+ span += type.GetColumnSpan(session.Factory);
+ }
+
+ return span;
}
public SqlString FilteredSQL
@@ -378,42 +465,41 @@
get { return processedSQL; }
}
- public object[] FilteredPositionalParameterValues
+ public IList<IType> FilteredParameterTypes
{
- get { return processedPositionalParameterValues; }
+ get { return filteredParameterTypes; }
}
- public IType[] FilteredPositionalParameterTypes
+ public IList<object> FilteredParameterValues
{
- get { return processedPositionalParameterTypes; }
+ get { return filteredParameterValues; }
}
- public bool NaturalKeyLookup
+ public IList<int> FilteredParameterLocations
{
- get { return _naturalKeyLookup; }
- set { _naturalKeyLookup = value; }
+ get { return filteredParameterLocations; }
}
+ public bool NaturalKeyLookup { get; set; }
+
public IResultTransformer ResultTransformer
{
get { return _resultTransformer; }
}
- public bool HasAutoDiscoverScalarTypes
- {
- get { return autoDiscoverTypes; }
- set { autoDiscoverTypes = value; }
- }
+ public bool HasAutoDiscoverScalarTypes { get; set; }
public QueryParameters CreateCopyUsing(RowSelection selection)
{
- QueryParameters copy = new QueryParameters(_positionalParameterTypes, _positionalParameterValues,
- _namedParameters, _lockModes, selection, _readOnly, _cacheable, _cacheRegion, _comment,
- _collectionKeys, _optionalObject, _optionalEntityName, _optionalId, _resultTransformer);
+ var copy = new QueryParameters(_positionalParameterTypes, _positionalParameterValues, _namedParameters, _lockModes,
+ selection, _readOnly, _cacheable, _cacheRegion, _comment, _collectionKeys,
+ _optionalObject, _optionalEntityName, _optionalId, _resultTransformer);
+ copy._positionalParameterLocations = _positionalParameterLocations;
copy.processedSQL = processedSQL;
- copy.processedPositionalParameterTypes = processedPositionalParameterTypes;
- copy.processedPositionalParameterValues = processedPositionalParameterValues;
+ copy.filteredParameterTypes = filteredParameterTypes;
+ copy.filteredParameterValues = filteredParameterValues;
+ copy.filteredParameterLocations = filteredParameterLocations;
return copy;
}
}
-}
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -701,6 +701,21 @@
return o.ToArray();
}
+ protected override void AdjustNamedParameterLocationsForQueryParameters(QueryParameters parameters)
+ {
+ foreach (int existingParameterLocation in parameters.FilteredParameterLocations)
+ {
+ foreach (IList<int> namedParameterLocations in namedParameters.Values)
+ {
+ for (int index = 0; index < namedParameterLocations.Count; index++)
+ {
+ if (namedParameterLocations[index] == existingParameterLocation)
+ namedParameterLocations[index]++;
+ }
+ }
+ }
+ }
+
public static string ScalarName(int x, int y)
{
return new StringBuilder()
Modified: trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -307,8 +307,7 @@
for (int i = 0; i < loaders.Count; i++)
{
QueryParameters parameter = parameters[i];
- colIndex += loaders[i].BindPositionalParameters(command, parameter, colIndex, session);
- colIndex += loaders[i].BindNamedParameters(command, parameter.NamedParameters, colIndex, session);
+ colIndex += parameter.BindParameters(command, loaders[i].GetNamedParameterLocs, colIndex, session);
}
return colIndex;
}
Modified: trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -632,8 +632,7 @@
{
QueryTranslator translator = Translators[i];
QueryParameters parameter = Parameters[i];
- colIndex += translator.BindPositionalParameters(command, parameter, colIndex, session);
- colIndex += translator.BindNamedParameters(command, parameter.NamedParameters, colIndex, session);
+ colIndex += parameter.BindParameters(command, translator.GetNamedParameterLocs, colIndex, session);
}
return colIndex;
}
Modified: trunk/nhibernate/src/NHibernate/Loader/Collection/SubselectCollectionLoader.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Collection/SubselectCollectionLoader.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate/Loader/Collection/SubselectCollectionLoader.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -28,8 +28,9 @@
}
namedParameters = queryParameters.NamedParameters;
- types = queryParameters.FilteredPositionalParameterTypes;
- values = queryParameters.FilteredPositionalParameterValues;
+ // NH Different behavior: to deal with positionslParameter+NamedParameter+ParameterOfFilters
+ types = queryParameters.PositionalParameterTypes;
+ values = queryParameters.PositionalParameterValues;
this.namedParameterLocMap = namedParameterLocMap;
}
@@ -42,5 +43,23 @@
{
return namedParameterLocMap[name];
}
+
+ protected override void AdjustNamedParameterLocationsForQueryParameters(QueryParameters parameters)
+ {
+ if (namedParameterLocMap == null)
+ return;
+
+ foreach (int existingParameterLocation in parameters.FilteredParameterLocations)
+ {
+ foreach (IList<int> namedParameterLocations in namedParameterLocMap.Values)
+ {
+ for (int index = 0; index < namedParameterLocations.Count; index++)
+ {
+ if (namedParameterLocations[index] >= existingParameterLocation)
+ namedParameterLocations[index]++;
+ }
+ }
+ }
+ }
}
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Loader/Collection/SubselectOneToManyLoader.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Collection/SubselectOneToManyLoader.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate/Loader/Collection/SubselectOneToManyLoader.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -30,8 +30,9 @@
}
namedParameters = queryParameters.NamedParameters;
- types = queryParameters.FilteredPositionalParameterTypes;
- values = queryParameters.FilteredPositionalParameterValues;
+ // NH Different behavior: to deal with positionslParameter+NamedParameter+ParameterOfFilters
+ types = queryParameters.PositionalParameterTypes;
+ values = queryParameters.PositionalParameterValues;
this.namedParameterLocMap = namedParameterLocMap;
}
@@ -44,5 +45,24 @@
{
return namedParameterLocMap[name];
}
+
+ protected override void AdjustNamedParameterLocationsForQueryParameters(QueryParameters parameters)
+ {
+ if (namedParameterLocMap == null)
+ return;
+
+ foreach (int existingParameterLocation in parameters.FilteredParameterLocations)
+ {
+ foreach (IList<int> namedParameterLocations in namedParameterLocMap.Values)
+ {
+ for (int index = 0; index < namedParameterLocations.Count; index++)
+ {
+ if (namedParameterLocations[index] >= existingParameterLocation)
+ namedParameterLocations[index]++;
+ }
+ }
+ }
+ }
+
}
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -320,6 +320,30 @@
}
}
+ protected override void AdjustNamedParameterLocationsForQueryParameters(QueryParameters parameters)
+ {
+ var existingParameterLocations = parameters.FilteredParameterLocations.GetEnumerator();
+ while (existingParameterLocations.MoveNext())
+ {
+ foreach (string name in parameters.NamedParameters.Keys)
+ {
+ object locations = namedParameterBindPoints[name];
+ if (locations is int)
+ {
+ namedParameterBindPoints[name] = ((int)locations) + 1;
+ }
+ else
+ {
+ IList locationsList = (IList)locations;
+ for (int i = 0; i < locationsList.Count; i++)
+ {
+ locationsList[i] = ((int)locationsList[i]) + 1;
+ }
+ }
+ }
+ }
+ }
+
protected override void AutoDiscoverTypes(IDataReader rs)
{
MetaData metadata = new MetaData(rs);
Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -1173,6 +1173,7 @@
protected virtual SqlString ProcessFilters(QueryParameters parameters, ISessionImplementor session)
{
parameters.ProcessFilters(SqlString, session);
+ AdjustNamedParameterLocationsForQueryParameters(parameters);
return parameters.FilteredSQL;
}
@@ -1256,79 +1257,26 @@
protected internal virtual int BindParameterValues(IDbCommand statement, QueryParameters queryParameters,
int startIndex, ISessionImplementor session)
{
- int span = 0;
- span += BindPositionalParameters(statement, queryParameters, startIndex, session);
- span += BindNamedParameters(statement, queryParameters.NamedParameters, startIndex + span, session);
- return span;
+ // NH Different behavior:
+ // The responsibility of parameter binding was entirely moved to QueryParameters
+ // to deal with positionslParameter+NamedParameter+ParameterOfFilters
+ return queryParameters.BindParameters(statement, GetNamedParameterLocs, 0, session);
}
- /// <summary>
- /// Bind positional parameter values to the <c>IDbCommand</c>
- /// (these are parameters specified by ?).
- /// </summary>
- /// <param name="st">The ADO prepared statement </param>
- /// <param name="queryParameters">The encapsulation of the parameter values to be bound. </param>
- /// <param name="start">The position from which to start binding parameter values. </param>
- /// <param name="session">The originating session. </param>
- /// <returns> The number of ADO bind positions actually bound during this method execution. </returns>
- protected internal virtual int BindPositionalParameters(IDbCommand st, QueryParameters queryParameters, int start,
- ISessionImplementor session)
+ public virtual int[] GetNamedParameterLocs(string name)
{
- object[] values = queryParameters.FilteredPositionalParameterValues;
- IType[] types = queryParameters.FilteredPositionalParameterTypes;
-
- int span = 0;
- for (int i = 0; i < values.Length; i++)
- {
- types[i].NullSafeSet(st, values[i], start + span, session);
- span += types[i].GetColumnSpan(session.Factory);
- }
-
- return span;
+ throw new AssertionFailure("no named parameters");
}
- /// <summary>
- /// Bind named parameters to the <c>IDbCommand</c>
- /// </summary>
- /// <param name="st">The <see cref="IDbCommand"/> that contains the parameters.</param>
- /// <param name="namedParams">The named parameters (key) and the values to set.</param>
- /// <param name="session">The <see cref="ISession"/> this Loader is using.</param>
- /// <param name="start"></param>
- protected internal virtual int BindNamedParameters(IDbCommand st, IDictionary<string, TypedValue> namedParams,
- int start, ISessionImplementor session)
+ protected virtual void AdjustNamedParameterLocationsForQueryParameters(QueryParameters parameters)
{
- if (namedParams != null)
- {
- // assumes that types are all of span 1
- int result = 0;
- foreach (KeyValuePair<string, TypedValue> namedParam in namedParams)
- {
- string name = namedParam.Key;
- TypedValue typedval = namedParam.Value;
- int[] locs = GetNamedParameterLocs(name);
- for (int i = 0; i < locs.Length; i++)
- {
- if (log.IsDebugEnabled)
- {
- log.Debug("BindNamedParameters() " + typedval.Value + " -> " + name + " [" + (locs[i] + start) + "]");
- }
- typedval.Type.NullSafeSet(st, typedval.Value, locs[i] + start, session);
- }
- result += locs.Length;
- }
- return result;
- }
- else
- {
- return 0;
- }
+ // if you support named parameter locations (by overriding GetNamedParameterLocs), then you might need to
+ // allow for the locations to be adjusted by introduced filtered parameters by overriding
+ // this method too.
+ if ((parameters.NamedParameters != null) && (parameters.NamedParameters.Keys.Count > 0))
+ throw new AssertionFailure(GetType() + " must override to handle implementation of named parameter locations");
}
- public virtual int[] GetNamedParameterLocs(string name)
- {
- throw new AssertionFailure("no named parameters");
- }
-
/// <summary>
/// Fetch a <c>IDbCommand</c>, call <c>SetMaxRows</c> and then execute it,
/// advance to the first result and return an SQL <c>IDataReader</c>
@@ -1784,16 +1732,24 @@
List<IType> paramTypeList = new List<IType>();
int span = 0;
- foreach (IType type in parameters.FilteredPositionalParameterTypes)
+ for (int index = 0; index < parameters.PositionalParameterTypes.Length; index++)
{
- paramTypeList.Add(type);
+ int location = parameters.PositionalParameterLocations[index];
+ IType type = parameters.PositionalParameterTypes[index];
+ ArrayHelper.SafeSetValue(paramTypeList, location, type);
span += type.GetColumnSpan(Factory);
}
- if (parameters.NamedParameters != null && parameters.NamedParameters.Count > 0)
+ for (int index = 0; index < parameters.FilteredParameterTypes.Count; index++)
{
- int offset = paramTypeList.Count;
+ int location = parameters.FilteredParameterLocations[index];
+ IType type = parameters.FilteredParameterTypes[index];
+ ArrayHelper.SafeSetValue(paramTypeList, location, type);
+ span += type.GetColumnSpan(Factory);
+ }
+ if (parameters.NamedParameters != null && parameters.NamedParameters.Count > 0)
+ {
// convert the named parameters to an array of types
foreach (KeyValuePair<string, TypedValue> namedParameter in parameters.NamedParameters)
{
@@ -1804,7 +1760,14 @@
for (int i = 0; i < locs.Length; i++)
{
- ArrayHelper.SafeSetValue(paramTypeList, locs[i] + offset, typedval.Type);
+ int location = locs[i];
+
+ // can still clash with positional parameters
+ // could consider throwing an exception to locate problem (NH-1098)
+ while ((location < paramTypeList.Count) && (paramTypeList[location] != null))
+ location++;
+
+ ArrayHelper.SafeSetValue(paramTypeList, location, typedval.Type);
}
}
}
Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -121,7 +121,7 @@
Assert.AreEqual( 1, result.Count );
}
- [Test, Ignore( "Known issue, parameter order is wrong when named and positional parameters are mixed" )]
+ [Test]
public void QueryWithNamedParameters()
{
ISession session = OpenSession();
Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Fixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Fixture.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Fixture.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -0,0 +1,76 @@
+using NUnit.Framework;
+using NUnit.Framework.SyntaxHelpers;
+
+namespace NHibernate.Test.NHSpecificTest.NH1693
+{
+ [TestFixture]
+ public class Fixture : BugTestCase
+ {
+ protected override void OnTearDown()
+ {
+ using (var session = OpenSession())
+ {
+ session.Delete("from Invoice");
+ session.Flush();
+ }
+ }
+
+ protected override void OnSetUp()
+ {
+ using (var session = OpenSession())
+ using (var tx = session.BeginTransaction())
+ {
+ session.Save(new Invoice { Mode = "a", Num = 1, Category = 10 });
+ session.Save(new Invoice { Mode = "a", Num = 2, Category = 10 });
+ session.Save(new Invoice { Mode = "a", Num = 3, Category = 20 });
+ session.Save(new Invoice { Mode = "a", Num = 4, Category = 10 });
+ session.Save(new Invoice { Mode = "b", Num = 2, Category = 10 });
+ session.Save(new Invoice { Mode = "b", Num = 3, Category = 10 });
+ session.Save(new Invoice { Mode = "b", Num = 5, Category = 10 });
+
+ tx.Commit();
+ }
+ }
+
+ [Test]
+ public void without_filter()
+ {
+ using (var session = OpenSession())
+ using (var tx = session.BeginTransaction())
+ {
+ var q1 =
+ "from Invoice i where i.Mode='a' and i.Category=:cat and not exists (from Invoice i2 where i2.Mode='a' and i2.Category=:cat and i2.Num=i.Num+1)";
+ var list = session.CreateQuery(q1)
+ .SetParameter("cat", 10)
+ .List<Invoice>();
+ Assert.That(list, Has.Count(2));
+ Assert.That(list[0].Num == 2 && list[0].Mode == "a");
+ Assert.That(list[1].Num == 4 && list[1].Mode == "a");
+
+ tx.Commit();
+ }
+ }
+
+ [Test]
+ public void with_filter()
+ {
+ using (var session = OpenSession())
+ using (var tx = session.BeginTransaction())
+ {
+ session.EnableFilter("modeFilter").SetParameter("currentMode", "a");
+
+ var q1 =
+ "from Invoice i where i.Category=:cat and not exists (from Invoice i2 where i2.Category=:cat and i2.Num=i.Num+1)";
+ var list = session.CreateQuery(q1)
+ .SetParameter("cat", 10)
+ .List<Invoice>();
+ Assert.That(list, Has.Count(2));
+ Assert.That(list[0].Num == 2 && list[0].Mode == "a");
+ Assert.That(list[1].Num == 4 && list[1].Mode == "a");
+
+ tx.Commit();
+ }
+ }
+
+ }
+}
Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Mappings.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Mappings.hbm.xml (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Mappings.hbm.xml 2009-03-28 19:07:03 UTC (rev 4158)
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ assembly="NHibernate.Test"
+ namespace="NHibernate.Test.NHSpecificTest.NH1693">
+
+ <class name="Invoice">
+ <id name="ID" type="Int32">
+ <generator class="hilo" />
+ </id>
+ <property name="Mode" type="String" />
+ <property name="Num" type="Int32" />
+ <property name="Category" type="Int32" />
+
+ <filter name="modeFilter" condition="Mode=:currentMode" />
+ </class>
+
+ <filter-def name="modeFilter">
+ <filter-param name="currentMode" type="String"/>
+ </filter-def>
+
+</hibernate-mapping>
Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Model.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Model.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Model.cs 2009-03-28 19:07:03 UTC (rev 4158)
@@ -0,0 +1,10 @@
+namespace NHibernate.Test.NHSpecificTest.NH1693
+{
+ public class Invoice
+ {
+ public virtual int ID { get; private set; }
+ public virtual string Mode { get; set; }
+ public virtual int Category { get; set; }
+ public virtual int Num { get; set; }
+ }
+}
Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-03-28 16:35:33 UTC (rev 4157)
+++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-03-28 19:07:03 UTC (rev 4158)
@@ -294,6 +294,8 @@
<Compile Include="HQL\BaseFunctionFixture.cs" />
<Compile Include="NHSpecificTest\DtcFailures\DtcFailuresFixture.cs" />
<Compile Include="NHSpecificTest\DtcFailures\Person.cs" />
+ <Compile Include="NHSpecificTest\NH1693\Fixture.cs" />
+ <Compile Include="NHSpecificTest\NH1693\Model.cs" />
<Compile Include="NHSpecificTest\NH1694\Fixture.cs" />
<Compile Include="NHSpecificTest\NH1706\Domain.cs" />
<Compile Include="NHSpecificTest\NH1706\KeyPropertyRefFixture.cs" />
@@ -1696,6 +1698,7 @@
<EmbeddedResource Include="Cascade\JobBatch.hbm.xml" />
<EmbeddedResource Include="Deletetransient\Person.hbm.xml" />
<Content Include="DynamicEntity\package.html" />
+ <EmbeddedResource Include="NHSpecificTest\NH1693\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1710\WithColumnNode.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1710\InLine.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1710\Heuristic.hbm.xml" />
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|