|
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] |