From: <ste...@us...> - 2009-12-01 22:08:36
|
Revision: 4886 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4886&view=rev Author: steverstrong Date: 2009-12-01 22:08:23 +0000 (Tue, 01 Dec 2009) Log Message: ----------- Changes to HQLQueryPlan and IQueryTranslatorFactory to support polymorphic Linq queries Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Engine/Query/FilterQueryPlan.cs trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlToken.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs trunk/nhibernate/src/NHibernate/Hql/Classic/ClassicQueryTranslatorFactory.cs trunk/nhibernate/src/NHibernate/Hql/IQueryTranslatorFactory.cs trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate.Test/App.config trunk/nhibernate/src/NHibernate.Test/BulkManipulation/BaseFixture.cs trunk/nhibernate/src/NHibernate.Test/HQL/Ast/BaseFixture.cs trunk/nhibernate/src/NHibernate.Test/HQL/Ast/HqlFixture.cs trunk/nhibernate/src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs Modified: trunk/nhibernate/src/NHibernate/Engine/Query/FilterQueryPlan.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/FilterQueryPlan.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Engine/Query/FilterQueryPlan.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -8,7 +8,7 @@ /// being filtered. /// </summary> [Serializable] - public class FilterQueryPlan : HQLQueryPlan + public class FilterQueryPlan : HQLStringQueryPlan { private readonly string collectionRole; Modified: trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -7,258 +7,86 @@ using NHibernate.Event; using NHibernate.Hql; using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Impl; using NHibernate.Type; using NHibernate.Util; namespace NHibernate.Engine.Query { + public interface IQueryPlan + { + ParameterMetadata ParameterMetadata { get; } + ISet<string> QuerySpaces { get; } + IQueryTranslator[] Translators { get; } + ReturnMetadata ReturnMetadata { get; } + void PerformList(QueryParameters queryParameters, ISessionImplementor statelessSessionImpl, IList results); + int PerformExecuteUpdate(QueryParameters queryParameters, ISessionImplementor statelessSessionImpl); + IEnumerable<T> PerformIterate<T>(QueryParameters queryParameters, IEventSource session); + IEnumerable PerformIterate(QueryParameters queryParameters, IEventSource session); + } + + public interface IQueryExpressionPlan : IQueryPlan + { + IQueryExpression QueryExpression { get; } + } + /// <summary> Defines a query execution plan for an HQL query (or filter). </summary> [Serializable] - public class HQLQueryPlan + public class HQLQueryPlan : IQueryPlan { - private static readonly ILog log = LogManager.GetLogger(typeof(HQLQueryPlan)); + protected static readonly ILog Log = LogManager.GetLogger(typeof(HQLQueryPlan)); - private readonly string sourceQuery; - private readonly IQueryTranslator[] translators; - private readonly string[] sqlStrings; + private readonly string _sourceQuery; - private readonly ParameterMetadata parameterMetadata; - private readonly ReturnMetadata returnMetadata; - private readonly HashedSet<string> querySpaces; - - private readonly HashedSet<string> enabledFilterNames; - private readonly bool shallow; - private IQueryExpression sourceQueryExpression; - - public HQLQueryPlan(string hql, bool shallow, - IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) - : this(hql, (string) null, shallow, enabledFilters, factory) - { - } - - public HQLQueryPlan(string expressionStr, IQueryExpression queryExpression, bool shallow, - IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) - : this(expressionStr, queryExpression, null, shallow, enabledFilters, factory) + protected HQLQueryPlan(string sourceQuery) { + _sourceQuery = sourceQuery; } - protected internal HQLQueryPlan(string hql, string collectionRole, bool shallow, - IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) - { - sourceQuery = hql; - this.shallow = shallow; - - enabledFilterNames = new HashedSet<string>(enabledFilters.Keys); - - HashedSet<string> combinedQuerySpaces = new HashedSet<string>(); - string[] concreteQueryStrings = QuerySplitter.ConcreteQueries(hql, factory); - int length = concreteQueryStrings.Length; - translators = new IQueryTranslator[length]; - List<string> sqlStringList = new List<string>(); - for (int i = 0; i < length; i++) - { - if (collectionRole == null) - { - translators[i] = - factory.Settings.QueryTranslatorFactory.CreateQueryTranslator(hql, concreteQueryStrings[i], enabledFilters, - factory); - translators[i].Compile(factory.Settings.QuerySubstitutions, shallow); - } - else - { - translators[i] = - factory.Settings.QueryTranslatorFactory.CreateFilterTranslator(hql, concreteQueryStrings[i], enabledFilters, - factory); - ((IFilterTranslator)translators[i]).Compile(collectionRole, factory.Settings.QuerySubstitutions, shallow); - } - foreach (string qs in translators[i].QuerySpaces) - { - combinedQuerySpaces.Add(qs); - } - sqlStringList.AddRange(translators[i].CollectSqlStrings); - } - - sqlStrings = sqlStringList.ToArray(); - querySpaces = combinedQuerySpaces; - - if (length == 0) - { - parameterMetadata = new ParameterMetadata(null, null); - returnMetadata = null; - } - else - { - parameterMetadata = BuildParameterMetadata(translators[0].GetParameterTranslations(), hql); - if (translators[0].IsManipulationStatement) - { - returnMetadata = null; - } - else - { - if (length > 1) - { - int returns = translators[0].ReturnTypes.Length; - returnMetadata = new ReturnMetadata(translators[0].ReturnAliases, new IType[returns]); - } - else - { - returnMetadata = new ReturnMetadata(translators[0].ReturnAliases, translators[0].ReturnTypes); - } - } - } - } - - protected internal HQLQueryPlan(string expressionStr, IQueryExpression queryExpression, string collectionRole, bool shallow, - IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) - { - sourceQueryExpression = queryExpression; - sourceQuery = expressionStr; - this.shallow = shallow; - - enabledFilterNames = new HashedSet<string>(enabledFilters.Keys); - - // TODO - no support for polymorphism here - done during Expression -> AST translation? - // TODO - polymorphism approach used in method above also sucks. Could be done in AST much more cleanly? Look at this... - IQueryTranslatorFactory2 qtFactory = new ASTQueryTranslatorFactory(); - - IQueryTranslator translator = qtFactory.CreateQueryTranslator(expressionStr, queryExpression, enabledFilters, - factory); - - translator.Compile(factory.Settings.QuerySubstitutions, shallow); - - translators = new[] { translator }; - - sqlStrings = new List<string>(translator.CollectSqlStrings).ToArray(); - - querySpaces = new HashedSet<string>(translator.QuerySpaces); - - var parameterTranslations = translator.GetParameterTranslations(); - - var namedParamDescriptorMap = new Dictionary<string, NamedParameterDescriptor>(); - foreach (NamedParameterDescriptor entry in queryExpression.ParameterDescriptors) - { - namedParamDescriptorMap[entry.Name] = - new NamedParameterDescriptor(entry.Name, parameterTranslations.GetNamedParameterExpectedType(entry.Name), - entry.SourceLocations, entry.JpaStyle); - } - - parameterMetadata = new ParameterMetadata(new OrdinalParameterDescriptor[0], namedParamDescriptorMap); - - returnMetadata = new ReturnMetadata(translator.ReturnAliases, translator.ReturnTypes); - } - - public string SourceQuery - { - get { return sourceQuery; } - } - public ISet<string> QuerySpaces { - get { return querySpaces; } + get; + protected set; } public ParameterMetadata ParameterMetadata { - get { return parameterMetadata; } - } + get; + protected set; + } public ReturnMetadata ReturnMetadata { - get { return returnMetadata; } - } + get; + protected set; + } - public ISet EnabledFilterNames - { - get { return enabledFilterNames; } - } - public string[] SqlStrings { - get { return sqlStrings; } - } + get; + protected set; + } - public ISet UtilizedFilterNames - { - get - { - // TODO : add this info to the translator and aggregate it here... - return null; - } - } - - public bool Shallow - { - get { return shallow; } - } - public IQueryTranslator[] Translators { - get - { - IQueryTranslator[] copy = new IQueryTranslator[translators.Length]; - Array.Copy(translators, 0, copy, 0, copy.Length); - return copy; - } - } + get; + protected set; + } - public IQueryExpression QueryExpression - { - get { return sourceQueryExpression; } - } - - private static ParameterMetadata BuildParameterMetadata(IParameterTranslations parameterTranslations, string hql) - { - long start = DateTime.Now.Ticks; - ParamLocationRecognizer recognizer = ParamLocationRecognizer.ParseLocations(hql); - long end = DateTime.Now.Ticks; - if (log.IsDebugEnabled) - { - log.Debug("HQL param location recognition took " + (end - start) + " mills (" + hql + ")"); - } - - int ordinalParamCount = parameterTranslations.OrdinalParameterCount; - int[] locations = recognizer.OrdinalParameterLocationList.ToArray(); - if (parameterTranslations.SupportsOrdinalParameterMetadata && locations.Length != ordinalParamCount) - { - throw new HibernateException("ordinal parameter mismatch"); - } - ordinalParamCount = locations.Length; - OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount]; - for (int i = 1; i <= ordinalParamCount; i++) - { - ordinalParamDescriptors[i - 1] = - new OrdinalParameterDescriptor(i, - parameterTranslations.SupportsOrdinalParameterMetadata - ? parameterTranslations.GetOrdinalParameterExpectedType(i) - : null, locations[i - 1]); - } - - Dictionary<string, NamedParameterDescriptor> namedParamDescriptorMap = new Dictionary<string, NamedParameterDescriptor>(); - foreach (KeyValuePair<string, ParamLocationRecognizer.NamedParameterDescription> entry in recognizer.NamedParameterDescriptionMap) - { - string name = entry.Key; - ParamLocationRecognizer.NamedParameterDescription description = entry.Value; - namedParamDescriptorMap[name] = - new NamedParameterDescriptor(name, parameterTranslations.GetNamedParameterExpectedType(name), - description.BuildPositionsArray(), description.JpaStyle); - - } - return new ParameterMetadata(ordinalParamDescriptors, namedParamDescriptorMap); - } - public void PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results) { - if (log.IsDebugEnabled) + if (Log.IsDebugEnabled) { - log.Debug("find: " + SourceQuery); + Log.Debug("find: " + _sourceQuery); queryParameters.LogParameters(session.Factory); } + bool hasLimit = queryParameters.RowSelection != null && queryParameters.RowSelection.DefinesLimits; - bool needsLimit = hasLimit && translators.Length > 1; + bool needsLimit = hasLimit && Translators.Length > 1; QueryParameters queryParametersToUse; if (needsLimit) { - log.Warn("firstResult/maxResults specified on polymorphic query; applying in memory!"); + Log.Warn("firstResult/maxResults specified on polymorphic query; applying in memory!"); RowSelection selection = new RowSelection(); selection.FetchSize = queryParameters.RowSelection.FetchSize; selection.Timeout = queryParameters.RowSelection.Timeout; @@ -272,9 +100,9 @@ IList combinedResults = results ?? new List<object>(); IdentitySet distinction = new IdentitySet(); int includedCount = -1; - for (int i = 0; i < translators.Length; i++) + for (int i = 0; i < Translators.Length; i++) { - IList tmp = translators[i].List(session, queryParametersToUse); + IList tmp = Translators[i].List(session, queryParametersToUse); if (needsLimit) { // NOTE : firstRow is zero-based @@ -333,28 +161,28 @@ { isMany = null; results = null; - if (log.IsDebugEnabled) + if (Log.IsDebugEnabled) { - log.Debug("enumerable: " + SourceQuery); + Log.Debug("enumerable: " + _sourceQuery); queryParameters.LogParameters(session.Factory); } - if (translators.Length == 0) + if (Translators.Length == 0) { result = CollectionHelper.EmptyEnumerable; } else { results = null; - bool many = translators.Length > 1; + bool many = Translators.Length > 1; if (many) { - results = new IEnumerable[translators.Length]; + results = new IEnumerable[Translators.Length]; } result = null; - for (int i = 0; i < translators.Length; i++) + for (int i = 0; i < Translators.Length; i++) { - result = translators[i].GetEnumerable(queryParameters, session); + result = Translators[i].GetEnumerable(queryParameters, session); if (many) results[i] = result; } @@ -364,22 +192,191 @@ public int PerformExecuteUpdate(QueryParameters queryParameters, ISessionImplementor session) { - if (log.IsDebugEnabled) + if (Log.IsDebugEnabled) { - log.Debug("executeUpdate: " + SourceQuery); + Log.Debug("executeUpdate: " + _sourceQuery); queryParameters.LogParameters(session.Factory); } - if (translators.Length != 1) + if (Translators.Length != 1) { - log.Warn("manipulation query [" + SourceQuery + "] resulted in [" + translators.Length + "] split queries"); + Log.Warn("manipulation query [" + _sourceQuery + "] resulted in [" + Translators.Length + "] split queries"); } int result = 0; - for (int i = 0; i < translators.Length; i++) + for (int i = 0; i < Translators.Length; i++) { - result += translators[i].ExecuteUpdate(queryParameters, session); + result += Translators[i].ExecuteUpdate(queryParameters, session); } return result; } - } + protected void BuildSqlStringsAndQuerySpaces() + { + var combinedQuerySpaces = new HashedSet<string>(); + var sqlStringList = new List<string>(); + + foreach (var translator in Translators) + { + foreach (var qs in translator.QuerySpaces) + { + combinedQuerySpaces.Add(qs); + } + + sqlStringList.AddRange(translator.CollectSqlStrings); + } + + SqlStrings = sqlStringList.ToArray(); + QuerySpaces = combinedQuerySpaces; + } + } + + [Serializable] + public class HQLStringQueryPlan : HQLQueryPlan + { + public HQLStringQueryPlan(string hql, bool shallow, + IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + : this(hql, (string) null, shallow, enabledFilters, factory) + { + } + + protected internal HQLStringQueryPlan(string hql, string collectionRole, bool shallow, + IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + :base(hql) + { + Translators = factory.Settings.QueryTranslatorFactory.CreateQueryTranslators(hql, collectionRole, shallow, enabledFilters, factory); + + BuildSqlStringsAndQuerySpaces(); + + if (Translators.Length == 0) + { + ParameterMetadata = new ParameterMetadata(null, null); + ReturnMetadata = null; + } + else + { + ParameterMetadata = BuildParameterMetadata(Translators[0].GetParameterTranslations(), hql); + if (Translators[0].IsManipulationStatement) + { + ReturnMetadata = null; + } + else + { + if (Translators.Length > 1) + { + int returns = Translators[0].ReturnTypes.Length; + ReturnMetadata = new ReturnMetadata(Translators[0].ReturnAliases, new IType[returns]); + } + else + { + ReturnMetadata = new ReturnMetadata(Translators[0].ReturnAliases, Translators[0].ReturnTypes); + } + } + } + } + + private static ParameterMetadata BuildParameterMetadata(IParameterTranslations parameterTranslations, string hql) + { + long start = DateTime.Now.Ticks; + ParamLocationRecognizer recognizer = ParamLocationRecognizer.ParseLocations(hql); + long end = DateTime.Now.Ticks; + if (Log.IsDebugEnabled) + { + Log.Debug("HQL param location recognition took " + (end - start) + " mills (" + hql + ")"); + } + + int ordinalParamCount = parameterTranslations.OrdinalParameterCount; + int[] locations = recognizer.OrdinalParameterLocationList.ToArray(); + if (parameterTranslations.SupportsOrdinalParameterMetadata && locations.Length != ordinalParamCount) + { + throw new HibernateException("ordinal parameter mismatch"); + } + ordinalParamCount = locations.Length; + OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount]; + for (int i = 1; i <= ordinalParamCount; i++) + { + ordinalParamDescriptors[i - 1] = + new OrdinalParameterDescriptor(i, + parameterTranslations.SupportsOrdinalParameterMetadata + ? parameterTranslations.GetOrdinalParameterExpectedType(i) + : null, locations[i - 1]); + } + + Dictionary<string, NamedParameterDescriptor> namedParamDescriptorMap = new Dictionary<string, NamedParameterDescriptor>(); + foreach (KeyValuePair<string, ParamLocationRecognizer.NamedParameterDescription> entry in recognizer.NamedParameterDescriptionMap) + { + string name = entry.Key; + ParamLocationRecognizer.NamedParameterDescription description = entry.Value; + namedParamDescriptorMap[name] = + new NamedParameterDescriptor(name, parameterTranslations.GetNamedParameterExpectedType(name), + description.BuildPositionsArray(), description.JpaStyle); + + } + return new ParameterMetadata(ordinalParamDescriptors, namedParamDescriptorMap); + } + } + + [Serializable] + public class HQLLinqQueryPlan : HQLQueryPlan, IQueryExpressionPlan + { + public IQueryExpression QueryExpression + { + get; + protected set; + } + + public HQLLinqQueryPlan(string expressionStr, IQueryExpression queryExpression, bool shallow, + IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + : this(expressionStr, queryExpression, null, shallow, enabledFilters, factory) + { + } + + protected internal HQLLinqQueryPlan(string expressionStr, IQueryExpression queryExpression, string collectionRole, bool shallow, + IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + : base (expressionStr) + { + QueryExpression = queryExpression; + + IQueryTranslatorFactory2 qtFactory = new ASTQueryTranslatorFactory(); + + Translators = qtFactory.CreateQueryTranslators(expressionStr, queryExpression, collectionRole, shallow, enabledFilters, factory); + + BuildSqlStringsAndQuerySpaces(); + + if (Translators.Length == 0) + { + ParameterMetadata = new ParameterMetadata(null, null); + ReturnMetadata = null; + } + else + { + var parameterTranslations = Translators[0].GetParameterTranslations(); + + var namedParamDescriptorMap = new Dictionary<string, NamedParameterDescriptor>(); + foreach (NamedParameterDescriptor entry in queryExpression.ParameterDescriptors) + { + namedParamDescriptorMap[entry.Name] = + new NamedParameterDescriptor(entry.Name, parameterTranslations.GetNamedParameterExpectedType(entry.Name), + entry.SourceLocations, entry.JpaStyle); + } + + ParameterMetadata = new ParameterMetadata(new OrdinalParameterDescriptor[0], namedParamDescriptorMap); + + if (Translators[0].IsManipulationStatement) + { + ReturnMetadata = null; + } + else + { + if (Translators.Length > 1) + { + int returns = Translators[0].ReturnTypes.Length; + ReturnMetadata = new ReturnMetadata(Translators[0].ReturnAliases, new IType[returns]); + } + else + { + ReturnMetadata = new ReturnMetadata(Translators[0].ReturnAliases, Translators[0].ReturnTypes); + } + } + } + } + } } Modified: trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -47,10 +47,10 @@ return metadata; } - public HQLQueryPlan GetHQLQueryPlan(string queryString, bool shallow, IDictionary<string, IFilter> enabledFilters) + public IQueryPlan GetHQLQueryPlan(string queryString, bool shallow, IDictionary<string, IFilter> enabledFilters) { var key = new HQLQueryPlanKey(queryString, shallow, enabledFilters); - var plan = (HQLQueryPlan)planCache[key]; + var plan = (IQueryPlan)planCache[key]; if (plan == null) { @@ -58,7 +58,7 @@ { log.Debug("unable to locate HQL query plan in cache; generating (" + queryString + ")"); } - plan = new HQLQueryPlan(queryString, shallow, enabledFilters, factory); + plan = new HQLStringQueryPlan(queryString, shallow, enabledFilters, factory); planCache.Put(key, plan); } else @@ -72,12 +72,12 @@ return plan; } - public HQLQueryPlan GetHQLQueryPlan(IQueryExpression queryExpression, bool shallow, IDictionary<string, IFilter> enabledFilters) + public IQueryExpressionPlan GetHQLQueryPlan(IQueryExpression queryExpression, bool shallow, IDictionary<string, IFilter> enabledFilters) { string expressionStr = queryExpression.Key; var key = new HQLQueryPlanKey(expressionStr, shallow, enabledFilters); - var plan = (HQLQueryPlan)planCache[key]; + var plan = (IQueryExpressionPlan)planCache[key]; if (plan == null) { @@ -85,7 +85,7 @@ { log.Debug("unable to locate HQL query plan in cache; generating (" + expressionStr + ")"); } - plan = new HQLQueryPlan(expressionStr, queryExpression, shallow, enabledFilters, factory); + plan = new HQLLinqQueryPlan(expressionStr, queryExpression, shallow, enabledFilters, factory); planCache.Put(key, plan); } else Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -1,5 +1,12 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Antlr.Runtime; using NHibernate.Engine; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Hql.Ast.ANTLR.Util; +using NHibernate.Hql.Util; namespace NHibernate.Hql.Ast.ANTLR { @@ -12,19 +19,247 @@ /// </summary> public class ASTQueryTranslatorFactory : IQueryTranslatorFactory2 { - public IQueryTranslator CreateQueryTranslator(string queryIdentifier, string queryString, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) + public IQueryTranslator[] CreateQueryTranslators(string queryString, string collectionRole, bool shallow, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) { - return new QueryTranslatorImpl(queryIdentifier, queryString, filters, factory); - } + var isFilter = collectionRole != null; + var parser = new HqlParseEngine(queryString, isFilter, factory); + parser.Parse(); - public IFilterTranslator CreateFilterTranslator(string queryIdentifier, string queryString, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) - { - return new QueryTranslatorImpl(queryIdentifier, queryString, filters, factory); + HqlParseEngine[] polymorphicParsers = AstPolymorphicProcessor.Process(parser, factory); + + var translators = polymorphicParsers + .Select(hql => new QueryTranslatorImpl(queryString, hql, filters, factory)) + .ToArray(); + + foreach (var translator in translators) + { + if (collectionRole == null) + { + translator.Compile(factory.Settings.QuerySubstitutions, shallow); + } + else + { + translator.Compile(collectionRole, factory.Settings.QuerySubstitutions, shallow); + } + } + + return translators; } - public IQueryTranslator CreateQueryTranslator(string queryIdentifier, IQueryExpression queryExpression, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) + public IQueryTranslator[] CreateQueryTranslators(string queryIdentifier, IQueryExpression queryExpression, string collectionRole, bool shallow, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) { - return new QueryTranslatorImpl(queryIdentifier, queryExpression, filters, factory); + var isFilter = collectionRole != null; + var parser = new HqlParseEngine(queryExpression.Translate(factory), factory); + + HqlParseEngine[] polymorphicParsers = AstPolymorphicProcessor.Process(parser, factory); + + var translators = polymorphicParsers + .Select(hql => new QueryTranslatorImpl(queryIdentifier, hql, filters, factory)) + .ToArray(); + + foreach (var translator in translators) + { + if (collectionRole == null) + { + translator.Compile(factory.Settings.QuerySubstitutions, shallow); + } + else + { + translator.Compile(collectionRole, factory.Settings.QuerySubstitutions, shallow); + } + } + + return translators; } } + + public class AstPolymorphicProcessor + { + public static HqlParseEngine[] Process(HqlParseEngine parser, ISessionFactoryImplementor factory) + { + // Find all the polymorphic "froms" + var fromDetector = new FromDetector(factory); + var polymorphic = new NodeTraverser(fromDetector); + polymorphic.TraverseDepthFirst(parser.Ast); + + if (fromDetector.Map.Count > 0) + { + var parsers = DuplicateTree(parser.Ast, fromDetector.Map); + + return parsers.Select(p => new HqlParseEngine(p, factory)).ToArray(); + } + else + { + return new [] { parser }; + } + } + + private static IEnumerable<IASTNode> DuplicateTree(IASTNode ast, IEnumerable<KeyValuePair<IASTNode, IASTNode[]>> nodeMapping) + { + var replacements = ExpandDictionaryArrays(nodeMapping); + + var dups = new IASTNode[replacements.Count()]; + + for (var i = 0; i < replacements.Count(); i++) + { + dups[i] = DuplicateTree(ast, replacements[i]); + } + + return dups; + } + + private static IASTNode DuplicateTree(IASTNode ast, Dictionary<IASTNode, IASTNode> nodeMapping) + { + IASTNode candidate; + + if (nodeMapping.TryGetValue(ast, out candidate)) + { + return candidate; + } + + var dup = ast.DupNode(); + + foreach (var child in ast) + { + dup.AddChild(DuplicateTree(child, nodeMapping)); + } + + return dup; + } + + static IList<Dictionary<IASTNode, IASTNode>> ExpandDictionaryArrays(IEnumerable<KeyValuePair<IASTNode, IASTNode[]>> input) + { + return (from list in ExpandDictionaryArraysInner(input) + select list.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)).ToList(); + } + + static IEnumerable<IEnumerable<KeyValuePair<IASTNode, IASTNode>>> ExpandDictionaryArraysInner(IEnumerable<KeyValuePair<IASTNode, IASTNode[]>> input) + { + var output = new List<IEnumerable<KeyValuePair<IASTNode, IASTNode>>>(); + + foreach (var value in input.First().Value) + { + var inner = new List<KeyValuePair<IASTNode, IASTNode>> + {new KeyValuePair<IASTNode, IASTNode>(input.First().Key, value)}; + + if (input.Count() > 1) + { + output.AddRange(ExpandDictionaryArraysInner(input.Skip(1)).Select(c => c.Union(inner))); + } + else + { + output.Add(inner); + } + } + + return output; + } + + } + + + internal class FromDetector : IVisitationStrategy + { + private readonly ISessionFactoryImplementor _sfi; + private readonly Dictionary<IASTNode, IASTNode[]> _map = new Dictionary<IASTNode, IASTNode[]>(); + + public FromDetector(ISessionFactoryImplementor sfi) + { + _sfi = sfi; + } + + public IDictionary<IASTNode, IASTNode[]> Map + { + get { return _map; } + } + + public void Visit(IASTNode node) + { + if (node.Type == HqlSqlWalker.FROM && node.ChildCount > 0) + { + foreach (var child in node) + { + string className = null; + IASTNode identifer = null; + + if (child.Type == HqlSqlWalker.RANGE) + { + identifer = child.GetChild(0); + + if (identifer.Type == HqlSqlWalker.IDENT) + { + className = identifer.Text; + } + else if (identifer.Type == HqlSqlWalker.DOT) + { + className = BuildPath(identifer); + } + else + { + // TODO + throw new NotSupportedException(); + } + } + else + { + // TODO - stuff for joins? + } + + if (className != null) + { + System.Type classType = (new SessionFactoryHelper(_sfi)).GetImportedClass(className); + + if (classType != null) + { + string[] implementors = _sfi.GetImplementors(classType.FullName); + + if (implementors != null) + { + if (implementors.Length == 1 && + ((implementors[0] == className) || (implementors[0] == classType.FullName))) + { + // No need to change things + return; + } + + Map.Add(identifer, + implementors.Select(implementor => MakeIdent(identifer, implementor)).ToArray()); + } + } + } + } + } + } + + private IASTNode MakeIdent(IASTNode source, string text) + { + var ident = source.DupNode(); + ident.Type = HqlSqlWalker.IDENT; + ident.Text = text; + return ident; + } + + private static string BuildPath(IASTNode node) + { + var sb = new StringBuilder(); + BuildPath(node, sb); + return sb.ToString(); + } + + private static void BuildPath(IASTNode node, StringBuilder sb) + { + if (node.Type == HqlSqlWalker.DOT) + { + BuildPath(node.GetChild(0), sb); + + sb.Append('.'); + sb.Append(node.GetChild(1).Text); + } + else + { + sb.Append(node.Text); + } + } + } + } Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -127,7 +127,7 @@ break; default: // Case 2: The current token is after FROM and before '.'. - if (t != IDENT && input.LA(-1) == FROM && input.LA(2) == DOT) + if (t != IDENT && input.LA(-1) == FROM && ((input.LA(2) == DOT) || (input.LA(2) == IDENT) || (input.LA(2) == -1))) { HqlToken hqlToken = (HqlToken)input.LT(1); if (hqlToken.PossibleId) Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlToken.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlToken.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/HqlToken.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -23,6 +23,20 @@ } /// <summary> + /// Public constructor + /// </summary> + public HqlToken(IToken other) + : base(other) + { + var hqlToken = other as HqlToken; + + if (hqlToken != null) + { + _previousTokenType = hqlToken._previousTokenType; + } + } + + /// <summary> /// Indicates if the token could be an identifier. /// </summary> public bool PossibleId Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -46,12 +46,12 @@ /// <param name="factory">The session factory constructing this translator instance.</param> public QueryTranslatorImpl( string queryIdentifier, - string query, + HqlParseEngine parsedQuery, IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) { _queryIdentifier = queryIdentifier; - _hql = query; + _parser = parsedQuery; _compiled = false; _shallowQuery = false; _enabledFilters = enabledFilters; @@ -466,7 +466,7 @@ } } - internal class HqlParseEngine + public class HqlParseEngine { private static readonly ILog log = LogManager.GetLogger(typeof(HqlParseEngine)); @@ -581,7 +581,7 @@ } } - internal class HqlSqlTranslator + internal class HqlSqlTranslator { private readonly IASTNode _inputAst; private readonly CommonTokenStream _tokens; Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Tree/ASTNode.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -33,10 +33,9 @@ _startIndex = -1; _stopIndex = -1; _childIndex = -1; - _token = other._token; + _token = new HqlToken(other._token); _startIndex = other._startIndex; _stopIndex = other._stopIndex; - } public bool IsNil Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/ClassicQueryTranslatorFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/ClassicQueryTranslatorFactory.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/ClassicQueryTranslatorFactory.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Linq; +using Iesi.Collections.Generic; using NHibernate.Engine; namespace NHibernate.Hql.Classic @@ -8,20 +10,25 @@ /// </summary> public class ClassicQueryTranslatorFactory : IQueryTranslatorFactory { - #region IQueryTranslatorFactory Members - - public IQueryTranslator CreateQueryTranslator(string queryIdentifier, string queryString, IDictionary<string, IFilter> filters, - ISessionFactoryImplementor factory) + public IQueryTranslator[] CreateQueryTranslators(string queryString, string collectionRole, bool shallow, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) { - return new QueryTranslator(queryIdentifier, queryString, filters, factory); - } + var translators = QuerySplitter.ConcreteQueries(queryString, factory) + .Select(hql => new QueryTranslator(queryString, hql, filters, factory)) + .ToArray(); - public IFilterTranslator CreateFilterTranslator(string queryIdentifier, string queryString, IDictionary<string, IFilter> filters, - ISessionFactoryImplementor factory) - { - return new QueryTranslator(queryIdentifier, queryString, filters, factory); + foreach (var translator in translators) + { + if (collectionRole == null) + { + translator.Compile(factory.Settings.QuerySubstitutions, shallow); + } + else + { + translator.Compile(collectionRole, factory.Settings.QuerySubstitutions, shallow); + } + } + + return translators; } - - #endregion } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Hql/IQueryTranslatorFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/IQueryTranslatorFactory.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Hql/IQueryTranslatorFactory.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using Iesi.Collections.Generic; using NHibernate.Engine; namespace NHibernate.Hql @@ -13,31 +15,11 @@ /// Construct a <see cref="NHibernate.Hql.IQueryTranslator"/> instance /// capable of translating an HQL query string. /// </summary> - /// <param name="queryIdentifier"> - /// The query-identifier (used in <see cref="NHibernate.Stat.QueryStatistics"/> collection). - /// This is typically the same as the queryString parameter except for the case of - /// split polymorphic queries which result in multiple physical sql queries. - /// </param> /// <param name="queryString">The query string to be translated</param> /// <param name="filters">Currently enabled filters</param> /// <param name="factory">The session factory</param> /// <returns>An appropriate translator.</returns> - IQueryTranslator CreateQueryTranslator(string queryIdentifier, string queryString, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory); - - /// <summary> - /// Construct a <see cref="NHibernate.Hql.IFilterTranslator"/> instance capable of - /// translating an HQL filter string. - /// </summary> - /// <param name="queryIdentifier"> - /// The query-identifier (used in <see cref="NHibernate.Stat.QueryStatistics"/> collection). - /// This is typically the same as the queryString parameter except for the case of - /// split polymorphic queries which result in multiple physical sql queries. - /// </param> - /// <param name="queryString">The query string to be translated</param> - /// <param name="filters">Currently enabled filters</param> - /// <param name="factory">The session factory</param> - /// <returns>An appropriate translator.</returns> - IFilterTranslator CreateFilterTranslator(string queryIdentifier, string queryString, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory); + IQueryTranslator[] CreateQueryTranslators(string queryString, string collectionRole, bool shallow, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory); } /// <summary> @@ -59,6 +41,6 @@ /// <param name="filters">Currently enabled filters</param> /// <param name="factory">The session factory</param> /// <returns>An appropriate translator.</returns> - IQueryTranslator CreateQueryTranslator(string queryIdentifier, IQueryExpression queryExpression, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory); + IQueryTranslator[] CreateQueryTranslators(string queryIdentifier, IQueryExpression queryExpression, string collectionRole, bool shallow, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory); } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -290,7 +290,7 @@ } } - protected internal virtual HQLQueryPlan GetHQLQueryPlan(string query, bool shallow) + protected internal virtual IQueryPlan GetHQLQueryPlan(string query, bool shallow) { using (new SessionIdLoggingContext(SessionId)) { @@ -298,7 +298,7 @@ } } - protected internal virtual HQLQueryPlan GetHQLQueryPlan(IQueryExpression queryExpression, bool shallow) + protected internal virtual IQueryExpressionPlan GetHQLQueryPlan(IQueryExpression queryExpression, bool shallow) { using (new SessionIdLoggingContext(SessionId)) { Modified: trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -619,7 +619,7 @@ { CheckAndUpdateSessionStatus(); queryParameters.ValidateParameters(); - HQLQueryPlan plan = GetHQLQueryPlan(query, false); + var plan = GetHQLQueryPlan(query, false); AutoFlushIfRequired(plan.QuerySpaces); bool success = false; @@ -663,7 +663,7 @@ { CheckAndUpdateSessionStatus(); queryParameters.ValidateParameters(); - HQLQueryPlan plan = GetHQLQueryPlan(queryExpression, false); + var plan = GetHQLQueryPlan(queryExpression, false); AutoFlushIfRequired(plan.QuerySpaces); bool success = false; @@ -694,7 +694,7 @@ { using (new SessionIdLoggingContext(SessionId)) { - HQLQueryPlan plan = Factory.QueryPlanCache.GetHQLQueryPlan(query, scalar, enabledFilters); + var plan = Factory.QueryPlanCache.GetHQLQueryPlan(query, scalar, enabledFilters); AutoFlushIfRequired(plan.QuerySpaces); return plan.Translators; } @@ -730,7 +730,7 @@ { CheckAndUpdateSessionStatus(); queryParameters.ValidateParameters(); - HQLQueryPlan plan = GetHQLQueryPlan(query, true); + var plan = GetHQLQueryPlan(query, true); AutoFlushIfRequired(plan.QuerySpaces); dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called @@ -751,7 +751,7 @@ { CheckAndUpdateSessionStatus(); queryParameters.ValidateParameters(); - HQLQueryPlan plan = GetHQLQueryPlan(query, true); + var plan = GetHQLQueryPlan(query, true); AutoFlushIfRequired(plan.QuerySpaces); dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called @@ -2785,7 +2785,7 @@ { CheckAndUpdateSessionStatus(); queryParameters.ValidateParameters(); - HQLQueryPlan plan = GetHQLQueryPlan(query, false); + var plan = GetHQLQueryPlan(query, false); AutoFlushIfRequired(plan.QuerySpaces); bool success = false; Modified: trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -109,7 +109,7 @@ { CheckAndUpdateSessionStatus(); queryParameters.ValidateParameters(); - HQLQueryPlan plan = GetHQLQueryPlan(query, false); + var plan = GetHQLQueryPlan(query, false); bool success = false; try { @@ -381,7 +381,7 @@ using (new SessionIdLoggingContext(SessionId)) { // take the union of the query spaces (ie the queried tables) - HQLQueryPlan plan = Factory.QueryPlanCache.GetHQLQueryPlan(query, scalar, EnabledFilters); + var plan = Factory.QueryPlanCache.GetHQLQueryPlan(query, scalar, EnabledFilters); return plan.Translators; } } @@ -964,7 +964,7 @@ { CheckAndUpdateSessionStatus(); queryParameters.ValidateParameters(); - HQLQueryPlan plan = GetHQLQueryPlan(query, false); + var plan = GetHQLQueryPlan(query, false); bool success = false; int result; try Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -346,7 +346,7 @@ if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof (NhQueryable<>)) { - return _hqlTreeBuilder.Ident(t.GetGenericArguments()[0].Name); + return _hqlTreeBuilder.Ident(t.GetGenericArguments()[0].FullName); } } Modified: trunk/nhibernate/src/NHibernate.Test/App.config =================================================================== --- trunk/nhibernate/src/NHibernate.Test/App.config 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate.Test/App.config 2009-12-01 22:08:23 UTC (rev 4886) @@ -43,7 +43,9 @@ <bytecode-provider type="lcg"/> <reflection-optimizer use="true"/> <session-factory name="NHibernate.Test"> - <property name="connection.provider">NHibernate.Test.DebugConnectionProvider, NHibernate.Test</property> + <!--<property name="query.factory_class">NHibernate.Hql.Classic.ClassicQueryTranslatorFactory, NHibernate</property> +--> + <property name="connection.provider">NHibernate.Test.DebugConnectionProvider, NHibernate.Test</property> <property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider, NHibernate</property> <property name="cache.use_query_cache">true</property> <property name="query.startup_check">false</property> Modified: trunk/nhibernate/src/NHibernate.Test/BulkManipulation/BaseFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/BulkManipulation/BaseFixture.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate.Test/BulkManipulation/BaseFixture.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -39,7 +39,7 @@ public string GetSql(string query) { - var qt = new QueryTranslatorImpl(null, query, emptyfilters, sessions); + var qt = new QueryTranslatorImpl(null, new HqlParseEngine(query, false, sessions), emptyfilters, sessions); qt.Compile(null, false); return qt.SQLString; } Modified: trunk/nhibernate/src/NHibernate.Test/HQL/Ast/BaseFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/HQL/Ast/BaseFixture.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate.Test/HQL/Ast/BaseFixture.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -39,7 +39,9 @@ public string GetSql(string query) { - var qt = new QueryTranslatorImpl(null, query, emptyfilters, sessions); + var parser = new HqlParseEngine(query, false, sessions); + parser.Parse(); + var qt = new QueryTranslatorImpl(null, parser, emptyfilters, sessions); qt.Compile(null, false); return qt.SQLString; } Modified: trunk/nhibernate/src/NHibernate.Test/HQL/Ast/HqlFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/HQL/Ast/HqlFixture.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate.Test/HQL/Ast/HqlFixture.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -12,7 +12,7 @@ { protected HQLQueryPlan CreateQueryPlan(string hql, bool scalar) { - return new HQLQueryPlan(hql, scalar, new CollectionHelper.EmptyMapClass<string, IFilter>(), sessions); + return new HQLStringQueryPlan(hql, scalar, new CollectionHelper.EmptyMapClass<string, IFilter>(), sessions); } protected HQLQueryPlan CreateQueryPlan(string hql) Modified: trunk/nhibernate/src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Linq.Expressions; +using NHibernate.Linq; using NHibernate.Test.Linq.Entities; using NUnit.Framework; @@ -97,5 +98,20 @@ Assert.AreNotEqual(firstResultOnPage3.ProductId, firstResultOnPage4.ProductId); Assert.AreNotEqual(firstResultOnPage2.ProductId, firstResultOnPage4.ProductId); } + + [Test] + public void SelectFromObject() + { + using (var s = OpenSession()) + { + var hql = s.CreateQuery("from System.Object o").List(); + + var r = from o in s.Query<object>() select o; + + var l = r.ToList(); + + Console.WriteLine(l.Count); + } + } } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs 2009-12-01 21:03:41 UTC (rev 4885) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs 2009-12-01 22:08:23 UTC (rev 4886) @@ -39,7 +39,7 @@ { string hql = @"from Customer c where contains(c.Name, :smth)"; - HQLQueryPlan plan = new HQLQueryPlan(hql, false, new CollectionHelper.EmptyMapClass<string, IFilter>(), sessions); + HQLQueryPlan plan = new HQLStringQueryPlan(hql, false, new CollectionHelper.EmptyMapClass<string, IFilter>(), sessions); Assert.AreEqual(1, plan.ParameterMetadata.NamedParameterNames.Count); Assert.AreEqual(1, plan.QuerySpaces.Count); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |