From: <ste...@us...> - 2009-12-02 15:07:25
|
Revision: 4893 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4893&view=rev Author: steverstrong Date: 2009-12-02 15:07:16 +0000 (Wed, 02 Dec 2009) Log Message: ----------- Refactoring of HQLQueryPlan changes Modified Paths: -------------- 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/QueryTranslatorImpl.cs trunk/nhibernate/src/NHibernate/Hql/Classic/ClassicQueryTranslatorFactory.cs trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs trunk/nhibernate/src/NHibernate/Hql/IQueryTranslator.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/BulkManipulation/BaseFixture.cs trunk/nhibernate/src/NHibernate.Test/HQL/Ast/BaseFixture.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate/Engine/Query/HQLExpressionQueryPlan.cs trunk/nhibernate/src/NHibernate/Engine/Query/HQLStringQueryPlan.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/AstPolymorphicProcessor.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/CrossJoinDictionaryArrays.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/PolymorphicQuerySourceDetector.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QuerySourceDetector.cs Added: trunk/nhibernate/src/NHibernate/Engine/Query/HQLExpressionQueryPlan.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/HQLExpressionQueryPlan.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Engine/Query/HQLExpressionQueryPlan.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using NHibernate.Hql; +using NHibernate.Hql.Ast.ANTLR; + +namespace NHibernate.Engine.Query +{ + [Serializable] + public class HQLExpressionQueryPlan : HQLQueryPlan, IQueryExpressionPlan + { + public IQueryExpression QueryExpression + { + get; + protected set; + } + + public HQLExpressionQueryPlan(string expressionStr, IQueryExpression queryExpression, bool shallow, + IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + : this(expressionStr, queryExpression, null, shallow, enabledFilters, factory) + { + } + + protected internal HQLExpressionQueryPlan(string expressionStr, IQueryExpression queryExpression, string collectionRole, bool shallow, + IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + : base(expressionStr, CreateTranslators(expressionStr, queryExpression, collectionRole, shallow, enabledFilters, factory)) + { + QueryExpression = queryExpression; + } + + private static IQueryTranslator[] CreateTranslators(string expressionStr, IQueryExpression queryExpression, string collectionRole, bool shallow, IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + { + IQueryTranslatorFactory2 qtFactory = new ASTQueryTranslatorFactory(); + + return qtFactory.CreateQueryTranslators(expressionStr, queryExpression, collectionRole, shallow, enabledFilters, factory); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs 2009-12-02 05:30:33 UTC (rev 4892) +++ trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -1,13 +1,10 @@ using System; using System.Collections; using System.Collections.Generic; -using Iesi.Collections; using Iesi.Collections.Generic; using log4net; using NHibernate.Event; using NHibernate.Hql; -using NHibernate.Hql.Ast.ANTLR; -using NHibernate.Impl; using NHibernate.Type; using NHibernate.Util; @@ -38,39 +35,42 @@ private readonly string _sourceQuery; - protected HQLQueryPlan(string sourceQuery) + protected HQLQueryPlan(string sourceQuery, IQueryTranslator[] translators) { + Translators = translators; _sourceQuery = sourceQuery; + + FinaliseQueryPlan(); } - public ISet<string> QuerySpaces + public ISet<string> QuerySpaces { get; - protected set; + private set; } public ParameterMetadata ParameterMetadata { get; - protected set; + private set; } public ReturnMetadata ReturnMetadata { get; - protected set; + private set; } public string[] SqlStrings { get; - protected set; + private set; } public IQueryTranslator[] Translators { get; - protected set; + private set; } public void PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results) @@ -156,8 +156,26 @@ return new SafetyEnumerable<T>(PerformIterate(queryParameters, session)); } - private void DoIterate(QueryParameters queryParameters, IEventSource session, out bool? isMany, - out IEnumerable[] results, out IEnumerable result) + public int PerformExecuteUpdate(QueryParameters queryParameters, ISessionImplementor session) + { + if (Log.IsDebugEnabled) + { + Log.Debug("executeUpdate: " + _sourceQuery); + queryParameters.LogParameters(session.Factory); + } + if (Translators.Length != 1) + { + Log.Warn("manipulation query [" + _sourceQuery + "] resulted in [" + Translators.Length + "] split queries"); + } + int result = 0; + for (int i = 0; i < Translators.Length; i++) + { + result += Translators[i].ExecuteUpdate(queryParameters, session); + } + return result; + } + + void DoIterate(QueryParameters queryParameters, IEventSource session, out bool? isMany, out IEnumerable[] results, out IEnumerable result) { isMany = null; results = null; @@ -190,176 +208,23 @@ } } - public int PerformExecuteUpdate(QueryParameters queryParameters, ISessionImplementor session) - { - if (Log.IsDebugEnabled) - { - Log.Debug("executeUpdate: " + _sourceQuery); - queryParameters.LogParameters(session.Factory); - } - if (Translators.Length != 1) - { - Log.Warn("manipulation query [" + _sourceQuery + "] resulted in [" + Translators.Length + "] split queries"); - } - int result = 0; - for (int i = 0; i < Translators.Length; i++) - { - result += Translators[i].ExecuteUpdate(queryParameters, session); - } - return result; - } - - protected void BuildSqlStringsAndQuerySpaces() + void FinaliseQueryPlan() { - 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; + BuildSqlStringsAndQuerySpaces(); + BuildMetaData(); } - } - [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(); - + void BuildMetaData() + { 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(); + ParameterMetadata = Translators[0].BuildParameterMetadata(); - 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; @@ -378,5 +243,24 @@ } } } + + 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; + } } } Added: trunk/nhibernate/src/NHibernate/Engine/Query/HQLStringQueryPlan.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/HQLStringQueryPlan.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Engine/Query/HQLStringQueryPlan.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using NHibernate.Hql; + +namespace NHibernate.Engine.Query +{ + [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, CreateTranslators(hql, collectionRole, shallow, enabledFilters, factory)) + { + } + + private static IQueryTranslator[] CreateTranslators(string hql, string collectionRole, bool shallow, IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + { + return factory.Settings.QueryTranslatorFactory.CreateQueryTranslators(hql, collectionRole, shallow, enabledFilters, factory); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs 2009-12-02 05:30:33 UTC (rev 4892) +++ trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -85,7 +85,7 @@ { log.Debug("unable to locate HQL query plan in cache; generating (" + expressionStr + ")"); } - plan = new HQLLinqQueryPlan(expressionStr, queryExpression, shallow, enabledFilters, factory); + plan = new HQLExpressionQueryPlan(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-02 05:30:33 UTC (rev 4892) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -1,12 +1,7 @@ -using System; -using System.Collections.Generic; +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 { @@ -21,37 +16,21 @@ { public IQueryTranslator[] CreateQueryTranslators(string queryString, string collectionRole, bool shallow, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) { - var isFilter = collectionRole != null; - var parser = new HqlParseEngine(queryString, isFilter, factory); - parser.Parse(); + var ast = new HqlParseEngine(queryString, collectionRole != null, factory).Parse(); - HqlParseEngine[] polymorphicParsers = AstPolymorphicProcessor.Process(parser, factory); + return CreateQueryTranslators(ast, queryString, collectionRole, shallow, + filters, 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[] CreateQueryTranslators(string queryIdentifier, IQueryExpression queryExpression, string collectionRole, bool shallow, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) { - var isFilter = collectionRole != null; - var parser = new HqlParseEngine(queryExpression.Translate(factory), factory); + return CreateQueryTranslators(queryExpression.Translate(factory), queryIdentifier, collectionRole, shallow, + filters, factory); + } - HqlParseEngine[] polymorphicParsers = AstPolymorphicProcessor.Process(parser, factory); + static IQueryTranslator[] CreateQueryTranslators(IASTNode ast, string queryIdentifier, string collectionRole, bool shallow, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) + { + var polymorphicParsers = AstPolymorphicProcessor.Process(ast, factory); var translators = polymorphicParsers .Select(hql => new QueryTranslatorImpl(queryIdentifier, hql, filters, factory)) @@ -70,196 +49,7 @@ } 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); - } - } - } - } Added: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/AstPolymorphicProcessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/AstPolymorphicProcessor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/AstPolymorphicProcessor.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Engine; +using NHibernate.Hql.Ast.ANTLR.Tree; + +namespace NHibernate.Hql.Ast.ANTLR +{ + public class AstPolymorphicProcessor + { + private readonly IASTNode _ast; + private readonly ISessionFactoryImplementor _factory; + private IEnumerable<KeyValuePair<IASTNode, IASTNode[]>> _nodeMapping; + + private AstPolymorphicProcessor(IASTNode ast, ISessionFactoryImplementor factory) + { + _ast = ast; + _factory = factory; + } + + public static IASTNode[] Process(IASTNode ast, ISessionFactoryImplementor factory) + { + var processor = new AstPolymorphicProcessor(ast, factory); + + return processor.Process(); + } + + private IASTNode[] Process() + { + // Find all the polymorphic query sources + _nodeMapping = new PolymorphicQuerySourceDetector(_factory).Process(_ast); + + if (_nodeMapping.Count() > 0) + { + return DuplicateTree().ToArray(); + } + else + { + return new[] { _ast }; + } + } + + private IEnumerable<IASTNode> DuplicateTree() + { + var replacements = CrossJoinDictionaryArrays.PerformCrossJoin(_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, IDictionary<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; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/CrossJoinDictionaryArrays.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/CrossJoinDictionaryArrays.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/CrossJoinDictionaryArrays.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Hql.Ast.ANTLR.Tree; + +namespace NHibernate.Hql.Ast.ANTLR +{ + public static class CrossJoinDictionaryArrays + { + public static IList<Dictionary<IASTNode, IASTNode>> PerformCrossJoin(IEnumerable<KeyValuePair<IASTNode, IASTNode[]>> input) + { + return (from list in CrossJoinKeyValuePairList(input) + select list.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)).ToList(); + } + + static IEnumerable<IEnumerable<KeyValuePair<IASTNode, IASTNode>>> CrossJoinKeyValuePairList(IEnumerable<KeyValuePair<IASTNode, IASTNode[]>> input) + { + if (input.Count() == 1) + { + return ExpandKeyValuePair(input.First()); + } + + return from headEntry in ExpandKeyValuePair(input.First()) + from tailEntry in CrossJoinKeyValuePairList(input.Skip(1)) + select headEntry.Union(tailEntry); + } + + static IEnumerable<IEnumerable<KeyValuePair<IASTNode, IASTNode>>> ExpandKeyValuePair(KeyValuePair<IASTNode, IASTNode[]> input) + { + return from i in input.Value + select new List<KeyValuePair<IASTNode, IASTNode>> { new KeyValuePair<IASTNode, IASTNode>(input.Key, i) }.AsEnumerable(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/PolymorphicQuerySourceDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/PolymorphicQuerySourceDetector.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/PolymorphicQuerySourceDetector.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NHibernate.Engine; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Hql.Util; + +namespace NHibernate.Hql.Ast.ANTLR +{ + internal class PolymorphicQuerySourceDetector + { + private readonly ISessionFactoryImplementor _sfi; + private readonly Dictionary<IASTNode, IASTNode[]> _map = new Dictionary<IASTNode, IASTNode[]>(); + private readonly SessionFactoryHelper _sessionFactoryHelper; + + public PolymorphicQuerySourceDetector(ISessionFactoryImplementor sfi) + { + _sfi = sfi; + _sessionFactoryHelper = new SessionFactoryHelper(sfi); + } + + public Dictionary<IASTNode, IASTNode[]> Process(IASTNode tree) + { + foreach (var querySource in new QuerySourceDetector(tree).LocateQuerySources()) + { + var className = GetClassName(querySource); + var classType = _sessionFactoryHelper.GetImportedClass(className); + + if (classType != null) + { + AddImplementorsToMap(querySource, classType); + } + } + + return _map; + } + + private void AddImplementorsToMap(IASTNode querySource, System.Type classType) + { + var implementors = _sfi.GetImplementors(classType.FullName); + + if (implementors.Length == 1 && implementors[0] == classType.FullName) + { + // No need to change things + return; + } + + _map.Add(querySource, + implementors.Select(implementor => MakeIdent(querySource, implementor)).ToArray()); + } + + private static string GetClassName(IASTNode querySource) + { + switch (querySource.Type) + { + case HqlSqlWalker.IDENT: + return querySource.Text; + case HqlSqlWalker.DOT: + return BuildPath(querySource); + } + + // TODO + throw new NotSupportedException(); + } + + private static 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); + } + } + + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QuerySourceDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QuerySourceDetector.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QuerySourceDetector.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Hql.Ast.ANTLR.Util; + +namespace NHibernate.Hql.Ast.ANTLR +{ + internal class QuerySourceDetector : IVisitationStrategy + { + private readonly IASTNode _tree; + private readonly List<IASTNode> _nodes; + + public QuerySourceDetector(IASTNode tree) + { + _tree = tree; + _nodes = new List<IASTNode>(); + } + + public IList<IASTNode> LocateQuerySources() + { + // Find all the polymorphic query sources + var nodeTraverser = new NodeTraverser(this); + nodeTraverser.TraverseDepthFirst(_tree); + + return _nodes; + } + + public void Visit(IASTNode node) + { + if (node.Type == HqlSqlWalker.FROM) + { + _nodes.AddRange(node.Where(child => child.Type == HqlSqlWalker.RANGE).Select(range => range.GetChild(0))); + } + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-12-02 05:30:33 UTC (rev 4892) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -6,6 +6,7 @@ using Iesi.Collections.Generic; using log4net; using NHibernate.Engine; +using NHibernate.Engine.Query; using NHibernate.Hql.Ast.ANTLR.Exec; using NHibernate.Hql.Ast.ANTLR.Loader; using NHibernate.Hql.Ast.ANTLR.Tree; @@ -23,63 +24,41 @@ { private static readonly ILog log = LogManager.GetLogger(typeof(QueryTranslatorImpl)); - private bool _shallowQuery; + private readonly string _queryIdentifier; + private readonly IASTNode _stageOneAst; + private readonly ISessionFactoryImplementor _factory; + + private bool _shallowQuery; private bool _compiled; - private readonly string _queryIdentifier; - private readonly string _hql; - private IDictionary<string, IFilter> _enabledFilters; - private readonly ISessionFactoryImplementor _factory; + private IDictionary<string, IFilter> _enabledFilters; private QueryLoader _queryLoader; - private IStatementExecutor statementExecutor; - private IStatement sqlAst; + private IStatementExecutor _statementExecutor; + private IStatement _sqlAst; private ParameterTranslationsImpl _paramTranslations; - private IDictionary<string, string> tokenReplacements; - private HqlParseEngine _parser; + private IDictionary<string, string> _tokenReplacements; private HqlSqlGenerator _generator; /// <summary> /// Creates a new AST-based query translator. /// </summary> /// <param name="queryIdentifier">The query-identifier (used in stats collection)</param> - /// <param name="query">The hql query to translate</param> + /// <param name="parsedQuery">The hql query to translate</param> /// <param name="enabledFilters">Currently enabled filters</param> /// <param name="factory">The session factory constructing this translator instance.</param> public QueryTranslatorImpl( string queryIdentifier, - HqlParseEngine parsedQuery, + IASTNode parsedQuery, IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) { _queryIdentifier = queryIdentifier; - _parser = parsedQuery; + _stageOneAst = parsedQuery; _compiled = false; _shallowQuery = false; _enabledFilters = enabledFilters; _factory = factory; } - /// <summary> - /// Creates a new AST-based query translator. - /// </summary> - /// <param name="queryIdentifier">The query-identifier (used in stats collection)</param> - /// <param name="queryExpression">The hql query to translate</param> - /// <param name="enabledFilters">Currently enabled filters</param> - /// <param name="factory">The session factory constructing this translator instance.</param> - public QueryTranslatorImpl( - string queryIdentifier, - IQueryExpression queryExpression, - IDictionary<string, IFilter> enabledFilters, - ISessionFactoryImplementor factory) - { - _queryIdentifier = queryIdentifier; - _hql = queryExpression.ToString(); - _compiled = false; - _shallowQuery = false; - _enabledFilters = enabledFilters; - _factory = factory; - _parser = new HqlParseEngine(queryExpression.Translate(factory), factory); - } - /// <summary> /// Compile a "normal" query. This method may be called multiple /// times. Subsequent invocations are no-ops. @@ -91,11 +70,23 @@ DoCompile( replacements, shallow, null ); } + /// <summary> + /// Compile a filter. This method may be called multiple + /// times. Subsequent invocations are no-ops. + /// </summary> + /// <param name="collectionRole">the role name of the collection used as the basis for the filter.</param> + /// <param name="replacements">Defined query substitutions.</param> + /// <param name="shallow">Does this represent a shallow (scalar or entity-id) select?</param> + public void Compile(string collectionRole, IDictionary<string, string> replacements, bool shallow) + { + DoCompile(replacements, shallow, collectionRole); + } + public IList List(ISessionImplementor session, QueryParameters queryParameters) { // Delegate to the QueryLoader... ErrorIfDML(); - var query = ( QueryNode ) sqlAst; + var query = ( QueryNode ) _sqlAst; bool hasLimit = queryParameters.RowSelection != null && queryParameters.RowSelection.DefinesLimits; bool needsDistincting = ( query.GetSelectClause().IsDistinct || hasLimit ) && ContainsCollectionFetches; @@ -168,14 +159,14 @@ public int ExecuteUpdate(QueryParameters queryParameters, ISessionImplementor session) { ErrorIfSelect(); - return statementExecutor.Execute(queryParameters, session); + return _statementExecutor.Execute(queryParameters, session); } private void ErrorIfSelect() { - if (!sqlAst.NeedsExecutor) + if (!_sqlAst.NeedsExecutor) { - throw new QueryExecutionRequestException("Not supported for select queries:", _hql); + throw new QueryExecutionRequestException("Not supported for select queries:", _queryIdentifier); } } @@ -189,17 +180,44 @@ get { return _queryLoader.ReturnTypes; } } - public string[][] GetColumnNames() + public ParameterMetadata BuildParameterMetadata() + { + var parameterTranslations = GetParameterTranslations(); + + var ordinalDescriptors = new OrdinalParameterDescriptor[parameterTranslations.OrdinalParameterCount]; + + for (var i = 1; i <= ordinalDescriptors.Length; i++) + { + ordinalDescriptors[i - 1] = + new OrdinalParameterDescriptor(i, + parameterTranslations.SupportsOrdinalParameterMetadata + ? parameterTranslations.GetOrdinalParameterExpectedType(i) + : null, parameterTranslations.GetOrdinalParameterSqlLocation(i)); + } + + var namedDescriptorMap = new Dictionary<string, NamedParameterDescriptor>(); + foreach (var name in parameterTranslations.GetNamedParameterNames()) + { + namedDescriptorMap[name] = + new NamedParameterDescriptor(name, parameterTranslations.GetNamedParameterExpectedType(name), + parameterTranslations.GetNamedParameterSqlLocations(name), false);// description.JpaStyle); + + } + + return new ParameterMetadata(ordinalDescriptors, namedDescriptorMap); + } + + public string[][] GetColumnNames() { ErrorIfDML(); - return sqlAst.Walker.SelectClause.ColumnNames; + return _sqlAst.Walker.SelectClause.ColumnNames; } public IParameterTranslations GetParameterTranslations() { if (_paramTranslations == null) { - _paramTranslations = new ParameterTranslationsImpl(sqlAst.Walker.Parameters); + _paramTranslations = new ParameterTranslationsImpl(_sqlAst.Walker.Parameters); } return _paramTranslations; @@ -207,7 +225,7 @@ public ISet<string> QuerySpaces { - get { return sqlAst.Walker.QuerySpaces; } + get { return _sqlAst.Walker.QuerySpaces; } } public string SQLString @@ -217,7 +235,7 @@ public IStatement SqlAST { - get { return sqlAst; } + get { return _sqlAst; } } public IList<IParameterSpecification> CollectedParameterSpecifications @@ -242,7 +260,7 @@ var list = new List<string>(); if (IsManipulationStatement) { - foreach (var sqlStatement in statementExecutor.SqlStatements) + foreach (var sqlStatement in _statementExecutor.SqlStatements) { if (sqlStatement != null) { @@ -260,7 +278,7 @@ public string QueryString { - get { return _hql; } + get { return _queryIdentifier; } } public IDictionary<string, IFilter> EnabledFilters @@ -273,7 +291,7 @@ get { ErrorIfDML(); - return sqlAst.Walker.ReturnTypes; + return _sqlAst.Walker.ReturnTypes; } } @@ -282,7 +300,7 @@ get { ErrorIfDML(); - return sqlAst.Walker.ReturnAliases; + return _sqlAst.Walker.ReturnAliases; } } @@ -291,28 +309,16 @@ get { ErrorIfDML(); - IList<IASTNode> collectionFetches = ((QueryNode)sqlAst).FromClause.GetCollectionFetches(); + IList<IASTNode> collectionFetches = ((QueryNode)_sqlAst).FromClause.GetCollectionFetches(); return collectionFetches != null && collectionFetches.Count > 0; } } public bool IsManipulationStatement { - get { return sqlAst.NeedsExecutor; } + get { return _sqlAst.NeedsExecutor; } } - /// <summary> - /// Compile a filter. This method may be called multiple - /// times. Subsequent invocations are no-ops. - /// </summary> - /// <param name="collectionRole">the role name of the collection used as the basis for the filter.</param> - /// <param name="replacements">Defined query substitutions.</param> - /// <param name="shallow">Does this represent a shallow (scalar or entity-id) select?</param> - public void Compile(string collectionRole, IDictionary<string, string> replacements, bool shallow) - { - DoCompile(replacements, shallow, collectionRole); - } - public bool IsShallowQuery { get { return _shallowQuery; } @@ -337,20 +343,17 @@ } // Remember the parameters for the compilation. - tokenReplacements = replacements ?? new Dictionary<string, string>(1); + _tokenReplacements = replacements ?? new Dictionary<string, string>(1); _shallowQuery = shallow; try { - // PHASE 1 : Parse the HQL into an AST. - HqlParseEngine parser = Parse(true); + // PHASE 1 : Analyze the HQL AST, and produce an SQL AST. + var translator = Analyze(collectionRole); - // PHASE 2 : Analyze the HQL AST, and produce an SQL AST. - var translator = Analyze(parser, collectionRole); + _sqlAst = translator.SqlStatement; - sqlAst = translator.SqlStatement; - // at some point the generate phase needs to be moved out of here, // because a single object-level DML might spawn multiple SQL DML // command executions. @@ -362,24 +365,24 @@ // QueryLoader currently even has a dependency on this at all; does // it need it? Ideally like to see the walker itself given to the delegates directly... - if (sqlAst.NeedsExecutor) + if (_sqlAst.NeedsExecutor) { - statementExecutor = BuildAppropriateStatementExecutor(sqlAst); + _statementExecutor = BuildAppropriateStatementExecutor(_sqlAst); } else { - // PHASE 3 : Generate the SQL. - _generator = new HqlSqlGenerator(sqlAst, parser.Tokens, _factory); + // PHASE 2 : Generate the SQL. + _generator = new HqlSqlGenerator(_sqlAst, _factory); _generator.Generate(); - _queryLoader = new QueryLoader(this, _factory, sqlAst.Walker.SelectClause); + _queryLoader = new QueryLoader(this, _factory, _sqlAst.Walker.SelectClause); } _compiled = true; } catch ( QueryException qe ) { - qe.QueryString = _hql; + qe.QueryString = _queryIdentifier; throw; } catch ( RecognitionException e ) @@ -390,13 +393,13 @@ { log.Info( "converted antlr.RecognitionException", e ); } - throw QuerySyntaxException.Convert( e, _hql ); + throw QuerySyntaxException.Convert(e, _queryIdentifier); } _enabledFilters = null; //only needed during compilation phase... } - private IStatementExecutor BuildAppropriateStatementExecutor(IStatement statement) + private static IStatementExecutor BuildAppropriateStatementExecutor(IStatement statement) { HqlSqlWalker walker = statement.Walker; if (walker.StatementType == HqlSqlWalker.DELETE) @@ -438,30 +441,20 @@ } } - private HqlSqlTranslator Analyze(HqlParseEngine parser, string collectionRole) + private HqlSqlTranslator Analyze(string collectionRole) { - var translator = new HqlSqlTranslator(parser.Ast, parser.Tokens, this, _factory, tokenReplacements, - collectionRole); + var translator = new HqlSqlTranslator(_stageOneAst, this, _factory, _tokenReplacements, collectionRole); + translator.Translate(); return translator; } - private HqlParseEngine Parse(bool isFilter) - { - if (_parser == null) - { - _parser = new HqlParseEngine(_hql, isFilter, _factory); - _parser.Parse(); - } - return _parser; - } - private void ErrorIfDML() { - if (sqlAst.NeedsExecutor) + if (_sqlAst.NeedsExecutor) { - throw new QueryExecutionRequestException("Not supported for DML operations", _hql); + throw new QueryExecutionRequestException("Not supported for DML operations", _queryIdentifier); } } } @@ -473,7 +466,6 @@ private readonly string _hql; private CommonTokenStream _tokens; private readonly bool _filter; - private IASTNode _ast; private readonly ISessionFactoryImplementor _sfi; public HqlParseEngine(string hql, bool filter, ISessionFactoryImplementor sfi) @@ -483,60 +475,38 @@ _sfi = sfi; } - public HqlParseEngine(IASTNode ast, ISessionFactoryImplementor sfi) + public IASTNode Parse() { - _sfi = sfi; - _ast = ast; - } + // Parse the query string into an HQL AST. + var lex = new HqlLexer(new CaseInsensitiveStringStream(_hql)); + _tokens = new CommonTokenStream(lex); - public IASTNode Ast - { - get { return _ast; } - } + var parser = new HqlParser(_tokens) {TreeAdaptor = new ASTTreeAdaptor(), Filter = _filter}; - public CommonTokenStream Tokens - { - get { return _tokens; } - } + if (log.IsDebugEnabled) + { + log.Debug("parse() - HQL: " + _hql); + } - public void Parse() - { - if (_ast == null) - { - // Parse the query string into an HQL AST. - var lex = new HqlLexer(new CaseInsensitiveStringStream(_hql)); - _tokens = new CommonTokenStream(lex); + try + { + var ast = (IASTNode) parser.statement().Tree; - var parser = new HqlParser(_tokens); - parser.TreeAdaptor = new ASTTreeAdaptor(); + var walker = new NodeTraverser(new ConstantConverter(_sfi)); + walker.TraverseDepthFirst(ast); - parser.Filter = _filter; - - if (log.IsDebugEnabled) - { - log.Debug("parse() - HQL: " + _hql); - } - - try - { - _ast = (IASTNode)parser.statement().Tree; - - var walker = new NodeTraverser(new ConstantConverter(_sfi)); - walker.TraverseDepthFirst(_ast); - - //showHqlAst( hqlAst ); - } + return ast; + } finally - { - parser.ParseErrorHandler.ThrowQueryException(); - } - } + { + parser.ParseErrorHandler.ThrowQueryException(); + } } class ConstantConverter : IVisitationStrategy { - private IASTNode dotRoot; - private ISessionFactoryImplementor _sfi; + private IASTNode _dotRoot; + private readonly ISessionFactoryImplementor _sfi; public ConstantConverter(ISessionFactoryImplementor sfi) { @@ -545,31 +515,31 @@ public void Visit(IASTNode node) { - if (dotRoot != null) + if (_dotRoot != null) { // we are already processing a dot-structure - if (ASTUtil.IsSubtreeChild(dotRoot, node)) + if (ASTUtil.IsSubtreeChild(_dotRoot, node)) { // ignore it... return; } // we are now at a new tree level - dotRoot = null; + _dotRoot = null; } - if (dotRoot == null && node.Type == HqlSqlWalker.DOT) + if (_dotRoot == null && node.Type == HqlSqlWalker.DOT) { - dotRoot = node; - HandleDotStructure(dotRoot); + _dotRoot = node; + HandleDotStructure(_dotRoot); } } private void HandleDotStructure(IASTNode dotStructureRoot) { - String expression = ASTUtil.GetPathText(dotStructureRoot); + var expression = ASTUtil.GetPathText(dotStructureRoot); - object constant = ReflectHelper.GetConstantValue(expression, _sfi); + var constant = ReflectHelper.GetConstantValue(expression, _sfi); if (constant != null) { @@ -584,17 +554,15 @@ internal class HqlSqlTranslator { private readonly IASTNode _inputAst; - private readonly CommonTokenStream _tokens; private readonly QueryTranslatorImpl _qti; private readonly ISessionFactoryImplementor _sfi; private readonly IDictionary<string, string> _tokenReplacements; private readonly string _collectionRole; private IStatement _resultAst; - public HqlSqlTranslator(IASTNode ast, CommonTokenStream tokens, QueryTranslatorImpl qti, ISessionFactoryImplementor sfi, IDictionary<string, string> tokenReplacements, string collectionRole) + public HqlSqlTranslator(IASTNode ast, QueryTranslatorImpl qti, ISessionFactoryImplementor sfi, IDictionary<string, string> tokenReplacements, string collectionRole) { _inputAst = ast; - _tokens = tokens; _qti = qti; _sfi = sfi; _tokenReplacements = tokenReplacements; @@ -608,26 +576,25 @@ public IStatement Translate() { - if (_resultAst == null) - { - var nodes = new HqlSqlWalkerTreeNodeStream(_inputAst); - nodes.TokenStream = _tokens; + if (_resultAst == null) + { + var nodes = new HqlSqlWalkerTreeNodeStream(_inputAst); - var hqlSqlWalker = new HqlSqlWalker(_qti, _sfi, nodes, _tokenReplacements, _collectionRole); - hqlSqlWalker.TreeAdaptor = new HqlSqlWalkerTreeAdaptor(hqlSqlWalker); + var hqlSqlWalker = new HqlSqlWalker(_qti, _sfi, nodes, _tokenReplacements, _collectionRole); + hqlSqlWalker.TreeAdaptor = new HqlSqlWalkerTreeAdaptor(hqlSqlWalker); - try - { - // Transform the tree. - _resultAst = (IStatement)hqlSqlWalker.statement().Tree; - } - finally - { - hqlSqlWalker.ParseErrorHandler.ThrowQueryException(); - } - } + try + { + // Transform the tree. + _resultAst = (IStatement) hqlSqlWalker.statement().Tree; + } + finally + { + hqlSqlWalker.ParseErrorHandler.ThrowQueryException(); + } + } - return _resultAst; + return _resultAst; } } @@ -636,15 +603,13 @@ private static readonly ILog log = LogManager.GetLogger(typeof(HqlSqlGenerator)); private readonly IASTNode _ast; - private readonly ITokenStream _tokens; private readonly ISessionFactoryImplementor _sfi; private SqlString _sql; private IList<IParameterSpecification> _parameters; - public HqlSqlGenerator(IStatement ast, ITokenStream tokens, ISessionFactoryImplementor sfi) + public HqlSqlGenerator(IStatement ast, ISessionFactoryImplementor sfi) { _ast = (IASTNode)ast; - _tokens = tokens; _sfi = sfi; } @@ -660,34 +625,30 @@ public SqlString Generate() { - if (_sql == null) - { - var nodes = new CommonTreeNodeStream(_ast); - nodes.TokenStream = _tokens; + if (_sql == null) + { + var gen = new SqlGenerator(_sfi, new CommonTreeNodeStream(_ast)); - var gen = new SqlGenerator(_sfi, nodes); - //gen.TreeAdaptor = new ASTTreeAdaptor(); + try + { + gen.statement(); - try - { - gen.statement(); + _sql = gen.GetSQL(); - _sql = gen.GetSQL(); + if (log.IsDebugEnabled) + { + log.Debug("SQL: " + _sql); + } + } + finally + { + gen.ParseErrorHandler.ThrowQueryException(); + } - if (log.IsDebugEnabled) - { - log.Debug("SQL: " + _sql); - } + _parameters = gen.GetCollectedParameters(); } - finally - { - gen.ParseErrorHandler.ThrowQueryException(); - } - _parameters = gen.GetCollectedParameters(); - } - - return _sql; + return _sql; } } } Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/ClassicQueryTranslatorFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/ClassicQueryTranslatorFactory.cs 2009-12-02 05:30:33 UTC (rev 4892) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/ClassicQueryTranslatorFactory.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -13,8 +13,8 @@ public IQueryTranslator[] CreateQueryTranslators(string queryString, string collectionRole, bool shallow, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) { var translators = QuerySplitter.ConcreteQueries(queryString, factory) - .Select(hql => new QueryTranslator(queryString, hql, filters, factory)) - .ToArray(); + .Select(hql => new QueryTranslator(queryString, hql, filters, factory)) + .ToArray(); foreach (var translator in translators) { Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2009-12-02 05:30:33 UTC (rev 4892) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2009-12-02 15:07:16 UTC (rev 4893) @@ -10,6 +10,7 @@ using log4net; using NHibernate.Engine; +using NHibernate.Engine.Query; using NHibernate.Hql.Util; using NHibernate.Impl; using NHibernate.Loader; @@ -366,7 +367,52 @@ get { return actualReturnTypes; } } - public virtual string[][] ScalarColumnNames + public ParameterMetadata BuildParameterMetadata() + { + return BuildParameterMetadata(GetParameterTranslations(), queryString); + } + + 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) + { + str... [truncated message content] |