ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ptupit...@apache.org
Subject ignite git commit: IGNITE-3591 .NET: Fix self-joins in LINQ
Date Wed, 27 Jul 2016 12:26:06 GMT
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 <ptupitsyn@apache.org>
Authored: Wed Jul 27 15:25:59 2016 +0300
Committer: Pavel Tupitsyn <ptupitsyn@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;
 


Mime
View raw message