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 2021/02/02 09:48:35 UTC
[ignite] branch master updated: IGNITE-14064 .NET: Fix SQL table
name for generic query types
This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 8ab3211 IGNITE-14064 .NET: Fix SQL table name for generic query types
8ab3211 is described below
commit 8ab32115ab98e1f814933fc6de2df729c1a356a6
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Tue Feb 2 12:48:13 2021 +0300
IGNITE-14064 .NET: Fix SQL table name for generic query types
* Fix `BinaryNameMapper.simpleName` to strip namespaces from generic types
* Fix `QueryUtils.typeName` to strip generic part
---
.../ignite/binary/BinaryBasicNameMapper.java | 24 ++++
.../internal/processors/query/QueryUtils.java | 5 +
.../binary/BinaryBasicNameMapperSelfTest.java | 21 +++
.../Query/CacheQueriesCodeConfigurationTest.cs | 17 +--
.../Cache/Query/Linq/CacheLinqTest.Misc.cs | 148 +++++++++++++++++++++
5 files changed, 203 insertions(+), 12 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryBasicNameMapper.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryBasicNameMapper.java
index 697108f..cf99e95 100644
--- a/modules/core/src/main/java/org/apache/ignite/binary/BinaryBasicNameMapper.java
+++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryBasicNameMapper.java
@@ -87,6 +87,8 @@ public class BinaryBasicNameMapper implements BinaryNameMapper {
private static String simpleName(String clsName) {
assert clsName != null;
+ clsName = simplifyDotNetGenerics(clsName);
+
int idx = clsName.lastIndexOf('$');
if (idx == clsName.length() - 1)
@@ -119,6 +121,28 @@ public class BinaryBasicNameMapper implements BinaryNameMapper {
return idx >= 0 ? clsName.substring(idx + 1) : clsName;
}
+ /**
+ * Converts .NET generic type arguments to a simple form (without namespaces and outer classes classes).
+ *
+ * @param clsName Class name.
+ * @return Simplified class name.
+ */
+ private static String simplifyDotNetGenerics(String clsName) {
+ // .NET generic part starts with [[ (not valid for Java class name). Clean up every generic part recursively.
+ // Example: Foo.Bar`1[[Baz.Qux`2[[System.String],[System.Int32]]]]
+ int genericIdx = clsName.indexOf("[[");
+
+ if (genericIdx > 0)
+ clsName = clsName.substring(0, genericIdx + 2) + simpleName(clsName.substring(genericIdx + 2));
+
+ genericIdx = clsName.indexOf("],[", genericIdx);
+
+ if (genericIdx > 0)
+ clsName = clsName.substring(0, genericIdx + 3) + simpleName(clsName.substring(genericIdx + 3));
+
+ return clsName;
+ }
+
/** {@inheritDoc} */
@Override public boolean equals(Object o) {
if (this == o)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
index c561a5e..bff1ae2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
@@ -1115,6 +1115,11 @@ public class QueryUtils {
* @return Type name.
*/
public static String typeName(String clsName) {
+ int genericStart = clsName.indexOf('`'); // .NET generic, not valid for Java class name.
+
+ if (genericStart >= 0)
+ clsName = clsName.substring(0, genericStart);
+
int pkgEnd = clsName.lastIndexOf('.');
if (pkgEnd >= 0 && pkgEnd < clsName.length() - 1)
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryBasicNameMapperSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryBasicNameMapperSelfTest.java
index cd4cff1..7237cca 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryBasicNameMapperSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryBasicNameMapperSelfTest.java
@@ -42,6 +42,27 @@ public class BinaryBasicNameMapperSelfTest extends GridCommonAbstractTest {
* @throws Exception If failed.
*/
@Test
+ public void testSimpleNameDotNet() throws Exception {
+ BinaryBasicNameMapper mapper = new BinaryBasicNameMapper(true);
+
+ assertEquals("Baz", mapper.typeName("Foo.Bar.Baz"));
+
+ assertEquals("Bar`1[[Qux]]", mapper.typeName("Foo.Bar`1[[Baz.Qux]]"));
+
+ assertEquals("List`1[[Int32[]]]",
+ mapper.typeName("System.Collections.Generic.List`1[[System.Int32[]]]"));
+
+ assertEquals("Bar`1[[Qux`2[[String],[Int32]]]]",
+ mapper.typeName("Foo.Bar`1[[Baz.Qux`2[[System.String],[System.Int32]]]]"));
+
+ assertEquals("Bar`1[[Qux`2[[C],[Int32]]]]",
+ mapper.typeName("Foo.Outer+Bar`1[[Baz.Outer2+Qux`2[[A.B+C],[System.Int32]]]]"));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
public void testFullName() throws Exception {
BinaryBasicNameMapper mapper = new BinaryBasicNameMapper(false);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesCodeConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesCodeConfigurationTest.cs
index 261071a..a80526d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesCodeConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesCodeConfigurationTest.cs
@@ -270,12 +270,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
var queryEntity = cache.GetConfiguration().QueryEntities.Single();
Assert.AreEqual(expectedTypeName, queryEntity.ValueTypeName);
- var tableName = cache.Query(new SqlFieldsQuery(
- "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=?", cache.Name))
- .Single().Single(); // The table name is weird, see IGNITE-14064.
-
- var sqlRes = cache.Query(new SqlFieldsQuery(string.Format("SELECT Foo, Bar from \"{0}\"", tableName)))
- .Single();
+ var sqlRes = cache.Query(new SqlFieldsQuery("SELECT Foo, Bar from GENERICTEST2")).Single();
Assert.AreEqual(key.Foo, sqlRes[0]);
Assert.AreEqual(value.Bar, sqlRes[1]);
@@ -298,14 +293,12 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
var value = new GenericTest<GenericTest2<string>>(new GenericTest2<string>("foobar"));
cache[1] = value;
- var tableName = cache.Query(new SqlFieldsQuery(
- "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=?", cache.Name))
- .Single().Single(); // The table name is weird, see IGNITE-14064.
-
- var sqlRes = cache.Query(new SqlFieldsQuery(string.Format("SELECT Bar from \"{0}\"", tableName)))
- .Single().Single();
+ var sqlRes = cache.Query(new SqlFieldsQuery("SELECT Bar from GENERICTEST")).Single().Single();
Assert.AreEqual(value.Foo.Bar, sqlRes);
+
+ var valTypeName = value.GetType().FullName;
+ Assert.IsNotNull(valTypeName);
}
/// <summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Misc.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Misc.cs
index 15bcfa6..bc67ea7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Misc.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Misc.cs
@@ -380,5 +380,153 @@ namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
.Select(x => selector(x))
.FirstOrDefault());
}
+
+ /// <summary>
+ /// Tests queries when cache key/val types are generic.
+ /// </summary>
+ [Test]
+ public void TestGenericCacheTypes()
+ {
+ var cfg = new CacheConfiguration(TestUtils.TestName)
+ {
+ QueryEntities = new[] {new QueryEntity(typeof(GenericTest<int>), typeof(GenericTest2<string>))}
+ };
+
+ var cache = Ignition.GetIgnite().GetOrCreateCache<GenericTest<int>, GenericTest2<string>>(cfg);
+ var key = new GenericTest<int>(1);
+ var value = new GenericTest2<string>("foo");
+ cache[key] = value;
+
+ var query = cache.AsCacheQueryable()
+ .Where(x => x.Key.Foo == key.Foo && x.Value.Bar == value.Bar)
+ .Select(x => x.Value.Bar);
+
+ var sql = query.ToCacheQueryable().GetFieldsQuery().Sql;
+ var res = query.ToList();
+
+ Assert.AreEqual(1, res.Count);
+ Assert.AreEqual(value.Bar, res[0]);
+
+ var expectedSql = string.Format("select _T0.BAR from \"{0}\".GENERICTEST2 as", cache.Name);
+ StringAssert.StartsWith(expectedSql, sql);
+ }
+
+ /// <summary>
+ /// Tests queries when cache key/val types are generic.
+ /// </summary>
+ [Test]
+ public void TestNestedGenericCacheTypes()
+ {
+ var cfg = new CacheConfiguration(TestUtils.TestName)
+ {
+ QueryEntities = new[] {new QueryEntity(typeof(int), typeof(GenericTest<GenericTest2<string>>))}
+ };
+
+ var cache = Ignition.GetIgnite().GetOrCreateCache<int, GenericTest<GenericTest2<string>>>(cfg);
+ var key = 1;
+ var value = new GenericTest<GenericTest2<string>>(new GenericTest2<string>("foo"));
+ cache[key] = value;
+
+ var query = cache.AsCacheQueryable()
+ .Where(x => x.Value.Foo.Bar == value.Foo.Bar)
+ .Select(x => x.Value.Foo);
+
+ var sql = query.ToCacheQueryable().GetFieldsQuery().Sql;
+ var res = query.ToList();
+
+ Assert.AreEqual(1, res.Count);
+ Assert.AreEqual(value.Foo.Bar, res[0].Bar);
+
+ var expectedSql = string.Format("select _T0.FOO from \"{0}\".GENERICTEST as", cache.Name);
+ StringAssert.StartsWith(expectedSql, sql);
+ }
+
+ /// <summary>
+ /// Tests queries when cache val type has two generic type arguments.
+ /// </summary>
+ [Test]
+ public void TestTwoGenericArgumentsCacheType()
+ {
+ var cfg = new CacheConfiguration(TestUtils.TestName)
+ {
+ QueryEntities = new[] {new QueryEntity(typeof(int), typeof(GenericTest3<int, string, bool>))}
+ };
+
+ var cache = Ignition.GetIgnite().GetOrCreateCache<int, GenericTest3<int, string, bool>>(cfg);
+ var key = 1;
+ var value = new GenericTest3<int, string, bool>(2, "3", true);
+ cache[key] = value;
+
+ var query = cache.AsCacheQueryable()
+ .Where(x => x.Value.Baz == value.Baz && x.Value.Qux == value.Qux && x.Value.Quz)
+ .Select(x => x.Value.Baz);
+
+ var sql = query.ToCacheQueryable().GetFieldsQuery().Sql;
+ var res = query.ToList();
+
+ Assert.AreEqual(1, res.Count);
+ Assert.AreEqual(value.Baz, res[0]);
+
+ var expectedSql = string.Format("select _T0.BAZ from \"{0}\".GENERICTEST3 as", cache.Name);
+ StringAssert.StartsWith(expectedSql, sql);
+ }
+
+ /// <summary>
+ /// Generic query type.
+ /// </summary>
+ private class GenericTest<T>
+ {
+ /** */
+ public GenericTest(T foo)
+ {
+ Foo = foo;
+ }
+
+ /** */
+ [QuerySqlField]
+ public T Foo { get; set; }
+ }
+
+ /// <summary>
+ /// Generic query type.
+ /// </summary>
+ private class GenericTest2<T>
+ {
+ /** */
+ public GenericTest2(T bar)
+ {
+ Bar = bar;
+ }
+
+ /** */
+ [QuerySqlField]
+ public T Bar { get; set; }
+ }
+
+ /// <summary>
+ /// Generic query type with two generic arguments.
+ /// </summary>
+ private class GenericTest3<T, T2, T3>
+ {
+ /** */
+ public GenericTest3(T baz, T2 qux, T3 quz)
+ {
+ Baz = baz;
+ Qux = qux;
+ Quz = quz;
+ }
+
+ /** */
+ [QuerySqlField]
+ public T Baz { get; set; }
+
+ /** */
+ [QuerySqlField]
+ public T2 Qux { get; set; }
+
+ /** */
+ [QuerySqlField]
+ public T3 Quz { get; set; }
+ }
}
}