|
From: <fab...@us...> - 2011-05-23 12:59:39
|
Revision: 5860
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5860&view=rev
Author: fabiomaulo
Date: 2011-05-23 12:59:32 +0000 (Mon, 23 May 2011)
Log Message:
-----------
LINQ provider using HQL skip/take
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs
trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs
trunk/nhibernate/src/NHibernate/Linq/IntermediateHqlTree.cs
trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFirst.cs
trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessSkip.cs
trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessTake.cs
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2011-05-23 12:28:49 UTC (rev 5859)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeBuilder.cs 2011-05-23 12:59:32 UTC (rev 5860)
@@ -176,6 +176,16 @@
return new HqlOrderBy(_factory);
}
+ public HqlSkip Skip(HqlExpression parameter)
+ {
+ return new HqlSkip(_factory, parameter);
+ }
+
+ public HqlTake Take(HqlExpression parameter)
+ {
+ return new HqlTake(_factory, parameter);
+ }
+
public HqlSelect Select(HqlExpression expression)
{
return new HqlSelect(_factory, expression);
Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2011-05-23 12:28:49 UTC (rev 5859)
+++ trunk/nhibernate/src/NHibernate/Hql/Ast/HqlTreeNode.cs 2011-05-23 12:59:32 UTC (rev 5860)
@@ -363,6 +363,18 @@
}
}
+ public class HqlSkip : HqlStatement
+ {
+ public HqlSkip(IASTFactory factory, HqlExpression parameter)
+ : base(HqlSqlWalker.SKIP, "skip", factory, parameter) { }
+ }
+
+ public class HqlTake : HqlStatement
+ {
+ public HqlTake(IASTFactory factory, HqlExpression parameter)
+ : base(HqlSqlWalker.TAKE, "take", factory, parameter) {}
+ }
+
public class HqlConstant : HqlExpression
{
public HqlConstant(IASTFactory factory, int type, string value)
Modified: trunk/nhibernate/src/NHibernate/Linq/IntermediateHqlTree.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Linq/IntermediateHqlTree.cs 2011-05-23 12:28:49 UTC (rev 5859)
+++ trunk/nhibernate/src/NHibernate/Linq/IntermediateHqlTree.cs 2011-05-23 12:59:32 UTC (rev 5860)
@@ -11,26 +11,45 @@
{
public class IntermediateHqlTree
{
- private readonly bool _root;
+ /* NOTE:
+ * Because common understanding of our users, we are flatting the behavior of Skip and Take methods.
+ * In RAM a query like primeNumbers.Skip(2).Take(6).Where(x=> x > 10) has a completely different results than primeNumbers.Where(x=> x > 10).Skip(2).Take(6) that has
+ * different results than primeNumbers.Take(6).Where(x=> x > 10).Skip(2) and so on.
+ * We are flatting/override even the double-usage of Skip and Take in the same query as: primeNumbers.Skip(2).Where(x=> x > 10).Take(6).Skip(3)
+ * We ***shouldn't*** change the behavior of the query just because we are translating it in SQL.
+ */
+ private readonly bool isRoot;
private readonly List<Action<IQuery, IDictionary<string, Tuple<object, IType>>>> _additionalCriteria = new List<Action<IQuery, IDictionary<string, Tuple<object, IType>>>>();
private readonly List<LambdaExpression> _listTransformers = new List<LambdaExpression>();
private readonly List<LambdaExpression> _itemTransformers = new List<LambdaExpression>();
private readonly List<LambdaExpression> _postExecuteTransformers = new List<LambdaExpression>();
private bool _hasDistinctRootOperator;
+ private HqlExpression skipCount;
+ private HqlExpression takeCount;
- public HqlTreeNode Root { get; private set; }
- public HqlTreeBuilder TreeBuilder { get; private set; }
+ private HqlTreeNode root;
+ public HqlTreeNode Root
+ {
+ get
+ {
+ ExecuteAddSkipClause(skipCount);
+ ExecuteAddTakeClause(takeCount);
+ return root;
+ }
+ }
+ public HqlTreeBuilder TreeBuilder { get; private set; }
+
public IntermediateHqlTree(bool root)
{
- _root = root;
+ isRoot = root;
TreeBuilder = new HqlTreeBuilder();
- Root = TreeBuilder.Query(TreeBuilder.SelectFrom(TreeBuilder.From()));
+ this.root = TreeBuilder.Query(TreeBuilder.SelectFrom(TreeBuilder.From()));
}
public ExpressionToHqlTranslationResults GetTranslation()
{
- if (_root)
+ if (isRoot)
{
DetectOuterExists();
}
@@ -62,41 +81,86 @@
public void AddFromClause(HqlTreeNode from)
{
- Root.NodesPreOrder.Where(n => n is HqlFrom).First().AddChild(from);
+ root.NodesPreOrder.Where(n => n is HqlFrom).First().AddChild(from);
}
public void AddSelectClause(HqlTreeNode select)
{
- Root.NodesPreOrder.Where(n => n is HqlSelectFrom).First().AddChild(select);
+ root.NodesPreOrder.Where(n => n is HqlSelectFrom).First().AddChild(select);
}
public void AddGroupByClause(HqlGroupBy groupBy)
{
- Root.As<HqlQuery>().AddChild(groupBy);
+ root.As<HqlQuery>().AddChild(groupBy);
}
public void AddOrderByClause(HqlExpression orderBy, HqlDirectionStatement direction)
{
- var orderByRoot = Root.NodesPreOrder.Where(n => n is HqlOrderBy).FirstOrDefault();
+ var orderByRoot = root.NodesPreOrder.Where(n => n is HqlOrderBy).FirstOrDefault();
if (orderByRoot == null)
{
orderByRoot = TreeBuilder.OrderBy();
- Root.As<HqlQuery>().AddChild(orderByRoot);
+ root.As<HqlQuery>().AddChild(orderByRoot);
}
orderByRoot.AddChild(orderBy);
orderByRoot.AddChild(direction);
}
- public void AddWhereClause(HqlBooleanExpression where)
+ public void AddSkipClause(HqlExpression toSkip)
+ {
+ skipCount = toSkip;
+ }
+
+ public void AddTakeClause(HqlExpression toTake)
+ {
+ takeCount = toTake;
+ }
+
+ private void ExecuteAddTakeClause(HqlExpression toTake)
+ {
+ if(toTake == null)
+ {
+ return;
+ }
+
+ HqlQuery hqlQuery = root.NodesPreOrder.OfType<HqlQuery>().First();
+ HqlTreeNode takeRoot = hqlQuery.Children.FirstOrDefault(n => n is HqlTake);
+
+ // were present we ignore the new value
+ if (takeRoot == null)
+ {
+ //We should check the value instead delegate the behavior to the result SQL-> MSDN: If count is less than or equal to zero, source is not enumerated and an empty IEnumerable<T> is returned.
+ takeRoot = TreeBuilder.Take(toTake);
+ hqlQuery.AddChild(takeRoot);
+ }
+ }
+
+ private void ExecuteAddSkipClause(HqlExpression toSkip)
+ {
+ if (toSkip == null)
+ {
+ return;
+ }
+ // We should check the value instead delegate the behavior to the result SQL-> MSDN: If count is less than or equal to zero, all elements of source are yielded.
+ HqlQuery hqlQuery = root.NodesPreOrder.OfType<HqlQuery>().First();
+ HqlTreeNode skipRoot = hqlQuery.Children.FirstOrDefault(n => n is HqlSkip);
+ if (skipRoot == null)
+ {
+ skipRoot = TreeBuilder.Skip(toSkip);
+ hqlQuery.AddChild(skipRoot);
+ }
+ }
+
+ public void AddWhereClause(HqlBooleanExpression where)
{
- var currentWhere = Root.NodesPreOrder.Where(n => n is HqlWhere).FirstOrDefault();
+ var currentWhere = root.NodesPreOrder.Where(n => n is HqlWhere).FirstOrDefault();
if (currentWhere == null)
{
currentWhere = TreeBuilder.Where(where);
- Root.As<HqlQuery>().AddChild(currentWhere);
+ root.As<HqlQuery>().AddChild(currentWhere);
}
else
{
@@ -109,16 +173,15 @@
private void DetectOuterExists()
{
- if (Root is HqlExists)
- {
- Root = Root.Children.First();
+ if (root is HqlExists)
+ {
+ AddTakeClause(TreeBuilder.Constant(1));
+ root = Root.Children.First();
- _additionalCriteria.Add((q, p) => q.SetMaxResults(1));
+ Expression<Func<IEnumerable<object>, bool>> x = l => l.Any();
- Expression<Func<IEnumerable<object>, bool>> x = l => l.Any();
-
- _listTransformers.Add(x);
- }
+ _listTransformers.Add(x);
+ }
}
@@ -139,7 +202,7 @@
public void SetRoot(HqlTreeNode newRoot)
{
- Root = newRoot;
+ root = newRoot;
}
}
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFirst.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFirst.cs 2011-05-23 12:28:49 UTC (rev 5859)
+++ trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFirst.cs 2011-05-23 12:59:32 UTC (rev 5860)
@@ -13,7 +13,7 @@
AddClientSideEval(firstMethod, queryModelVisitor, tree);
- tree.AddAdditionalCriteria((q, p) => q.SetMaxResults(1));
+ tree.AddTakeClause(tree.TreeBuilder.Constant(1));
}
}
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessSkip.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessSkip.cs 2011-05-23 12:28:49 UTC (rev 5859)
+++ trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessSkip.cs 2011-05-23 12:59:32 UTC (rev 5860)
@@ -1,22 +1,29 @@
using System.Linq.Expressions;
+using NHibernate.Engine.Query;
using Remotion.Linq.Clauses.ResultOperators;
namespace NHibernate.Linq.Visitors.ResultOperatorProcessors
{
- public class ProcessSkip : IResultOperatorProcessor<SkipResultOperator>
- {
- public void Process(SkipResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
- {
- NamedParameter parameterName;
+ public class ProcessSkip : IResultOperatorProcessor<SkipResultOperator>
+ {
+ #region IResultOperatorProcessor<SkipResultOperator> Members
- if (queryModelVisitor.VisitorParameters.ConstantToParameterMap.TryGetValue(resultOperator.Count as ConstantExpression, out parameterName))
- {
- tree.AddAdditionalCriteria((q, p) => q.SetFirstResult((int)p[parameterName.Name].First));
- }
- else
- {
- tree.AddAdditionalCriteria((q, p) => q.SetFirstResult(resultOperator.GetConstantCount()));
- }
- }
- }
+ public void Process(SkipResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
+ {
+ VisitorParameters parameters = queryModelVisitor.VisitorParameters;
+ NamedParameter namedParameter;
+
+ if (parameters.ConstantToParameterMap.TryGetValue(resultOperator.Count as ConstantExpression, out namedParameter))
+ {
+ parameters.RequiredHqlParameters.Add(new NamedParameterDescriptor(namedParameter.Name, null, new[] {parameters.RequiredHqlParameters.Count + 1}, false));
+ tree.AddSkipClause(tree.TreeBuilder.Parameter(namedParameter.Name));
+ }
+ else
+ {
+ tree.AddSkipClause(tree.TreeBuilder.Constant(resultOperator.GetConstantCount()));
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessTake.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessTake.cs 2011-05-23 12:28:49 UTC (rev 5859)
+++ trunk/nhibernate/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessTake.cs 2011-05-23 12:59:32 UTC (rev 5860)
@@ -1,24 +1,29 @@
using System.Linq.Expressions;
+using NHibernate.Engine.Query;
using Remotion.Linq.Clauses.ResultOperators;
namespace NHibernate.Linq.Visitors.ResultOperatorProcessors
{
- public class ProcessTake : IResultOperatorProcessor<TakeResultOperator>
- {
- public void Process(TakeResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
- {
- NamedParameter parameterName;
+ public class ProcessTake : IResultOperatorProcessor<TakeResultOperator>
+ {
+ #region IResultOperatorProcessor<TakeResultOperator> Members
- // TODO - very similar to ProcessSkip, plus want to investigate the scenario in the "else"
- // clause to see if it is valid
- if (queryModelVisitor.VisitorParameters.ConstantToParameterMap.TryGetValue(resultOperator.Count as ConstantExpression, out parameterName))
- {
- tree.AddAdditionalCriteria((q, p) => q.SetMaxResults((int)p[parameterName.Name].First));
- }
- else
- {
- tree.AddAdditionalCriteria((q, p) => q.SetMaxResults(resultOperator.GetConstantCount()));
- }
- }
- }
+ public void Process(TakeResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
+ {
+ VisitorParameters parameters = queryModelVisitor.VisitorParameters;
+ NamedParameter namedParameter;
+
+ if (parameters.ConstantToParameterMap.TryGetValue(resultOperator.Count as ConstantExpression, out namedParameter))
+ {
+ parameters.RequiredHqlParameters.Add(new NamedParameterDescriptor(namedParameter.Name, null, new[] {parameters.RequiredHqlParameters.Count + 1}, false));
+ tree.AddTakeClause(tree.TreeBuilder.Parameter(namedParameter.Name));
+ }
+ else
+ {
+ tree.AddTakeClause(tree.TreeBuilder.Constant(resultOperator.GetConstantCount()));
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|