diff --git a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeExpressionFragmentTranslator.cs b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeExpressionFragmentTranslator.cs
index ab22a1a40..d43d8a1d5 100644
--- a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeExpressionFragmentTranslator.cs
+++ b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeExpressionFragmentTranslator.cs
@@ -2,7 +2,7 @@
// The PostgreSQL License
//
-// Copyright (C) 2016 The Npgsql Development Team
+// Copyright (C) 2018 The Npgsql Development Team
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
@@ -49,6 +49,7 @@ public NpgsqlCompositeExpressionFragmentTranslator(
AddTranslators(ExpressionFragmentTranslators);
}
+ // ReSharper disable once MemberCanBeProtected.Global
///
/// Adds additional dispatches to the translators list.
///
diff --git a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeMemberTranslator.cs b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeMemberTranslator.cs
index a95d5460a..2b272323f 100644
--- a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeMemberTranslator.cs
+++ b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeMemberTranslator.cs
@@ -2,7 +2,7 @@
// The PostgreSQL License
//
-// Copyright (C) 2016 The Npgsql Development Team
+// Copyright (C) 2018 The Npgsql Development Team
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
diff --git a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeMethodCallTranslator.cs b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeMethodCallTranslator.cs
index ee123c573..402487960 100644
--- a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeMethodCallTranslator.cs
+++ b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlCompositeMethodCallTranslator.cs
@@ -2,7 +2,7 @@
// The PostgreSQL License
//
-// Copyright (C) 2016 The Npgsql Development Team
+// Copyright (C) 2018 The Npgsql Development Team
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
@@ -68,7 +68,7 @@ public NpgsqlCompositeMethodCallTranslator(
[NotNull] INpgsqlOptions npgsqlOptions)
: base(dependencies)
{
- var instanceTranslators = new IMethodCallTranslator[]
+ var versionDependentTranslators = new IMethodCallTranslator[]
{
new NpgsqlDateAddTranslator(npgsqlOptions.PostgresVersion),
new NpgsqlMathTranslator(npgsqlOptions.PostgresVersion)
@@ -78,7 +78,7 @@ public NpgsqlCompositeMethodCallTranslator(
AddTranslators(MethodCallTranslators);
// ReSharper disable once DoNotCallOverridableMethodsInConstructor
- AddTranslators(instanceTranslators);
+ AddTranslators(versionDependentTranslators);
foreach (var plugin in npgsqlOptions.Plugins)
plugin.AddMethodCallTranslators(this);
diff --git a/src/EFCore.PG/Query/ExpressionVisitors/NpgsqlSqlTranslatingExpressionVisitor.cs b/src/EFCore.PG/Query/ExpressionVisitors/NpgsqlSqlTranslatingExpressionVisitor.cs
index e150e88c2..036573158 100644
--- a/src/EFCore.PG/Query/ExpressionVisitors/NpgsqlSqlTranslatingExpressionVisitor.cs
+++ b/src/EFCore.PG/Query/ExpressionVisitors/NpgsqlSqlTranslatingExpressionVisitor.cs
@@ -2,7 +2,7 @@
// The PostgreSQL License
//
-// Copyright (C) 2016 The Npgsql Development Team
+// Copyright (C) 2018 The Npgsql Development Team
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
diff --git a/src/EFCore.PG/Query/Sql/Internal/NpgsqlQuerySqlGenerator.cs b/src/EFCore.PG/Query/Sql/Internal/NpgsqlQuerySqlGenerator.cs
index 48373a059..4aa2a3e57 100644
--- a/src/EFCore.PG/Query/Sql/Internal/NpgsqlQuerySqlGenerator.cs
+++ b/src/EFCore.PG/Query/Sql/Internal/NpgsqlQuerySqlGenerator.cs
@@ -2,7 +2,7 @@
// The PostgreSQL License
//
-// Copyright (C) 2016 The Npgsql Development Team
+// Copyright (C) 2018 The Npgsql Development Team
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
@@ -195,8 +195,7 @@ protected override Expression VisitBinary(BinaryExpression expression)
}
case ExpressionType.ArrayIndex:
- VisitArrayIndex(expression);
- return expression;
+ return VisitArrayIndex(expression);
default:
return base.VisitBinary(expression);
@@ -228,26 +227,29 @@ protected override Expression VisitUnary(UnaryExpression expression)
return base.VisitUnary(expression);
}
- protected virtual void VisitArrayIndex([NotNull] BinaryExpression expression)
+ [NotNull]
+ protected virtual Expression VisitArrayIndex([NotNull] BinaryExpression expression)
{
Debug.Assert(expression.NodeType == ExpressionType.ArrayIndex);
if (expression.Left.Type == typeof(byte[]))
{
- // bytea cannot be subscripted, but there's get_byte
- VisitSqlFunction(new SqlFunctionExpression("get_byte", typeof(byte),
- new[] { expression.Left, expression.Right }));
- return;
+ // bytea cannot be subscripted, but there's get_byte.
+ return VisitSqlFunction(
+ new SqlFunctionExpression(
+ "get_byte",
+ typeof(byte),
+ new[] { expression.Left, expression.Right }));
}
if (expression.Left.Type == typeof(string))
{
- // text cannot be subscripted, use substr
- // PostgreSQL substr() is 1-based.
-
- VisitSqlFunction(new SqlFunctionExpression("substr", typeof(char),
- new[] { expression.Left, expression.Right, Expression.Constant(1) }));
- return;
+ // text cannot be subscripted, use substr. PostgreSQL substr() is 1-based.
+ return VisitSqlFunction(
+ new SqlFunctionExpression(
+ "substr",
+ typeof(char),
+ new[] { expression.Left, expression.Right, Expression.Constant(1) }));
}
// Regular array from here
@@ -255,11 +257,13 @@ protected virtual void VisitArrayIndex([NotNull] BinaryExpression expression)
Sql.Append('[');
Visit(GenerateOneBasedIndexExpression(expression.Right));
Sql.Append(']');
+ return expression;
}
///
/// Produces expressions like: 1 = ANY ('{0,1,2}') or 'cat' LIKE ANY ('{a%,b%,c%}').
///
+ [NotNull]
public virtual Expression VisitArrayAnyAll([NotNull] ArrayAnyAllExpression expression)
{
Visit(expression.Operand);
@@ -291,7 +295,7 @@ public virtual Expression VisitRegexMatch([NotNull] RegexMatchExpression express
Visit(expression.Match);
Sql.Append(" ~ ");
- // PG regexps are singleline by default
+ // PG regexps are single-line by default
if (options == RegexOptions.Singleline)
{
Visit(expression.Pattern);
diff --git a/test/EFCore.PG.FunctionalTests/Query/ArrayQueryTest.cs b/test/EFCore.PG.FunctionalTests/Query/ArrayQueryTest.cs
index eb69eab25..41863ba5b 100644
--- a/test/EFCore.PG.FunctionalTests/Query/ArrayQueryTest.cs
+++ b/test/EFCore.PG.FunctionalTests/Query/ArrayQueryTest.cs
@@ -19,7 +19,7 @@ public class ArrayQueryTest : IClassFixture
[Fact]
public void Roundtrip()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var x = ctx.SomeEntities.Single(e => e.Id == 1);
Assert.Equal(new[] { 3, 4 }, x.SomeArray);
@@ -34,7 +34,7 @@ public void Roundtrip()
[Fact]
public void Index_with_constant()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var actual = ctx.SomeEntities.Where(e => e.SomeArray[0] == 3).ToList();
Assert.Equal(1, actual.Count);
@@ -45,7 +45,7 @@ public void Index_with_constant()
[Fact]
public void Index_with_non_constant()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
// ReSharper disable once ConvertToConstant.Local
var x = 0;
@@ -58,7 +58,7 @@ public void Index_with_non_constant()
[Fact]
public void Index_bytea_with_constant()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var actual = ctx.SomeEntities.Where(e => e.SomeBytea[0] == 3).ToList();
Assert.Equal(1, actual.Count);
@@ -69,7 +69,7 @@ public void Index_bytea_with_constant()
[Fact]
public void Index_multidimensional()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
// Operations on multidimensional arrays aren't mapped to SQL yet
var actual = ctx.SomeEntities.Where(e => e.SomeMatrix[0, 0] == 5).ToList();
@@ -84,7 +84,7 @@ public void Index_multidimensional()
[Fact]
public void SequenceEqual_with_parameter()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var arr = new[] { 3, 4 };
var x = ctx.SomeEntities.Single(e => e.SomeArray.SequenceEqual(arr));
@@ -96,7 +96,7 @@ public void SequenceEqual_with_parameter()
[Fact]
public void SequenceEqual_with_array_literal()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var x = ctx.SomeEntities.Single(e => e.SomeArray.SequenceEqual(new[] { 3, 4 }));
Assert.Equal(new[] { 3, 4 }, x.SomeArray);
@@ -111,7 +111,7 @@ public void SequenceEqual_with_array_literal()
[Fact]
public void Contains_with_literal()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var x = ctx.SomeEntities.Single(e => e.SomeArray.Contains(3));
Assert.Equal(new[] { 3, 4 }, x.SomeArray);
@@ -122,7 +122,7 @@ public void Contains_with_literal()
[Fact]
public void Contains_with_parameter()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
// ReSharper disable once ConvertToConstant.Local
var p = 3;
@@ -135,7 +135,7 @@ public void Contains_with_parameter()
[Fact]
public void Contains_with_column()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var x = ctx.SomeEntities.Single(e => e.SomeArray.Contains(e.Id + 2));
Assert.Equal(new[] { 3, 4 }, x.SomeArray);
@@ -150,7 +150,7 @@ public void Contains_with_column()
[Fact]
public void Length()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var x = ctx.SomeEntities.Single(e => e.SomeArray.Length == 2);
Assert.Equal(new[] { 3, 4 }, x.SomeArray);
@@ -161,7 +161,7 @@ public void Length()
[Fact(Skip = "https://github.com/aspnet/EntityFramework/issues/9242")]
public void Length_on_EF_Property()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
// TODO: This fails
var x = ctx.SomeEntities.Single(e => EF.Property(e, nameof(SomeArrayEntity.SomeArray)).Length == 2);
@@ -173,7 +173,7 @@ public void Length_on_EF_Property()
[Fact]
public void Length_on_literal_not_translated()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var _ = ctx.SomeEntities.Where(e => new[] { 1, 2, 3 }.Length == e.Id).ToList();
AssertDoesNotContainInSql("array_length");
@@ -187,7 +187,7 @@ public void Length_on_literal_not_translated()
[Fact]
public void Array_like_any_when_match_expression_is_column()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var patterns = new[] { "a", "b", "c" };
@@ -210,7 +210,7 @@ public void Array_like_any_when_match_expression_is_column()
[Fact]
public void Array_like_any_not_translated_when_match_expression_is_qsre()
{
- using (var ctx = CreateContext())
+ using (var ctx = Fixture.CreateContext())
{
var matches = new[] { "a", "b", "c" };
@@ -246,8 +246,6 @@ public ArrayQueryTest(ArrayFixture fixture)
Fixture.TestSqlLoggerFactory.Clear();
}
- ArrayContext CreateContext() => Fixture.CreateContext();
-
void AssertContainsInSql(string expected)
=> Assert.Contains(expected, Fixture.TestSqlLoggerFactory.Sql);
@@ -257,8 +255,8 @@ void AssertDoesNotContainInSql(string expected)
public class ArrayContext : DbContext
{
public DbSet SomeEntities { get; set; }
+
public ArrayContext(DbContextOptions options) : base(options) {}
- protected override void OnModelCreating(ModelBuilder builder) {}
}
public class SomeArrayEntity
@@ -268,54 +266,56 @@ public class SomeArrayEntity
public int[,] SomeMatrix { get; set; }
public List SomeList { get; set; }
public byte[] SomeBytea { get; set; }
-
- // ReSharper disable once UnusedMember.Global
public string SomeText { get; set; }
}
public class ArrayFixture : IDisposable
{
- readonly DbContextOptions _options;
+ readonly NpgsqlTestStore _testStore;
public TestSqlLoggerFactory TestSqlLoggerFactory { get; } = new TestSqlLoggerFactory();
public ArrayFixture()
{
_testStore = NpgsqlTestStore.CreateScratch();
- _options = new DbContextOptionsBuilder()
- .UseNpgsql(_testStore.ConnectionString, b => b.ApplyConfiguration())
- .UseInternalServiceProvider(
- new ServiceCollection()
- .AddEntityFrameworkNpgsql()
- .AddSingleton(TestSqlLoggerFactory)
- .BuildServiceProvider())
- .Options;
using (var ctx = CreateContext())
{
ctx.Database.EnsureCreated();
- ctx.SomeEntities.Add(new SomeArrayEntity
- {
- Id = 1,
- SomeArray = new[] { 3, 4 },
- SomeBytea = new byte[] { 3, 4 },
- SomeMatrix = new[,] { { 5, 6 }, { 7, 8 } },
- SomeList = new List { 3, 4 }
- });
- ctx.SomeEntities.Add(new SomeArrayEntity
- {
- Id = 2,
- SomeArray = new[] { 5, 6, 7 },
- SomeBytea = new byte[] { 5, 6, 7 },
- SomeMatrix = new[,] { { 10, 11 }, { 12, 13 } },
- SomeList = new List { 3, 4 }
- });
+ ctx.SomeEntities.AddRange(
+ new SomeArrayEntity
+ {
+ Id = 1,
+ SomeArray = new[] { 3, 4 },
+ SomeBytea = new byte[] { 3, 4 },
+ SomeMatrix = new[,] { { 5, 6 }, { 7, 8 } },
+ SomeList = new List { 3, 4 }
+ },
+ new SomeArrayEntity
+ {
+ Id = 2,
+ SomeArray = new[] { 5, 6, 7 },
+ SomeBytea = new byte[] { 5, 6, 7 },
+ SomeMatrix = new[,] { { 10, 11 }, { 12, 13 } },
+ SomeList = new List { 3, 4 }
+ });
ctx.SaveChanges();
}
}
- readonly NpgsqlTestStore _testStore;
- public ArrayContext CreateContext() => new ArrayContext(_options);
+ public ArrayContext CreateContext(Version postgresVersion = default)
+ => new ArrayContext(CreateOptions(postgresVersion));
+
public void Dispose() => _testStore.Dispose();
+
+ DbContextOptions CreateOptions(Version postgresVersion = null)
+ => new DbContextOptionsBuilder()
+ .UseNpgsql(_testStore.ConnectionString, b => b.ApplyConfiguration().SetPostgresVersion(postgresVersion))
+ .UseInternalServiceProvider(
+ new ServiceCollection()
+ .AddEntityFrameworkNpgsql()
+ .AddSingleton(TestSqlLoggerFactory)
+ .BuildServiceProvider())
+ .Options;
}
#endregion