From: <fab...@us...> - 2011-06-14 14:00:54
|
Revision: 5925 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5925&view=rev Author: fabiomaulo Date: 2011-06-14 14:00:44 +0000 (Tue, 14 Jun 2011) Log Message: ----------- Classic QueryTranslator using parameter specifications Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs trunk/nhibernate/src/NHibernate/Hql/Classic/OrderByParser.cs trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs trunk/nhibernate/src/NHibernate/Hql/Classic/WhereParser.cs trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs 2011-06-13 16:01:13 UTC (rev 5924) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs 2011-06-14 14:00:44 UTC (rev 5925) @@ -27,9 +27,13 @@ q.AppendGroupByToken(pathExpressionParser.WhereColumn); pathExpressionParser.AddAssociation(q); } - else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) + else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) //named query parameter { - q.AddNamedParameter(token.Substring(1)); + var name = token.Substring(1); + q.AppendGroupByParameter(name); + } + else if (token.Equals(StringHelper.SqlParameter)) + { q.AppendGroupByParameter(); } else Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/OrderByParser.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/OrderByParser.cs 2011-06-13 16:01:13 UTC (rev 5924) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/OrderByParser.cs 2011-06-14 14:00:44 UTC (rev 5925) @@ -27,7 +27,11 @@ } else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) { - q.AddNamedParameter(token.Substring(1)); + var name = token.Substring(1); + q.AppendOrderByParameter(name); + } + else if (StringHelper.SqlParameter.Equals(token)) + { q.AppendOrderByParameter(); } else Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2011-06-13 16:01:13 UTC (rev 5924) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2011-06-14 14:00:44 UTC (rev 5925) @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Collections; using System.Data; using System.Diagnostics; @@ -11,9 +12,9 @@ using NHibernate.Engine; using NHibernate.Engine.Query; using NHibernate.Event; -using NHibernate.Hql.Util; using NHibernate.Impl; using NHibernate.Loader; +using NHibernate.Param; using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.SqlCommand; @@ -21,8 +22,8 @@ using NHibernate.Type; using NHibernate.Util; using NHibernate.Dialect.Function; -using System.Collections.Specialized; using System.Collections.Generic; +using IQueryable = NHibernate.Persister.Entity.IQueryable; namespace NHibernate.Hql.Classic { @@ -79,6 +80,8 @@ private bool hasScalars; private bool shallowQuery; private QueryTranslator superQuery; + private IList<IParameterSpecification> collectedParameters = new List<IParameterSpecification>(); + private int positionalParameterFound; private class FetchedCollections { @@ -268,7 +271,108 @@ Compile(); } + private int GetPositionalParameterPosition() + { + return superQuery != null ? superQuery.GetPositionalParameterPosition() : positionalParameterFound++; + } + + public SqlString GetNamedParameter(string name) + { + var parameterSpecification = new NamedParameterSpecification(1, 0, name); + var parameter = Parameter.Placeholder; + parameter.BackTrack = parameterSpecification.GetIdsForBackTrack(Factory).First(); + + AddNamedParameter(name); + collectedParameters.Add(parameterSpecification); + return new SqlString(parameter); + } + + public SqlString GetPositionalParameter() + { + var parameterSpecification = new PositionalParameterSpecification(1, 0, GetPositionalParameterPosition()); + var parameter = Parameter.Placeholder; + parameter.BackTrack = parameterSpecification.GetIdsForBackTrack(Factory).First(); + collectedParameters.Add(parameterSpecification); + return new SqlString(parameter); + } + + public IEnumerable<IParameterSpecification> CollectedParameterSpecifications + { + get { return ((superQuery != null) ? superQuery.CollectedParameterSpecifications:Enumerable.Empty<IParameterSpecification>()).Concat(collectedParameters); } + } + + public override ISqlCommand CreateSqlCommand(QueryParameters queryParameters, ISessionImplementor session) + { + // A distinct-copy of parameter specifications collected during query construction + var parameterSpecs = new HashSet<IParameterSpecification>(CollectedParameterSpecifications); + SqlString sql = SqlString.Copy(); + + // dynamic-filter parameters: during the HQL->SQL parsing, filters can be added as SQL_TOKEN/string and the SqlGenerator will not find it + sql = ExpandDynamicFilterParameters(sql, parameterSpecs, session); + AdjustQueryParametersForSubSelectFetching(sql, parameterSpecs, session, queryParameters); // NOTE: see TODO below + + sql = AddLimitsParametersIfNeeded(sql, parameterSpecs, queryParameters, session); + // TODO: for sub-select fetching we have to try to assign the QueryParameter.ProcessedSQL here (with limits) but only after use IParameterSpecification for any kind of queries + + // The PreprocessSQL method can modify the SqlString but should never add parameters (or we have to override it) + sql = PreprocessSQL(sql, queryParameters, session.Factory.Dialect); + + // After the last modification to the SqlString we can collect all parameters types. + parameterSpecs.ResetEffectiveExpectedType(queryParameters); + + return new SqlCommandImpl(sql, parameterSpecs, queryParameters, session.Factory); + } + /// <summary> + /// Obtain an <c>IDbCommand</c> with all parameters pre-bound. Bind positional parameters, + /// named parameters, and limit parameters. + /// </summary> + /// <remarks> + /// Creates an IDbCommand object and populates it with the values necessary to execute it against the + /// database to Load an Entity. + /// </remarks> + /// <param name="queryParameters">The <see cref="QueryParameters"/> to use for the IDbCommand.</param> + /// <param name="scroll">TODO: find out where this is used...</param> + /// <param name="session">The SessionImpl this Command is being prepared in.</param> + /// <returns>A CommandWrapper wrapping an IDbCommand that is ready to be executed.</returns> + protected internal override IDbCommand PrepareQueryCommand(QueryParameters queryParameters, bool scroll, ISessionImplementor session) + { + var sqlCommand = (SqlCommandImpl)CreateSqlCommand(queryParameters, session); + var parameterSpecs = sqlCommand.Specifications; + var query = sqlCommand.Query; + var sqlQueryParametersList = sqlCommand.SqlQueryParametersList; + + parameterSpecs.SetQueryParameterLocations(sqlQueryParametersList, session.Factory); + + IDbCommand command = session.Batcher.PrepareQueryCommand(CommandType.Text, query, sqlCommand.ParameterTypes); + + try + { + RowSelection selection = queryParameters.RowSelection; + if (selection != null && selection.Timeout != RowSelection.NoValue) + { + command.CommandTimeout = selection.Timeout; + } + + sqlCommand.Bind(command, sqlQueryParametersList, 0, session); + + session.Batcher.ExpandQueryParameters(command, query); + } + catch (HibernateException) + { + session.Batcher.CloseCommand(command, null); + throw; + } + catch (Exception sqle) + { + session.Batcher.CloseCommand(command, null); + ADOExceptionReporter.LogExceptions(sqle); + throw; + } + return command; + } + + /// <summary> /// Compile a "normal" query. This method may be called multiple /// times. Subsequent invocations are no-ops. /// </summary> @@ -672,15 +776,17 @@ internal void AppendOrderByToken(string token) { - if (StringHelper.SqlParameter.Equals(token)) - orderByTokens.Add(SqlString.Parameter); - else - orderByTokens.Add(new SqlString(token)); + orderByTokens.Add(new SqlString(token)); } + internal void AppendOrderByParameter(string name) + { + orderByTokens.Add(GetNamedParameter(name)); + } + internal void AppendOrderByParameter() { - orderByTokens.Add(SqlString.Parameter); + orderByTokens.Add(GetPositionalParameter()); } internal void AppendGroupByToken(string token) @@ -688,9 +794,14 @@ groupByTokens.Add(new SqlString(token)); } + internal void AppendGroupByParameter(string name) + { + groupByTokens.Add(GetNamedParameter(name)); + } + internal void AppendGroupByParameter() { - groupByTokens.Add(SqlString.Parameter); + groupByTokens.Add(GetPositionalParameter()); } internal void AppendScalarSelectToken(string token) @@ -703,9 +814,14 @@ scalarSelectTokens.Add(new SqlString(tokens)); } + internal void AppendScalarSelectParameter(string name) + { + scalarSelectTokens.Add(GetNamedParameter(name)); + } + internal void AppendScalarSelectParameter() { - scalarSelectTokens.Add(SqlString.Parameter); + scalarSelectTokens.Add(GetPositionalParameter()); } internal void AddJoin(string name, JoinSequence joinSequence) @@ -1087,10 +1203,21 @@ int parenCount = 1; for (; tokenIdx < tokens.Count && parenCount > 0; tokenIdx++) { - if (tokens[tokenIdx].StartsWithCaseInsensitive(ParserHelper.HqlVariablePrefix) || tokens[tokenIdx].ToString().Equals(StringHelper.SqlParameter)) + if (tokens[tokenIdx].Parts.Count == 1 && (tokens[tokenIdx].Parts.First() is Parameter)) { - functionTokens.Add(SqlString.Parameter); + // the parameter was processed + functionTokens.Add(tokens[tokenIdx]); + continue; } + if (tokens[tokenIdx].StartsWithCaseInsensitive(ParserHelper.HqlVariablePrefix)) + { + string name = tokens[tokenIdx].Substring(1).ToString(); + functionTokens.Add(GetNamedParameter(name)); + } + else if (StringHelper.SqlParameter.Equals(tokens[tokenIdx].ToString())) + { + functionTokens.Add(GetPositionalParameter()); + } else { functionTokens.Add(tokens[tokenIdx]); Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs 2011-06-13 16:01:13 UTC (rev 5924) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs 2011-06-14 14:00:44 UTC (rev 5925) @@ -170,7 +170,11 @@ if (token.StartsWith(ParserHelper.HqlVariablePrefix)) { - q.AddNamedParameter(token.Substring(1)); + string name = token.Substring(1); + q.AppendScalarSelectParameter(name); + } + else if (token.Equals(StringHelper.SqlParameter)) + { q.AppendScalarSelectParameter(); } else if (constantToken) @@ -237,7 +241,11 @@ } else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) { - q.AddNamedParameter(token.Substring(1)); + string name = token.Substring(1); + q.AppendScalarSelectParameter(name); + } + else if (token.Equals(StringHelper.SqlParameter)) + { q.AppendScalarSelectParameter(); } else Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/WhereParser.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/WhereParser.cs 2011-06-13 16:01:13 UTC (rev 5924) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/WhereParser.cs 2011-06-14 14:00:44 UTC (rev 5925) @@ -470,17 +470,17 @@ } else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) //named query parameter { - q.AddNamedParameter(token.Substring(1)); + var name = token.Substring(1); // this is only a temporary parameter to help with the parsing of hql - // when the type becomes known then this will be converted to its real // parameter type. - AppendToken(q, SqlString.Parameter); + AppendToken(q, q.GetNamedParameter(name)); } else if (token.Equals(StringHelper.SqlParameter)) { //if the token is a "?" then we have a Parameter so convert it to a SqlCommand.Parameter // instead of appending a "?" to the WhereTokens - AppendToken(q, SqlString.Parameter); + AppendToken(q, q.GetPositionalParameter()); } else { Modified: trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs 2011-06-13 16:01:13 UTC (rev 5924) +++ trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs 2011-06-14 14:00:44 UTC (rev 5925) @@ -26,11 +26,6 @@ public static readonly SqlString Empty = new SqlString(new object[0]); - public static SqlString Parameter - { - get { return new SqlString(SqlCommand.Parameter.Placeholder); } - } - public SqlString(string sqlPart) { if (StringHelper.IsNotEmpty(sqlPart)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |