You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2016/07/27 12:26:06 UTC
ignite git commit: IGNITE-3591 .NET: Fix self-joins in LINQ
Repository: ignite
Updated Branches:
refs/heads/ignite-1.7 2f36ae559 -> f96b568e6
IGNITE-3591 .NET: Fix self-joins in LINQ
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/f96b568e
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/f96b568e
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/f96b568e
Branch: refs/heads/ignite-1.7
Commit: f96b568e662758a915309fe631c5bec4fd0ccdfe
Parents: 2f36ae5
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Wed Jul 27 15:25:59 2016 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Wed Jul 27 15:25:59 2016 +0300
----------------------------------------------------------------------
.../Cache/Query/CacheLinqTest.cs | 18 +++++
.../Apache.Ignite.Linq/Impl/AliasDictionary.cs | 74 ++++++++++++++++----
.../Impl/CacheQueryExpressionVisitor.cs | 4 +-
.../Impl/CacheQueryModelVisitor.cs | 6 +-
.../Apache.Ignite.Linq/Impl/ExpressionWalker.cs | 34 ++++-----
5 files changed, 96 insertions(+), 40 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/f96b568e/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
index 679f03a..70c5fb5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
@@ -537,6 +537,24 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
}
/// <summary>
+ /// Tests the join of a table to itself.
+ /// </summary>
+ [Test]
+ public void TestSelfJoin()
+ {
+ // Different queryables
+ var p1 = GetPersonCache().AsCacheQueryable();
+ var p2 = GetPersonCache().AsCacheQueryable();
+
+ var qry = p1.Join(p2, x => x.Value.Age, x => x.Key, (x, y) => x.Key);
+ Assert.AreEqual(PersonCount, qry.ToArray().Distinct().Count());
+
+ // Same queryables
+ var qry2 = p1.Join(p1, x => x.Value.Age, x => x.Key, (x, y) => x.Key);
+ Assert.AreEqual(PersonCount, qry2.ToArray().Distinct().Count());
+ }
+
+ /// <summary>
/// Tests the group by.
/// </summary>
[Test]
http://git-wip-us.apache.org/repos/asf/ignite/blob/f96b568e/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/AliasDictionary.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/AliasDictionary.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/AliasDictionary.cs
index 10a414c..5fd890d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/AliasDictionary.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/AliasDictionary.cs
@@ -17,10 +17,13 @@
namespace Apache.Ignite.Linq.Impl
{
+ using System;
using System.Collections.Generic;
using System.Diagnostics;
+ using System.Linq.Expressions;
using System.Text;
using Remotion.Linq.Clauses;
+ using Remotion.Linq.Clauses.Expressions;
/// <summary>
/// Alias dictionary.
@@ -31,10 +34,10 @@ namespace Apache.Ignite.Linq.Impl
private int _aliasIndex;
/** */
- private Dictionary<string, string> _aliases = new Dictionary<string, string>();
+ private Dictionary<IQuerySource, string> _aliases = new Dictionary<IQuerySource, string>();
/** */
- private readonly Stack<Dictionary<string, string>> _stack = new Stack<Dictionary<string, string>>();
+ private readonly Stack<Dictionary<IQuerySource, string>> _stack = new Stack<Dictionary<IQuerySource, string>>();
/// <summary>
/// Pushes current aliases to stack.
@@ -43,7 +46,7 @@ namespace Apache.Ignite.Linq.Impl
{
_stack.Push(_aliases);
- _aliases = new Dictionary<string, string>();
+ _aliases = new Dictionary<IQuerySource, string>();
}
/// <summary>
@@ -57,27 +60,34 @@ namespace Apache.Ignite.Linq.Impl
/// <summary>
/// Gets the table alias.
/// </summary>
- public string GetTableAlias(ICacheQueryableInternal queryable)
+ public string GetTableAlias(Expression expression)
{
- Debug.Assert(queryable != null);
+ Debug.Assert(expression != null);
- return GetTableAlias(ExpressionWalker.GetTableNameWithSchema(queryable));
+ return GetTableAlias(GetQuerySource(expression));
}
- /// <summary>
- /// Gets the table alias.
- /// </summary>
- public string GetTableAlias(string fullName)
+ public string GetTableAlias(IFromClause fromClause)
{
- Debug.Assert(!string.IsNullOrEmpty(fullName));
+ return GetTableAlias(GetQuerySource(fromClause.FromExpression) ?? fromClause);
+ }
+
+ public string GetTableAlias(JoinClause joinClause)
+ {
+ return GetTableAlias(GetQuerySource(joinClause.InnerSequence) ?? joinClause);
+ }
+
+ private string GetTableAlias(IQuerySource querySource)
+ {
+ Debug.Assert(querySource != null);
string alias;
- if (!_aliases.TryGetValue(fullName, out alias))
+ if (!_aliases.TryGetValue(querySource, out alias))
{
alias = "_T" + _aliasIndex++;
- _aliases[fullName] = alias;
+ _aliases[querySource] = alias;
}
return alias;
@@ -94,9 +104,45 @@ namespace Apache.Ignite.Linq.Impl
var queryable = ExpressionWalker.GetCacheQueryable(clause);
var tableName = ExpressionWalker.GetTableNameWithSchema(queryable);
- builder.AppendFormat("{0} as {1}", tableName, GetTableAlias(tableName));
+ builder.AppendFormat("{0} as {1}", tableName, GetTableAlias(clause));
return builder;
}
+
+ /// <summary>
+ /// Gets the query source.
+ /// </summary>
+ private static IQuerySource GetQuerySource(Expression expression)
+ {
+ var subQueryExp = expression as SubQueryExpression;
+
+ if (subQueryExp != null)
+ return GetQuerySource(subQueryExp.QueryModel.MainFromClause.FromExpression)
+ ?? subQueryExp.QueryModel.MainFromClause;
+
+ var srcRefExp = expression as QuerySourceReferenceExpression;
+
+ if (srcRefExp != null)
+ {
+ var fromSource = srcRefExp.ReferencedQuerySource as IFromClause;
+
+ if (fromSource != null)
+ return GetQuerySource(fromSource.FromExpression) ?? fromSource;
+
+ var joinSource = srcRefExp.ReferencedQuerySource as JoinClause;
+
+ if (joinSource != null)
+ return GetQuerySource(joinSource.InnerSequence) ?? joinSource;
+
+ throw new NotSupportedException("Unexpected query source: " + srcRefExp.ReferencedQuerySource);
+ }
+
+ var memberExpr = expression as MemberExpression;
+
+ if (memberExpr != null)
+ return GetQuerySource(memberExpr.Expression);
+
+ return null;
+ }
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f96b568e/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs
index eaca07a..2362137 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs
@@ -248,7 +248,7 @@ namespace Apache.Ignite.Linq.Impl
// In other cases we need both parts of cache entry
var format = _useStar ? "{0}.*" : "{0}._key, {0}._val";
- var tableName = Aliases.GetTableAlias(ExpressionWalker.GetCacheQueryable(expression));
+ var tableName = Aliases.GetTableAlias(expression);
ResultBuilder.AppendFormat(format, tableName);
@@ -283,7 +283,7 @@ namespace Apache.Ignite.Linq.Impl
{
var fieldName = GetFieldName(expression, queryable);
- ResultBuilder.AppendFormat("{0}.{1}", Aliases.GetTableAlias(queryable), fieldName);
+ ResultBuilder.AppendFormat("{0}.{1}", Aliases.GetTableAlias(expression), fieldName);
}
else
AppendParameter(RegisterEvaluatedParameter(expression));
http://git-wip-us.apache.org/repos/asf/ignite/blob/f96b568e/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs
index 1888414..a8c4c67 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs
@@ -418,8 +418,7 @@ namespace Apache.Ignite.Linq.Impl
VisitQueryModel(subQuery.QueryModel, true);
- var queryable = ExpressionWalker.GetCacheQueryable(subQuery.QueryModel.MainFromClause);
- var alias = _aliases.GetTableAlias(queryable);
+ var alias = _aliases.GetTableAlias(subQuery.QueryModel.MainFromClause);
_builder.AppendFormat(") as {0} on (", alias);
}
else
@@ -437,7 +436,8 @@ namespace Apache.Ignite.Linq.Impl
var queryable = ExpressionWalker.GetCacheQueryable(joinClause);
var tableName = ExpressionWalker.GetTableNameWithSchema(queryable);
- _builder.AppendFormat("inner join {0} as {1} on (", tableName, _aliases.GetTableAlias(tableName));
+ var alias = _aliases.GetTableAlias(joinClause);
+ _builder.AppendFormat("inner join {0} as {1} on (", tableName, alias);
}
BuildJoinCondition(joinClause.InnerKeySelector, joinClause.OuterKeySelector);
http://git-wip-us.apache.org/repos/asf/ignite/blob/f96b568e/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs
index 96371cc..bd57e3f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs
@@ -38,26 +38,6 @@ namespace Apache.Ignite.Linq.Impl
/// <summary>
/// Gets the cache queryable.
/// </summary>
- public static ICacheQueryableInternal GetCacheQueryable(QuerySourceReferenceExpression expression)
- {
- Debug.Assert(expression != null);
-
- var fromSource = expression.ReferencedQuerySource as IFromClause;
-
- if (fromSource != null)
- return GetCacheQueryable(fromSource);
-
- var joinSource = expression.ReferencedQuerySource as JoinClause;
-
- if (joinSource != null)
- return GetCacheQueryable(joinSource);
-
- throw new NotSupportedException("Unexpected query source: " + expression.ReferencedQuerySource);
- }
-
- /// <summary>
- /// Gets the cache queryable.
- /// </summary>
public static ICacheQueryableInternal GetCacheQueryable(IFromClause fromClause)
{
return GetCacheQueryable(fromClause.FromExpression);
@@ -84,7 +64,19 @@ namespace Apache.Ignite.Linq.Impl
var srcRefExp = expression as QuerySourceReferenceExpression;
if (srcRefExp != null)
- return GetCacheQueryable(srcRefExp);
+ {
+ var fromSource = srcRefExp.ReferencedQuerySource as IFromClause;
+
+ if (fromSource != null)
+ return GetCacheQueryable(fromSource);
+
+ var joinSource = srcRefExp.ReferencedQuerySource as JoinClause;
+
+ if (joinSource != null)
+ return GetCacheQueryable(joinSource);
+
+ throw new NotSupportedException("Unexpected query source: " + srcRefExp.ReferencedQuerySource);
+ }
var memberExpr = expression as MemberExpression;