From 87ef29ebf185f20090e7647455bce8c76298116b Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Thu, 7 Dec 2023 14:38:12 +0100 Subject: [PATCH 01/27] Fix number formatting for trace configuration. --- .../Services/FbTraceConfiguration.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbTraceConfiguration.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbTraceConfiguration.cs index fc8b4b5d1..10573f1cc 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbTraceConfiguration.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbTraceConfiguration.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; @@ -36,7 +37,7 @@ protected static string WriteString(string s) protected static string WriteNumber(int i) { - return i.ToString(); + return i.ToString(CultureInfo.InvariantCulture); } protected static string WriteRegEx(string re) From 7b08f61102df1cf184b40dea61e9d3e15b17f6bc Mon Sep 17 00:00:00 2001 From: Lars Weber <67638665+lweberprb@users.noreply.github.com> Date: Fri, 8 Dec 2023 09:29:56 +0100 Subject: [PATCH 02/27] Support DESC-flag in migrations and scaffolding (#126) --- .../Migrations/FbMigrationsSqlGenerator.cs | 13 +++++++++++++ .../Scaffolding/Internal/FbDatabaseModelFactory.cs | 12 ++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs index cda1862f3..fb0b3f91a 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs @@ -201,6 +201,19 @@ protected override void Generate(CreateIndexOperation operation, IModel model, M { builder.Append("UNIQUE "); } + + if (operation.IsDescending is not null && operation.IsDescending.Length > 0) + { + var isDescending = operation.IsDescending[0]; + if (operation.IsDescending.Any(x => x != isDescending)) + throw new NotSupportedException("Mixed order indices are not supported by Firebird."); + + if (isDescending) + { + builder.Append("DESC "); + } + } + IndexTraits(operation, model, builder); builder.Append("INDEX "); builder.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name)); diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs index 535998203..dd3710def 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs @@ -311,6 +311,7 @@ private void GetPrimaryKeys(DbConnection connection, IReadOnlyList /// Primary keys are handled as in , not here @@ -343,11 +344,18 @@ private void GetIndexes(DbConnection connection, IReadOnlyList ta IsUnique = reader.GetBoolean(1), }; - foreach (var column in reader.GetString(2).Split(',')) + foreach (var column in reader.GetString(3).Split(',')) { index.Columns.Add(table.Columns.Single(y => y.Name == column.Trim())); } + if (reader.GetBoolean(2)) + { + var isDescending = new bool[index.Columns.Count]; + isDescending.AsSpan().Fill(true); + index.IsDescending = isDescending; + } + table.Indexes.Add(index); } } From 87933e5e9edb79dcab32f410431c407cd8219b10 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Sun, 10 Dec 2023 15:27:45 +0100 Subject: [PATCH 03/27] Proper quoting of strings in trace config (#1149). --- .../Services/FbTraceConfiguration.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbTraceConfiguration.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbTraceConfiguration.cs index 10573f1cc..2b6f9ffc7 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbTraceConfiguration.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbTraceConfiguration.cs @@ -15,11 +15,7 @@ //$Authors = Jiri Cincura (jiri@cincura.net) -using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; namespace FirebirdSql.Data.Services; @@ -32,7 +28,12 @@ protected static string WriteBoolValue(bool b) protected static string WriteString(string s) { - return string.Format("'{0}'", s); + s = s + .Replace("{", "{{") + .Replace("}", "}}") + .Replace(@"\", @"\\") + .Replace("\"", "\\\""); + return string.Format("\"{0}\"", s); } protected static string WriteNumber(int i) @@ -42,6 +43,6 @@ protected static string WriteNumber(int i) protected static string WriteRegEx(string re) { - return WriteString(re.Replace(@"\", @"\\").Replace("'", @"\'")); + return WriteString(re); } } From 6c96b0f2d44d52039e3d19d5a4d4c87e563c91f2 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Thu, 18 Jan 2024 10:44:18 +0100 Subject: [PATCH 04/27] Update relevant parts to net8.0 --- .github/workflows/ci.yml | 4 ++-- include.ps1 | 2 +- src/Directory.Build.props | 2 +- .../EntityFramework.Firebird.Tests.csproj | 6 +++--- .../EntityFrameworkTestsBase.cs | 1 + .../FirebirdSql.Data.FirebirdClient.Tests.csproj | 2 +- .../Common/IscException.cs | 15 --------------- .../FirebirdClient/FbException.cs | 6 ++++++ .../FirebirdSql.Data.FirebirdClient.csproj | 4 +++- ...yFrameworkCore.Firebird.FunctionalTests.csproj | 2 +- ...dSql.EntityFrameworkCore.Firebird.Tests.csproj | 2 +- src/Perf/Perf.csproj | 2 +- src/Scratchpad/Scratchpad.csproj | 2 +- 13 files changed, 22 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d9685f32..747e64085 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,10 +19,10 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: .NET 7.0 + - name: .NET 8.0 uses: actions/setup-dotnet@v3 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Build run: | diff --git a/include.ps1 b/include.ps1 index 3031b02bc..cb57d88dd 100644 --- a/include.ps1 +++ b/include.ps1 @@ -7,5 +7,5 @@ function Check-ExitCode() { } function Get-UsedTargetFramework() { - return 'net7.0' + return 'net8.0' } \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 610fbe8f0..387e25820 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -27,7 +27,7 @@ true - + all runtime; build; native; contentfiles; analyzers diff --git a/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj b/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj index 1e04b33f4..bd91e8ab5 100644 --- a/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj +++ b/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj @@ -1,7 +1,6 @@  - - net7.0 + net8.0 false false true @@ -12,7 +11,8 @@ Exe FirebirdSql.Data.TestsBase.Program - + + diff --git a/src/EntityFramework.Firebird.Tests/EntityFrameworkTestsBase.cs b/src/EntityFramework.Firebird.Tests/EntityFrameworkTestsBase.cs index cc8936ad0..d54eaafa5 100644 --- a/src/EntityFramework.Firebird.Tests/EntityFrameworkTestsBase.cs +++ b/src/EntityFramework.Firebird.Tests/EntityFrameworkTestsBase.cs @@ -28,6 +28,7 @@ public abstract class EntityFrameworkTestsBase : FbTestsBase static EntityFrameworkTestsBase() { #if !NETFRAMEWORK + // example/documentation for .NET Framework System.Data.Common.DbProviderFactories.RegisterFactory(FbProviderServices.ProviderInvariantName, FirebirdClientFactory.Instance); #endif DbConfiguration.SetConfiguration(new FbTestDbContext.Conf()); diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FirebirdSql.Data.FirebirdClient.Tests.csproj b/src/FirebirdSql.Data.FirebirdClient.Tests/FirebirdSql.Data.FirebirdClient.Tests.csproj index 9ca84ea94..8f2fc2b53 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FirebirdSql.Data.FirebirdClient.Tests.csproj +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FirebirdSql.Data.FirebirdClient.Tests.csproj @@ -1,6 +1,6 @@  - net7.0 + net8.0 false false true diff --git a/src/FirebirdSql.Data.FirebirdClient/Common/IscException.cs b/src/FirebirdSql.Data.FirebirdClient/Common/IscException.cs index a015f055c..e8fba86a2 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Common/IscException.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Common/IscException.cs @@ -27,7 +27,6 @@ namespace FirebirdSql.Data.Common; -[Serializable] internal sealed class IscException : Exception { private string _message; @@ -117,13 +116,6 @@ public static IscException ForIOException(IOException exception) return ForErrorCodes(new[] { IscCodes.isc_net_write_err, IscCodes.isc_net_read_err }, exception); } - private IscException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - Errors = (List)info.GetValue(nameof(Errors), typeof(List)); - ErrorCode = info.GetInt32(nameof(ErrorCode)); - } - public void BuildExceptionData() { BuildErrorCode(); @@ -131,13 +123,6 @@ public void BuildExceptionData() BuildExceptionMessage(); } - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue(nameof(Errors), Errors); - info.AddValue(nameof(ErrorCode), ErrorCode); - } - private void BuildErrorCode() { ErrorCode = Errors.Count != 0 ? Errors[0].ErrorCode : 0; diff --git a/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbException.cs b/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbException.cs index bdf14b3ca..c009f8006 100644 --- a/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbException.cs +++ b/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbException.cs @@ -24,7 +24,9 @@ namespace FirebirdSql.Data.FirebirdClient; +#if !NET8_0_OR_GREATER [Serializable] +#endif public sealed class FbException : DbException { #region Fields @@ -50,22 +52,26 @@ private FbException(string message, Exception innerException) : base(message, innerException) { } +#if !NET8_0_OR_GREATER private FbException(SerializationInfo info, StreamingContext context) : base(info, context) { _errors = (FbErrorCollection)info.GetValue("errors", typeof(FbErrorCollection)); } +#endif #endregion #region Methods +#if !NET8_0_OR_GREATER public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("errors", _errors); } +#endif #endregion diff --git a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj index 4aae158c3..4e6cf87d6 100644 --- a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj +++ b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj @@ -1,6 +1,6 @@  - net48;netstandard2.0;netstandard2.1;net5.0;net6.0;net7.0 + net48;netstandard2.0;netstandard2.1;net5.0;net6.0;net7.0;net8.0 FirebirdSql.Data.FirebirdClient FirebirdSql.Data true @@ -53,6 +53,8 @@ + + all diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj index 38b0392aa..e02397c02 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj @@ -1,6 +1,6 @@  - net7.0 + net8.0 false false true diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj index bcb38dba7..bc068fe0d 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj @@ -1,6 +1,6 @@  - net7.0 + net8.0 false false true diff --git a/src/Perf/Perf.csproj b/src/Perf/Perf.csproj index 4f300758b..3aa612b2f 100644 --- a/src/Perf/Perf.csproj +++ b/src/Perf/Perf.csproj @@ -1,7 +1,7 @@  Exe - net7.0 + net8.0 true diff --git a/src/Scratchpad/Scratchpad.csproj b/src/Scratchpad/Scratchpad.csproj index 03f5f17c9..08b17c2d5 100644 --- a/src/Scratchpad/Scratchpad.csproj +++ b/src/Scratchpad/Scratchpad.csproj @@ -1,7 +1,7 @@  Exe - net7.0 + net8.0 true true ..\FirebirdSql.Data.TestsBase\FirebirdSql.Data.TestsBase.snk From cf461dcdb5e0eb4e016cf5343baa913b2e8dd1a8 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Tue, 20 Feb 2024 17:01:38 +0100 Subject: [PATCH 05/27] Fix formatting --- .../FirebirdClient/FbBatchCommand.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbBatchCommand.cs b/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbBatchCommand.cs index e0e88e6c9..1ac9faa7e 100644 --- a/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbBatchCommand.cs +++ b/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbBatchCommand.cs @@ -27,6 +27,7 @@ using FirebirdSql.Data.Logging; namespace FirebirdSql.Data.FirebirdClient; + public sealed class FbBatchCommand : IFbPreparedCommand, IDescriptorFiller, IDisposable #if !(NET48 || NETSTANDARD2_0) , IAsyncDisposable From bcc403d3d4417e075528e2d19a00f113ff347b14 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Fri, 15 Mar 2024 21:18:53 +0100 Subject: [PATCH 06/27] Update GH actions to solve Node.js warnings --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 747e64085..9213627ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@v4 - name: .NET 8.0 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: 8.0.x @@ -51,6 +51,7 @@ jobs: shell: powershell - name: Publish Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: + name: 'ci_${{ matrix.TEST_SUITE }}_${{ matrix.FIREBIRD_SELECTION }}_${{ env.CONFIGURATION }}' path: '.\\out\\' From b1d6fa2fb83fceedab4eb40c6b2075bbe0d97cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Tue, 26 Mar 2024 11:28:53 +0100 Subject: [PATCH 07/27] Fix validation for TPC. (#128) Based on https://github.com/dotnet/efcore/pull/33371. --- .../Infrastructure/Internal/FbModelValidator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Infrastructure/Internal/FbModelValidator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Infrastructure/Internal/FbModelValidator.cs index 55581b406..cbcbf2b53 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Infrastructure/Internal/FbModelValidator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Infrastructure/Internal/FbModelValidator.cs @@ -32,7 +32,7 @@ public FbModelValidator(ModelValidatorDependencies dependencies, RelationalModel protected override void ValidateValueGeneration(IEntityType entityType, IKey key, IDiagnosticsLogger logger) { - if (entityType.GetTableName() != null && (string)entityType[RelationalAnnotationNames.MappingStrategy] == RelationalAnnotationNames.TpcMappingStrategy) + if (entityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy && entityType.BaseType == null) { foreach (var storeGeneratedProperty in key.Properties.Where(p => (p.ValueGenerated & ValueGenerated.OnAdd) != 0 && p.GetValueGenerationStrategy() == FbValueGenerationStrategy.IdentityColumn)) { From 55eb3500bc01dd4b04d2e7dc8ac6e7bcb9553302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Truba=C4=8D?= <40642559+dant02@users.noreply.github.com> Date: Sun, 14 Apr 2024 19:22:31 +0200 Subject: [PATCH 08/27] Add property FbCommand.NamedParameters (FirebirdSQL#1161) (#1168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel Trubač --- .../FbCommandTests.cs | 16 ++++++++++++++++ .../FirebirdClient/FbBatchCommand.cs | 10 ++++++++++ .../FirebirdClient/FbCommand.cs | 10 ++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FbCommandTests.cs b/src/FirebirdSql.Data.FirebirdClient.Tests/FbCommandTests.cs index c5bf8f0ad..639c746ea 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FbCommandTests.cs +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FbCommandTests.cs @@ -187,6 +187,22 @@ public async Task NamedParametersReuseTest() } } + [Test] + public async Task NamedParametersPublicAccessor() + { + await using (var command = new FbCommand("select * from test where int_field >= @x1 and int_field <= @x2", Connection)) + { + Assert.IsNotNull(command.NamedParameters, "Unexpected null reference."); + Assert.IsTrue(command.NamedParameters.Count == 0, "Expected count 0 of named parameters before command prepare."); + + await command.PrepareAsync(); + + Assert.IsTrue(command.NamedParameters.Count == 2, "Expected count 2 of named parameters after command prepare."); + Assert.AreEqual(command.NamedParameters[0], "@x1"); + Assert.AreEqual(command.NamedParameters[1], "@x2"); + } + } + [Test] public async Task ExecuteStoredProcTest() { diff --git a/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbBatchCommand.cs b/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbBatchCommand.cs index 1ac9faa7e..9e17669d2 100644 --- a/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbBatchCommand.cs +++ b/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbBatchCommand.cs @@ -192,6 +192,16 @@ public int BatchBufferSize } } + /// + /// Gets collection of parameters parsed from the query text during command prepare. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IReadOnlyList NamedParameters + { + get { return _namedParameters; } + } + #endregion #region Internal Properties diff --git a/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbCommand.cs b/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbCommand.cs index 459cdf9e3..c5a2cdea8 100644 --- a/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbCommand.cs +++ b/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbCommand.cs @@ -198,6 +198,16 @@ public int FetchSize } } + /// + /// Gets collection of parameters parsed from the query text during command prepare. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IReadOnlyList NamedParameters + { + get { return _namedParameters; } + } + #endregion #region Protected DbCommand Properties From 6bce4ed1b739416dacadc31c27c4482d77051c5b Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Sat, 27 Apr 2024 00:57:09 +0200 Subject: [PATCH 09/27] Easier copyright handling. --- src/Directory.Build.props | 3 +++ src/EntityFramework.Firebird/EntityFramework.Firebird.csproj | 2 +- .../FirebirdSql.Data.FirebirdClient.csproj | 2 +- .../FirebirdSql.EntityFrameworkCore.Firebird.csproj | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 387e25820..a1348f8bb 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -20,6 +20,9 @@ snupkg license.txt + + 2024 + diff --git a/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj b/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj index a2bb42363..4e7a0f275 100644 --- a/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj +++ b/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj @@ -10,7 +10,7 @@ NETProvider - Entity Framework Provider - (c) 2014-2023 + (c) 2014-$(CopyrightEndYear) EntityFramework.Firebird diff --git a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj index 4e6cf87d6..ac5377a3d 100644 --- a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj +++ b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj @@ -11,7 +11,7 @@ NETProvider - ADO.NET Data Provider - (c) 2002-2023 + (c) 2002-$(CopyrightEndYear) FirebirdSql.Data.FirebirdClient diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj index 1991916c0..b67d78537 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj @@ -10,7 +10,7 @@ NETProvider - Entity Framework Core Provider - (c) 2017-2023 + (c) 2017-$(CopyrightEndYear) FirebirdSql.EntityFrameworkCore.Firebird From f2a55392a1a04a745b364a8edb989086bd579989 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Mon, 13 May 2024 11:14:05 +0200 Subject: [PATCH 10/27] EF Core 8 provider (and refactoring around). --- build.ps1 | 27 +- include.ps1 | 4 - src/Directory.Build.props | 3 +- .../EntityFramework.Firebird.Tests.csproj | 1 - .../EntityFramework.Firebird.csproj | 8 +- .../FirebirdSql.Data.FirebirdClient.csproj | 1 + ...meworkCore.Firebird.FunctionalTests.csproj | 3 +- .../Helpers/ModelHelpers.cs | 28 +- .../MigrationsFbTest.cs | 36 +- ...nsCollectionsSplitSharedTypeQueryFbTest.cs | 7 + .../Query/ComplexTypeQueryFbTest.cs | 198 +++++++ .../Query/FromSqlQueryFbTest.cs | 11 +- .../Query/FunkyDataQueryFbTest.cs | 8 + .../Query/GearsOfWarQueryFbTest.cs | 28 + ...ompleteMappingInheritanceQueryFbFixture.cs | 4 +- ...IncompleteMappingInheritanceQueryFbTest.cs | 8 +- .../InheritanceRelationshipsQueryFbTest.cs | 17 +- ...onSharedPrimitiveCollectionsQueryFbTest.cs | 191 +++++++ .../NorthwindAggregateOperatorsQueryFbTest.cs | 26 + .../NorthwindChangeTrackingQueryFbTest.cs | 3 +- .../Query/NorthwindCompiledQueryFbTest.cs | 63 +-- .../Query/NorthwindFunctionsQueryFbTest.cs | 42 +- .../Query/NorthwindJoinQueryFbTest.cs | 7 + .../NorthwindMiscellaneousQueryFbTest.cs | 14 + .../Query/NorthwindQueryFbFixture.cs | 1 + ...ixture.cs => OperatorsProceduralFbTest.cs} | 11 +- .../Query/OperatorsQueryFbTest.cs | 62 +++ .../Query/OptionalDependentQueryFbFixture.cs | 27 + .../Query/OptionalDependentQueryFbTest.cs | 100 ++++ .../Query/PrimitiveCollectionsQueryFbTest.cs | 481 ++++++++++++++++++ .../Query/QueryFilterFuncletizationFbTest.cs | 26 +- .../Query/SqlExecutorFbTest.cs | 43 +- .../Query/SqlQueryFbTest.cs | 148 ++++++ .../TPCFiltersInheritanceQueryFbFixture.cs | 2 +- .../Query/TPCGearsOfWarQueryFbTest.cs | 47 +- .../Query/TPCInheritanceQueryFbFixture.cs | 2 +- .../Query/TPCInheritanceQueryFbTest.cs | 6 +- .../Query/TPCInheritanceQueryFbTestBase.cs | 6 +- .../Query/TPCInheritanceQueryHiLoFbTest.cs | 6 +- ...=> TPHFiltersInheritanceQueryFbFixture.cs} | 4 +- ...cs => TPHFiltersInheritanceQueryFbTest.cs} | 4 +- ...ure.cs => TPHInheritanceQueryFbFixture.cs} | 2 +- ...FbTest.cs => TPHInheritanceQueryFbTest.cs} | 7 +- .../TPTFiltersInheritanceQueryFbFixture.cs | 2 +- .../Query/TPTGearsOfWarQueryFbTest.cs | 68 ++- .../Query/TPTInheritanceQueryFbTest.cs | 5 +- .../Query/UdfDbFunctionFbTests.cs | 53 +- ....EntityFrameworkCore.Firebird.Tests.csproj | 1 - .../Migrations/MigrationsTests.cs | 15 +- .../Extensions/FbPropertyExtensions.cs | 20 +- .../FbServiceCollectionExtensions.cs | 1 + ...irdSql.EntityFrameworkCore.Firebird.csproj | 10 +- .../Migrations/FbMigrationsSqlGenerator.cs | 8 +- .../Internal/FbDateOnlyMethodTranslator.cs | 66 +++ .../Internal/FbStringContainsTranslator.cs | 5 +- .../Internal/FbStringEndsWithTranslator.cs | 9 +- .../Internal/FbStringStartsWithTranslator.cs | 9 +- .../Query/Internal/FbQueryRootProcessor.cs | 33 ++ .../Query/Internal/FbQuerySqlGenerator.cs | 74 ++- .../FbQueryTranslationPreprocessor.cs | 34 ++ .../FbQueryTranslationPreprocessorFactory.cs | 37 ++ .../Storage/Internal/FbTypeMappingSource.cs | 2 +- .../Internal/FbValueGeneratorCache.cs | 2 +- .../Internal/FbValueGeneratorSelector.cs | 6 +- src/NETProvider.sln | 3 +- src/Versions.props | 18 + tests.ps1 | 7 +- 67 files changed, 1933 insertions(+), 278 deletions(-) create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexTypeQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryFbTest.cs rename src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/{InheritanceRelationshipsQueryFbFixture.cs => OperatorsProceduralFbTest.cs} (68%) create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OperatorsQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OptionalDependentQueryFbFixture.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OptionalDependentQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/PrimitiveCollectionsQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SqlQueryFbTest.cs rename src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/{FiltersInheritanceQueryFbFixture.cs => TPHFiltersInheritanceQueryFbFixture.cs} (85%) rename src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/{FiltersInheritanceQueryFbTest.cs => TPHFiltersInheritanceQueryFbTest.cs} (79%) rename src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/{InheritanceQueryFbFixture.cs => TPHInheritanceQueryFbFixture.cs} (94%) rename src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/{InheritanceQueryFbTest.cs => TPHInheritanceQueryFbTest.cs} (74%) create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbDateOnlyMethodTranslator.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryRootProcessor.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryTranslationPreprocessor.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryTranslationPreprocessorFactory.cs create mode 100644 src/Versions.props diff --git a/build.ps1 b/build.ps1 index c5b84ce41..9a321609d 100644 --- a/build.ps1 +++ b/build.ps1 @@ -8,7 +8,9 @@ $baseDir = Split-Path -Parent $PSCommandPath . "$baseDir\include.ps1" $outDir = "$baseDir\out" -$version = '' +$versionProvider = '' +$versionEFCore = '' +$versionEF6 = '' function Clean() { if (Test-Path $outDir) { @@ -29,19 +31,28 @@ function Build() { b 'Restore' $False b 'Restore' b 'Build' - $script:version = (Get-Item $baseDir\src\FirebirdSql.Data.FirebirdClient\bin\$Configuration\$(Get-UsedTargetFramework)\FirebirdSql.Data.FirebirdClient.dll).VersionInfo.ProductVersion -replace '(\d+)\.(\d+)\.(\d+)(-[a-z0-9]+)?(.*)','$1.$2.$3$4' +} + +function Versions() { + function v($file) { + return (Get-Item $file).VersionInfo.ProductVersion -replace '(\d+)\.(\d+)\.(\d+)(-[a-z0-9]+)?.*','$1.$2.$3$4' + } + $script:versionProvider = v $baseDir\src\FirebirdSql.Data.FirebirdClient\bin\$Configuration\net8.0\FirebirdSql.Data.FirebirdClient.dll + $script:versionEFCore = v $baseDir\src\FirebirdSql.EntityFrameworkCore.Firebird\bin\$Configuration\net8.0\FirebirdSql.EntityFrameworkCore.Firebird.dll + $script:versionEF6 = v $baseDir\src\EntityFramework.Firebird\bin\$Configuration\net48\EntityFramework.Firebird.dll } function NuGets() { - cp $baseDir\src\FirebirdSql.Data.FirebirdClient\bin\$Configuration\FirebirdSql.Data.FirebirdClient.$version.nupkg $outDir - cp $baseDir\src\EntityFramework.Firebird\bin\$Configuration\EntityFramework.Firebird.$version.nupkg $outDir - cp $baseDir\src\FirebirdSql.EntityFrameworkCore.Firebird\bin\$Configuration\FirebirdSql.EntityFrameworkCore.Firebird.$version.nupkg $outDir + cp $baseDir\src\FirebirdSql.Data.FirebirdClient\bin\$Configuration\FirebirdSql.Data.FirebirdClient.$versionProvider.nupkg $outDir + cp $baseDir\src\FirebirdSql.EntityFrameworkCore.Firebird\bin\$Configuration\FirebirdSql.EntityFrameworkCore.Firebird.$versionEFCore.nupkg $outDir + cp $baseDir\src\EntityFramework.Firebird\bin\$Configuration\EntityFramework.Firebird.$versionEF6.nupkg $outDir - cp $baseDir\src\FirebirdSql.Data.FirebirdClient\bin\$Configuration\FirebirdSql.Data.FirebirdClient.$version.snupkg $outDir - cp $baseDir\src\EntityFramework.Firebird\bin\$Configuration\EntityFramework.Firebird.$version.snupkg $outDir - cp $baseDir\src\FirebirdSql.EntityFrameworkCore.Firebird\bin\$Configuration\FirebirdSql.EntityFrameworkCore.Firebird.$version.snupkg $outDir + cp $baseDir\src\FirebirdSql.Data.FirebirdClient\bin\$Configuration\FirebirdSql.Data.FirebirdClient.$versionProvider.snupkg $outDir + cp $baseDir\src\FirebirdSql.EntityFrameworkCore.Firebird\bin\$Configuration\FirebirdSql.EntityFrameworkCore.Firebird.$versionEFCore.snupkg $outDir + cp $baseDir\src\EntityFramework.Firebird\bin\$Configuration\EntityFramework.Firebird.$versionEF6.snupkg $outDir } Clean Build +Versions NuGets diff --git a/include.ps1 b/include.ps1 index cb57d88dd..a713a7a9f 100644 --- a/include.ps1 +++ b/include.ps1 @@ -4,8 +4,4 @@ function Check-ExitCode() { echo "Non-zero ($exitCode) exit code. Exiting..." exit $exitCode } -} - -function Get-UsedTargetFramework() { - return 'net8.0' } \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props index a1348f8bb..e01e0d79d 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,11 +1,10 @@ + latest portable - 10.0.0 - FirebirdSQL NETProvider FirebirdSQL diff --git a/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj b/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj index bd91e8ab5..52ce20027 100644 --- a/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj +++ b/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj @@ -22,7 +22,6 @@ - diff --git a/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj b/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj index 4e7a0f275..8457ebd6e 100644 --- a/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj +++ b/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj @@ -9,6 +9,7 @@ true + $(EF6ProviderVersion) NETProvider - Entity Framework Provider (c) 2014-$(CopyrightEndYear) @@ -45,7 +46,7 @@ - + @@ -53,7 +54,10 @@ - + + + + diff --git a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj index ac5377a3d..25dcfcbb1 100644 --- a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj +++ b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj @@ -10,6 +10,7 @@ true + $(ProviderVersion) NETProvider - ADO.NET Data Provider (c) 2002-$(CopyrightEndYear) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj index e02397c02..bbadea15a 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj @@ -11,7 +11,7 @@ true - + @@ -20,7 +20,6 @@ - diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/ModelHelpers.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/ModelHelpers.cs index f2d9b2371..96fc88b6b 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/ModelHelpers.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/ModelHelpers.cs @@ -30,12 +30,30 @@ public static void SetStringLengths(ModelBuilder modelBuilder) { foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { - foreach (var property in entityType.GetProperties()) + HandleProperties(entityType.GetProperties()); + HandleComplexProperties(entityType.GetComplexProperties()); + } + + void HandleProperties(IEnumerable properties) + { + foreach (var property in properties) + { + SetStringLength(property); + } + } + void HandleComplexProperties(IEnumerable complexProperties) + { + foreach (var cp in complexProperties) + { + HandleProperties(cp.ComplexType.GetProperties()); + HandleComplexProperties(cp.ComplexType.GetComplexProperties()); + } + } + void SetStringLength(IMutableProperty property) + { + if (property.ClrType == typeof(string) && property.GetMaxLength() == null) { - if (property.ClrType == typeof(string) && property.GetMaxLength() == null) - { - property.SetMaxLength(500); - } + property.SetMaxLength(500); } } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/MigrationsFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/MigrationsFbTest.cs index d27631822..dc0c08b49 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/MigrationsFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/MigrationsFbTest.cs @@ -129,8 +129,10 @@ public MigrationsFbTest(MigrationsFbFixture fixture) [Fact(Skip = SkipReason)] public override Task Add_column_with_collation() => base.Add_column_with_collation(); - [Fact(Skip = SkipReason)] - public override Task Add_column_computed_with_collation() => base.Add_column_computed_with_collation(); + [Theory(Skip = SkipReason)] + [InlineData(true)] + [InlineData(false)] + public override Task Add_column_computed_with_collation(bool stored) => base.Add_column_computed_with_collation(stored); [Fact(Skip = SkipReason)] public override Task Add_column_shared() => base.Add_column_shared(); @@ -324,6 +326,36 @@ public MigrationsFbTest(MigrationsFbFixture fixture) [Fact(Skip = SkipReason)] public override Task Drop_primary_key_string() => base.Drop_primary_key_string(); + [Fact(Skip = SkipReason)] + public override Task Alter_sequence_restart_with() => base.Alter_sequence_restart_with(); + + [Fact(Skip = SkipReason)] + public override Task Add_column_with_unbounded_max_length() => base.Add_column_with_unbounded_max_length(); + + [Fact(Skip = SkipReason)] + public override Task Add_optional_primitive_collection_to_existing_table() => base.Add_optional_primitive_collection_to_existing_table(); + + [Fact(Skip = SkipReason)] + public override Task Add_required_primitve_collection_to_existing_table() => base.Add_required_primitve_collection_to_existing_table(); + + [Fact(Skip = SkipReason)] + public override Task Add_required_primitve_collection_with_custom_converter_and_custom_default_value_to_existing_table() => base.Add_required_primitve_collection_with_custom_converter_and_custom_default_value_to_existing_table(); + + [Fact(Skip = SkipReason)] + public override Task Add_required_primitve_collection_with_custom_default_value_to_existing_table() => base.Add_required_primitve_collection_with_custom_default_value_to_existing_table(); + + [Fact(Skip = SkipReason)] + public override Task Create_table_with_complex_type_with_required_properties_on_derived_entity_in_TPH() => base.Create_table_with_complex_type_with_required_properties_on_derived_entity_in_TPH(); + + [Fact(Skip = SkipReason)] + public override Task Create_table_with_optional_primitive_collection() => base.Create_table_with_optional_primitive_collection(); + + [Fact(Skip = SkipReason)] + public override Task Create_table_with_required_primitive_collection() => base.Create_table_with_required_primitive_collection(); + + [Fact(Skip = SkipReason)] + public override Task Add_required_primitve_collection_with_custom_default_value_sql_to_existing_table() => Task.CompletedTask; + public class MigrationsFbFixture : MigrationsFixtureBase { protected override string StoreName => nameof(MigrationsFbTest); diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest.cs index e5641d09e..0f470b08b 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest.cs @@ -146,4 +146,11 @@ public override Task Take_Select_collection_Take(bool async) { return base.Take_Select_collection_Take(async); } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(bool async) + { + return base.Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexTypeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexTypeQueryFbTest.cs new file mode 100644 index 000000000..0e84b62ab --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexTypeQueryFbTest.cs @@ -0,0 +1,198 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Linq; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.ComplexTypeModel; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class ComplexTypeQueryFbTest : ComplexTypeQueryRelationalTestBase +{ + public ComplexTypeQueryFbTest(ComplexTypeQueryFbFixture fixture) + : base(fixture) + { } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_complex_type_via_optional_navigation(bool async) + { + return Assert.ThrowsAsync(() => base.Project_complex_type_via_optional_navigation(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_struct_complex_type_via_optional_navigation(bool async) + { + return Assert.ThrowsAsync(() => base.Project_struct_complex_type_via_optional_navigation(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Union_property_in_complex_type(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Select(c => c.ShippingAddress.AddressLine1) + .Union(ss.Set().Select(c => c.BillingAddress.AddressLine1))); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_same_entity_with_nested_complex_type_twice_with_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Project_same_entity_with_nested_complex_type_twice_with_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_same_entity_with_nested_complex_type_twice_with_double_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Project_same_entity_with_nested_complex_type_twice_with_double_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_same_entity_with_struct_nested_complex_type_twice_with_double_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Project_same_entity_with_struct_nested_complex_type_twice_with_double_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_same_entity_with_struct_nested_complex_type_twice_with_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Project_same_entity_with_struct_nested_complex_type_twice_with_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_same_nested_complex_type_twice_with_double_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Project_same_nested_complex_type_twice_with_double_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_same_nested_complex_type_twice_with_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Project_same_nested_complex_type_twice_with_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_same_struct_nested_complex_type_twice_with_double_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Project_same_struct_nested_complex_type_twice_with_double_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_same_struct_nested_complex_type_twice_with_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Project_same_struct_nested_complex_type_twice_with_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Union_of_same_entity_with_nested_complex_type_projected_twice_with_double_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Union_of_same_entity_with_nested_complex_type_projected_twice_with_double_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Union_of_same_entity_with_nested_complex_type_projected_twice_with_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Union_of_same_entity_with_nested_complex_type_projected_twice_with_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Union_of_same_nested_complex_type_projected_twice_with_double_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Union_of_same_nested_complex_type_projected_twice_with_double_pushdown(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Union_of_same_nested_complex_type_projected_twice_with_pushdown(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Union_of_same_nested_complex_type_projected_twice_with_pushdown(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Same_entity_with_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(bool async) + { + return base.Same_entity_with_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(async); + } + + public class ComplexTypeQueryFbFixture : ComplexTypeQueryRelationalFixtureBase + { + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + ModelHelpers.SetStringLengths(modelBuilder); + } + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FromSqlQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FromSqlQueryFbTest.cs index f306be02a..3c1770985 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FromSqlQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FromSqlQueryFbTest.cs @@ -22,7 +22,6 @@ using FirebirdSql.Data.FirebirdClient; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestModels.Northwind; using Microsoft.EntityFrameworkCore.TestUtilities; @@ -36,13 +35,6 @@ public FromSqlQueryFbTest(NorthwindQueryFbFixture fixture) : base(fixture) { } - protected override DbParameter CreateDbParameter(string name, object value) - => new FbParameter - { - ParameterName = name, - Value = value - }; - [Theory] [MemberData(nameof(IsAsyncData))] public override async Task FromSql_Count_used_twice_without_parameters(bool async) @@ -164,4 +156,7 @@ public override Task Multiple_occurrences_of_FromSql_with_db_parameter_adds_para { return base.Multiple_occurrences_of_FromSql_with_db_parameter_adds_parameter_only_once(async); } + + protected override DbParameter CreateDbParameter(string name, object value) + => new FbParameter { ParameterName = name, Value = value }; } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FunkyDataQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FunkyDataQueryFbTest.cs index 8510b7af3..da2911974 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FunkyDataQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FunkyDataQueryFbTest.cs @@ -16,6 +16,7 @@ //$Authors = Jiri Cincura (jiri@cincura.net) using System.Linq; +using System.Threading.Tasks; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; using Microsoft.EntityFrameworkCore; @@ -31,6 +32,13 @@ public FunkyDataQueryFbTest(FunkyDataQueryFbFixture fixture) : base(fixture) { } + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task String_contains_on_argument_with_wildcard_column(bool async) + { + return base.String_contains_on_argument_with_wildcard_column(async); + } + public class FunkyDataQueryFbFixture : FunkyDataQueryFixtureBase { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/GearsOfWarQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/GearsOfWarQueryFbTest.cs index 3d832cce1..3ae01245b 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/GearsOfWarQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/GearsOfWarQueryFbTest.cs @@ -390,6 +390,27 @@ public override Task Correlated_collection_with_groupby_with_complex_grouping_ke return base.Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); } + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Subquery_inside_Take_argument(bool async) + { + return base.Subquery_inside_Take_argument(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task DateTimeOffset_to_unix_time_milliseconds(bool async) + { + return base.DateTimeOffset_to_unix_time_milliseconds(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task DateTimeOffset_to_unix_time_seconds(bool async) + { + return base.DateTimeOffset_to_unix_time_seconds(async); + } + [Theory(Skip = "NETProvider#1008")] [MemberData(nameof(IsAsyncData))] public override Task Where_TimeOnly_IsBetween(bool async) @@ -403,4 +424,11 @@ public override Task Where_TimeOnly_Add_TimeSpan(bool async) { return base.Where_TimeOnly_Add_TimeSpan(async); } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task String_concat_with_null_conditional_argument(bool async) + { + return base.String_concat_with_null_conditional_argument(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/IncompleteMappingInheritanceQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/IncompleteMappingInheritanceQueryFbFixture.cs index ac1102d7f..e7187d908 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/IncompleteMappingInheritanceQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/IncompleteMappingInheritanceQueryFbFixture.cs @@ -21,7 +21,7 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class IncompleteMappingInheritanceQueryFbFixture : InheritanceQueryFbFixture +public class IncompleteMappingInheritanceQueryFbFixture : TPHInheritanceQueryFbFixture { - protected override bool IsDiscriminatorMappingComplete => false; + public override bool IsDiscriminatorMappingComplete => false; } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/IncompleteMappingInheritanceQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/IncompleteMappingInheritanceQueryFbTest.cs index 7be95ad4c..b3730b89a 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/IncompleteMappingInheritanceQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/IncompleteMappingInheritanceQueryFbTest.cs @@ -15,14 +15,14 @@ //$Authors = Jiri Cincura (jiri@cincura.net) -using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Query; +using Xunit.Abstractions; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class IncompleteMappingInheritanceQueryFbTest : InheritanceRelationalQueryTestBase +public class IncompleteMappingInheritanceQueryFbTest : TPHInheritanceQueryTestBase { - public IncompleteMappingInheritanceQueryFbTest(IncompleteMappingInheritanceQueryFbFixture fixture) - : base(fixture) + public IncompleteMappingInheritanceQueryFbTest(IncompleteMappingInheritanceQueryFbFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture, testOutputHelper) { } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceRelationshipsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceRelationshipsQueryFbTest.cs index 20854abe0..e2fe8d34a 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceRelationshipsQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceRelationshipsQueryFbTest.cs @@ -17,12 +17,15 @@ using System.Threading.Tasks; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class InheritanceRelationshipsQueryFbTest : InheritanceRelationshipsQueryTestBase +public class InheritanceRelationshipsQueryFbTest : InheritanceRelationshipsQueryTestBase { public InheritanceRelationshipsQueryFbTest(InheritanceRelationshipsQueryFbFixture fixture) : base(fixture) @@ -361,4 +364,16 @@ public override Task Include_on_derived_type_with_queryable_Cast(bool async) { return base.Include_on_derived_type_with_queryable_Cast(async); } + + public class InheritanceRelationshipsQueryFbFixture : InheritanceRelationshipsQueryRelationalFixture + { + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + ModelHelpers.SetPrimaryKeyGeneration(modelBuilder); + ModelHelpers.SimpleTableNames(modelBuilder); + } + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryFbTest.cs new file mode 100644 index 000000000..42e0b1e56 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryFbTest.cs @@ -0,0 +1,191 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NonSharedPrimitiveCollectionsQueryFbTest : NonSharedPrimitiveCollectionsQueryRelationalTestBase +{ + [NotSupportedOnFirebirdFact] + public override Task Array_of_string() + { + return base.Array_of_string(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_int() + { + return base.Array_of_int(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_long() + { + return base.Array_of_long(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_short() + { + return base.Array_of_short(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_byte() + { + return base.Array_of_byte(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_double() + { + return base.Array_of_double(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_float() + { + return base.Array_of_float(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_decimal() + { + return base.Array_of_decimal(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_DateTime() + { + return base.Array_of_DateTime(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_DateTime_with_milliseconds() + { + return base.Array_of_DateTime_with_milliseconds(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_DateTime_with_microseconds() + { + return base.Array_of_DateTime_with_microseconds(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_DateOnly() + { + return base.Array_of_DateOnly(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_TimeOnly() + { + return base.Array_of_TimeOnly(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_TimeOnly_with_milliseconds() + { + return base.Array_of_TimeOnly_with_milliseconds(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_TimeOnly_with_microseconds() + { + return base.Array_of_TimeOnly_with_microseconds(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_DateTimeOffset() + { + return base.Array_of_DateTimeOffset(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_bool() + { + return base.Array_of_bool(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_Guid() + { + return base.Array_of_Guid(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_byte_array() + { + return base.Array_of_byte_array(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_enum() + { + return base.Array_of_enum(); + } + + [NotSupportedOnFirebirdFact] + public override Task Array_of_array_is_not_supported() + { + return base.Array_of_array_is_not_supported(); + } + + [NotSupportedOnFirebirdFact] + public override Task Multidimensional_array_is_not_supported() + { + return base.Multidimensional_array_is_not_supported(); + } + + [NotSupportedOnFirebirdFact] + public override Task Column_with_custom_converter() + { + return base.Column_with_custom_converter(); + } + + [NotSupportedOnFirebirdFact] + public override Task Parameter_with_inferred_value_converter() + { + return base.Parameter_with_inferred_value_converter(); + } + + [NotSupportedOnFirebirdFact] + public override Task Constant_with_inferred_value_converter() + { + return base.Constant_with_inferred_value_converter(); + } + + [NotSupportedOnFirebirdFact] + public override Task Inline_collection_in_query_filter() + { + return base.Inline_collection_in_query_filter(); + } + + [NotSupportedOnFirebirdFact] + public override Task Column_collection_inside_json_owned_entity() + { + return base.Column_collection_inside_json_owned_entity(); + } + + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindAggregateOperatorsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindAggregateOperatorsQueryFbTest.cs index fe50eb71c..778d544bf 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindAggregateOperatorsQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindAggregateOperatorsQueryFbTest.cs @@ -15,6 +15,7 @@ //$Authors = Jiri Cincura (jiri@cincura.net) +using System; using System.Threading.Tasks; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using Microsoft.EntityFrameworkCore.Query; @@ -38,6 +39,24 @@ public override Task Multiple_collection_navigation_with_FirstOrDefault_chained( return base.Multiple_collection_navigation_with_FirstOrDefault_chained(async); } + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override async Task Contains_with_local_enumerable_inline(bool async) + { + await Assert.ThrowsAsync( + async () => + await base.Contains_with_local_enumerable_inline(async)); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override async Task Contains_with_local_enumerable_inline_closure_mix(bool async) + { + await Assert.ThrowsAsync( + async () => + await base.Contains_with_local_enumerable_inline_closure_mix(async)); + } + [Theory] [MemberData(nameof(IsAsyncData))] public override Task Contains_with_local_anonymous_type_array_closure(bool async) @@ -72,4 +91,11 @@ public override Task Sum_with_division_on_decimal(bool async) { return base.Sum_with_division_on_decimal(async); } + + [Theory(Skip = "Different math on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Contains_inside_Average_without_GroupBy(bool async) + { + return base.Contains_inside_Average_without_GroupBy(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindChangeTrackingQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindChangeTrackingQueryFbTest.cs index b029cade2..eace4c3b5 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindChangeTrackingQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindChangeTrackingQueryFbTest.cs @@ -15,6 +15,7 @@ //$Authors = Jiri Cincura (jiri@cincura.net) +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestModels.Northwind; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestModels.Northwind; @@ -29,7 +30,7 @@ public NorthwindChangeTrackingQueryFbTest(NorthwindQueryFbFixture new NorthwindRelationalContext( + => new NorthwindFbContext( new DbContextOptionsBuilder(Fixture.CreateOptions()) .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking).Options); } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindCompiledQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindCompiledQueryFbTest.cs index d8b1e3e83..f8eaa9d2c 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindCompiledQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindCompiledQueryFbTest.cs @@ -15,15 +15,10 @@ //$Authors = Jiri Cincura (jiri@cincura.net) -using System; -using System.Linq; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.TestModels.Northwind; using Microsoft.EntityFrameworkCore.TestUtilities; -using Xunit; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; @@ -33,61 +28,15 @@ public NorthwindCompiledQueryFbTest(NorthwindQueryFbFixture : base(fixture) { } - [Fact] - public override void MakeBinary_does_not_throw_for_unsupported_operator() - { - Assert.Equal( - CoreStrings.TranslationFailed("DbSet() .Where(c => c.CustomerID == (string)(__parameters[0]))"), - Assert.Throws( - () => base.MakeBinary_does_not_throw_for_unsupported_operator()).Message.Replace("\r", "").Replace("\n", "")); - } - - [Fact] + [NotSupportedOnFirebirdFact] public override void Query_with_array_parameter() { - var query = EF.CompileQuery( - (NorthwindContext context, string[] args) - => context.Customers.Where(c => c.CustomerID == args[0])); - - using (var context = CreateContext()) - { - Assert.Equal( - CoreStrings.TranslationFailed("DbSet() .Where(c => c.CustomerID == __args[0])"), - Assert.Throws( - () => query(context, new[] { "ALFKI" }).First().CustomerID).Message.Replace("\r", "").Replace("\n", "")); - } - - using (var context = CreateContext()) - { - Assert.Equal( - CoreStrings.TranslationFailed("DbSet() .Where(c => c.CustomerID == __args[0])"), - Assert.Throws( - () => query(context, new[] { "ANATR" }).First().CustomerID).Message.Replace("\r", "").Replace("\n", "")); - } + base.Query_with_array_parameter(); } - [Fact] - public override async Task Query_with_array_parameter_async() + [NotSupportedOnFirebirdFact] + public override Task Query_with_array_parameter_async() { - var query = EF.CompileAsyncQuery( - (NorthwindContext context, string[] args) - => context.Customers.Where(c => c.CustomerID == args[0])); - - using (var context = CreateContext()) - { - Assert.Equal( - CoreStrings.TranslationFailed("DbSet() .Where(c => c.CustomerID == __args[0])"), - (await Assert.ThrowsAsync( - () => Enumerate(query(context, new[] { "ALFKI" })))).Message.Replace("\r", "").Replace("\n", "")); - } - - using (var context = CreateContext()) - { - Assert.Equal( - CoreStrings.TranslationFailed("DbSet() .Where(c => c.CustomerID == __args[0])"), - (await Assert.ThrowsAsync( - () => Enumerate(query(context, new[] { "ANATR" })))).Message.Replace("\r", "").Replace("\n", "")); - } + return base.Query_with_array_parameter_async(); } - } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindFunctionsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindFunctionsQueryFbTest.cs index d3ef9d563..13eb38b40 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindFunctionsQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindFunctionsQueryFbTest.cs @@ -108,6 +108,34 @@ public override Task TrimStart_with_char_array_argument_in_predicate(bool async) return base.TrimStart_with_char_array_argument_in_predicate(async); } + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_math_degrees(bool async) + { + return base.Where_math_degrees(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_math_radians(bool async) + { + return base.Where_mathf_radians(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_degrees(bool async) + { + return base.Where_math_degrees(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_radians(bool async) + { + return base.Where_mathf_radians(async); + } + [NotSupportedByProviderTheory] [MemberData(nameof(IsAsyncData))] public override Task Regex_IsMatch_MethodCall(bool async) @@ -268,18 +296,4 @@ public override Task Datetime_subtraction_TotalDays(bool async) { return base.Datetime_subtraction_TotalDays(async); } - - [Theory] - [MemberData(nameof(IsAsyncData))] - public override Task String_FirstOrDefault_MethodCall(bool async) - { - return base.String_FirstOrDefault_MethodCall(async); - } - - [Theory] - [MemberData(nameof(IsAsyncData))] - public override Task String_LastOrDefault_MethodCall(bool async) - { - return base.String_LastOrDefault_MethodCall(async); - } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindJoinQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindJoinQueryFbTest.cs index 49609b886..f6fd3ffae 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindJoinQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindJoinQueryFbTest.cs @@ -114,4 +114,11 @@ public override Task Unflattened_GroupJoin_composed_2(bool async) { return base.Unflattened_GroupJoin_composed_2(async); } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Join_local_collection_int_closure_is_cached_correctly(bool async) + { + return base.Join_local_collection_int_closure_is_cached_correctly(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindMiscellaneousQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindMiscellaneousQueryFbTest.cs index b2fcee996..9a48b8376 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindMiscellaneousQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindMiscellaneousQueryFbTest.cs @@ -133,4 +133,18 @@ public override Task SelectMany_correlated_subquery_hard(bool async) { return base.SelectMany_correlated_subquery_hard(async); } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Entity_equality_orderby_subquery(bool async) + { + return base.Entity_equality_orderby_subquery(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Subquery_with_navigation_inside_inline_collection(bool async) + { + return base.Subquery_with_navigation_inside_inline_collection(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindQueryFbFixture.cs index 5219a5cac..d6c6e7212 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindQueryFbFixture.cs @@ -22,6 +22,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.Northwind; using Microsoft.EntityFrameworkCore.TestUtilities; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceRelationshipsQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OperatorsProceduralFbTest.cs similarity index 68% rename from src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceRelationshipsQueryFbFixture.cs rename to src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OperatorsProceduralFbTest.cs index 81a30a962..1fdbc215d 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceRelationshipsQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OperatorsProceduralFbTest.cs @@ -15,22 +15,13 @@ //$Authors = Jiri Cincura (jiri@cincura.net) -using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; -using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class InheritanceRelationshipsQueryFbFixture : InheritanceRelationshipsQueryRelationalFixture +public class OperatorsProceduralFbTest : OperatorsProceduralQueryTestBase { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; - - protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) - { - base.OnModelCreating(modelBuilder, context); - ModelHelpers.SetPrimaryKeyGeneration(modelBuilder); - ModelHelpers.SimpleTableNames(modelBuilder); - } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OperatorsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OperatorsQueryFbTest.cs new file mode 100644 index 000000000..72a4473e5 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OperatorsQueryFbTest.cs @@ -0,0 +1,62 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class OperatorsQueryFbTest : OperatorsQueryTestBase +{ + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Concat_and_json_scalar(bool async) + { + return base.Concat_and_json_scalar(async); + } + + protected override ContextFactory Initialize(Action onModelCreating = null, Action onConfiguring = null, Action addServices = null, Action seed = null, Func shouldLogCategory = null, Func createTestStore = null, bool usePooling = true) + { + return base.Initialize( + modelBuilder => + { + ModelHelpers.SetStringLengths(modelBuilder); + onModelCreating?.Invoke(modelBuilder); + }, + onConfiguring, addServices, seed, shouldLogCategory, createTestStore, usePooling); + } + + protected override Task> InitializeAsync(Action onModelCreating = null, Action onConfiguring = null, Action addServices = null, Action seed = null, Func shouldLogCategory = null, Func createTestStore = null, bool usePooling = true) + { + return base.InitializeAsync( + modelBuilder => + { + ModelHelpers.SetStringLengths(modelBuilder); + onModelCreating?.Invoke(modelBuilder); + }, + onConfiguring, addServices, seed, shouldLogCategory, createTestStore, usePooling); + } + + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OptionalDependentQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OptionalDependentQueryFbFixture.cs new file mode 100644 index 000000000..337a447e7 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OptionalDependentQueryFbFixture.cs @@ -0,0 +1,27 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class OptionalDependentQueryFbFixture : OptionalDependentQueryFixtureBase +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OptionalDependentQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OptionalDependentQueryFbTest.cs new file mode 100644 index 000000000..72e33e6b0 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OptionalDependentQueryFbTest.cs @@ -0,0 +1,100 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class OptionalDependentQueryFbTest : OptionalDependentQueryTestBase +{ + public OptionalDependentQueryFbTest(OptionalDependentQueryFbFixture fixture) + : base(fixture) + { } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Basic_projection_entity_with_all_optional(bool async) + { + return base.Basic_projection_entity_with_all_optional(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Basic_projection_entity_with_some_required(bool async) + { + return base.Basic_projection_entity_with_some_required(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filter_nested_optional_dependent_with_all_optional_compared_to_not_null(bool async) + { + return base.Filter_nested_optional_dependent_with_all_optional_compared_to_not_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filter_nested_optional_dependent_with_all_optional_compared_to_null(bool async) + { + return base.Filter_nested_optional_dependent_with_all_optional_compared_to_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filter_nested_optional_dependent_with_some_required_compared_to_not_null(bool async) + { + return base.Filter_nested_optional_dependent_with_some_required_compared_to_not_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filter_nested_optional_dependent_with_some_required_compared_to_null(bool async) + { + return base.Filter_nested_optional_dependent_with_some_required_compared_to_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filter_optional_dependent_with_all_optional_compared_to_not_null(bool async) + { + return base.Filter_optional_dependent_with_all_optional_compared_to_not_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filter_optional_dependent_with_all_optional_compared_to_null(bool async) + { + return base.Filter_optional_dependent_with_all_optional_compared_to_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filter_optional_dependent_with_some_required_compared_to_not_null(bool async) + { + return base.Filter_optional_dependent_with_some_required_compared_to_not_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filter_optional_dependent_with_some_required_compared_to_null(bool async) + { + return base.Filter_optional_dependent_with_some_required_compared_to_null(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/PrimitiveCollectionsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/PrimitiveCollectionsQueryFbTest.cs new file mode 100644 index 000000000..8b800517d --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/PrimitiveCollectionsQueryFbTest.cs @@ -0,0 +1,481 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class PrimitiveCollectionsQueryFbTest : PrimitiveCollectionsQueryRelationalTestBase +{ + public PrimitiveCollectionsQueryFbTest(PrimitiveCollectionsQueryFbFixture fixture) + : base(fixture) + { } + + [ConditionalFact] + public virtual async Task Json_representation_of_bool_array() + { + await using var context = CreateContext(); + + Assert.Equal( + "[true,false]", + await context.Database.SqlQuery($@"SELECT ""Bools"" AS ""Value"" FROM ""PrimitiveCollectionsEntity"" WHERE ""Id"" = 1") + .SingleAsync()); + } + + [NotSupportedOnFirebirdFact] + public override void Parameter_collection_in_subquery_and_Convert_as_compiled_query() + { + base.Parameter_collection_in_subquery_and_Convert_as_compiled_query(); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_in_subquery_Union_another_parameter_collection_as_compiled_query(bool async) + { + return base.Parameter_collection_in_subquery_Union_another_parameter_collection_as_compiled_query(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_of_strings_contains_null(bool async) + { + return base.Column_collection_of_strings_contains_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Inline_collection_Count_with_one_value(bool async) + { + return base.Inline_collection_Count_with_one_value(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Inline_collection_Count_with_two_values(bool async) + { + return base.Inline_collection_Count_with_two_values(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Inline_collection_Count_with_three_values(bool async) + { + return base.Inline_collection_Count_with_three_values(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_Count(bool async) + { + return base.Parameter_collection_Count(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_of_ints_Contains_int(bool async) + { + return base.Parameter_collection_of_ints_Contains_int(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_of_nullable_ints_Contains_int(bool async) + { + return base.Parameter_collection_of_nullable_ints_Contains_int(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_of_nullable_ints_Contains_nullable_int(bool async) + { + return base.Parameter_collection_of_nullable_ints_Contains_nullable_int(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_of_strings_Contains_string(bool async) + { + return base.Parameter_collection_of_strings_Contains_string(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_of_strings_Contains_nullable_string(bool async) + { + return base.Parameter_collection_of_strings_Contains_nullable_string(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_of_DateTimes_Contains(bool async) + { + return base.Parameter_collection_of_DateTimes_Contains(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_of_bools_Contains(bool async) + { + return base.Parameter_collection_of_bools_Contains(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_of_enums_Contains(bool async) + { + return base.Parameter_collection_of_enums_Contains(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_null_Contains(bool async) + { + return base.Parameter_collection_null_Contains(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_of_ints_Contains(bool async) + { + return base.Column_collection_of_ints_Contains(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_of_nullable_ints_Contains(bool async) + { + return base.Column_collection_of_nullable_ints_Contains(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_of_nullable_ints_Contains_null(bool async) + { + return base.Column_collection_of_nullable_ints_Contains_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_of_nullable_strings_contains_null(bool async) + { + return base.Column_collection_of_nullable_strings_contains_null(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_of_bools_Contains(bool async) + { + return base.Column_collection_of_bools_Contains(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Count_method(bool async) + { + return base.Column_collection_Count_method(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Length(bool async) + { + return base.Column_collection_Length(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_index_int(bool async) + { + return base.Column_collection_index_int(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_index_string(bool async) + { + return base.Column_collection_index_string(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_index_datetime(bool async) + { + return base.Column_collection_index_datetime(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_index_beyond_end(bool async) + { + return base.Column_collection_index_beyond_end(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Nullable_reference_column_collection_index_equals_nullable_column(bool async) + { + return base.Nullable_reference_column_collection_index_equals_nullable_column(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Non_nullable_reference_column_collection_index_equals_nullable_column(bool async) + { + return base.Non_nullable_reference_column_collection_index_equals_nullable_column(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Inline_collection_index_Column(bool async) + { + return base.Inline_collection_index_Column(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_index_Column_equal_Column(bool async) + { + return base.Parameter_collection_index_Column_equal_Column(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_index_Column_equal_constant(bool async) + { + return base.Parameter_collection_index_Column_equal_constant(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_ElementAt(bool async) + { + return base.Column_collection_ElementAt(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Skip(bool async) + { + return base.Column_collection_Skip(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Take(bool async) + { + return base.Column_collection_Take(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Skip_Take(bool async) + { + return base.Column_collection_Skip_Take(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_OrderByDescending_ElementAt(bool async) + { + return base.Column_collection_OrderByDescending_ElementAt(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Any(bool async) + { + return base.Column_collection_Any(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Distinct(bool async) + { + return base.Column_collection_Distinct(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Join_parameter_collection(bool async) + { + return base.Column_collection_Join_parameter_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Inline_collection_Join_ordered_column_collection(bool async) + { + return base.Inline_collection_Join_ordered_column_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_Concat_column_collection(bool async) + { + return base.Parameter_collection_Concat_column_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Union_parameter_collection(bool async) + { + return base.Column_collection_Union_parameter_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_Intersect_inline_collection(bool async) + { + return base.Column_collection_Intersect_inline_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Inline_collection_Except_column_collection(bool async) + { + return base.Inline_collection_Except_column_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_in_subquery_Union_column_collection_as_compiled_query(bool async) + { + return base.Parameter_collection_in_subquery_Union_column_collection_as_compiled_query(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_in_subquery_Union_column_collection(bool async) + { + return base.Parameter_collection_in_subquery_Union_column_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_in_subquery_Union_column_collection_nested(bool async) + { + return base.Parameter_collection_in_subquery_Union_column_collection_nested(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Parameter_collection_in_subquery_Count_as_compiled_query(bool async) + { + return base.Parameter_collection_in_subquery_Count_as_compiled_query(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Column_collection_in_subquery_Union_parameter_collection(bool async) + { + return base.Column_collection_in_subquery_Union_parameter_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_collection_of_ints_ordered(bool async) + { + return base.Project_collection_of_ints_ordered(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_collection_of_datetimes_filtered(bool async) + { + return base.Project_collection_of_datetimes_filtered(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_collection_of_nullable_ints_with_paging(bool async) + { + return base.Project_collection_of_nullable_ints_with_paging(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_collection_of_nullable_ints_with_paging2(bool async) + { + return base.Project_collection_of_nullable_ints_with_paging2(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_collection_of_nullable_ints_with_paging3(bool async) + { + return base.Project_collection_of_nullable_ints_with_paging3(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_collection_of_ints_with_distinct(bool async) + { + return base.Project_collection_of_ints_with_distinct(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_empty_collection_of_nullables_and_collection_only_containing_nulls(bool async) + { + return base.Project_empty_collection_of_nullables_and_collection_only_containing_nulls(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_multiple_collections(bool async) + { + return base.Project_multiple_collections(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_primitive_collections_element(bool async) + { + return base.Project_primitive_collections_element(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async) + { + return base.Nested_contains_with_Lists_and_no_inferred_type_mapping(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Nested_contains_with_arrays_and_no_inferred_type_mapping(bool async) + { + return base.Nested_contains_with_arrays_and_no_inferred_type_mapping(async); + } + + PrimitiveCollectionsContext CreateContext() + { + return Fixture.CreateContext(); + } + + public class PrimitiveCollectionsQueryFbFixture : PrimitiveCollectionsQueryFixtureBase + { + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryFilterFuncletizationFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryFilterFuncletizationFbTest.cs index f06645473..0713a9824 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryFilterFuncletizationFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryFilterFuncletizationFbTest.cs @@ -58,22 +58,7 @@ public override void DbContext_list_is_parameterized() var fbTestStore = (FbTestStore)Fixture.TestStore; if (fbTestStore.ServerLessThan4()) return; - - using var context = CreateContext(); - // Default value of TenantIds is null InExpression over null values throws - Assert.Throws(() => context.Set().ToList()); - - context.TenantIds = new List(); - var query = context.Set().ToList(); - Assert.Empty(query); - - context.TenantIds = new List { 1 }; - query = context.Set().ToList(); - Assert.Single(query); - - context.TenantIds = new List { 2, 3 }; - query = context.Set().ToList(); - Assert.Equal(2, query.Count); + base.DbContext_list_is_parameterized(); } [Fact] @@ -292,6 +277,15 @@ public override void Using_multiple_context_in_filter_parametrize_only_current_c base.Using_multiple_context_in_filter_parametrize_only_current_context(); } + [Fact] + public override void Using_multiple_entities_with_filters_reuses_parameters() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Using_multiple_entities_with_filters_reuses_parameters(); + } + public class QueryFilterFuncletizationFbFixture : QueryFilterFuncletizationRelationalFixture { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SqlExecutorFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SqlExecutorFbTest.cs index 0f7e53b5b..d852e8c1b 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SqlExecutorFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SqlExecutorFbTest.cs @@ -22,6 +22,7 @@ using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; @@ -38,39 +39,27 @@ protected override DbParameter CreateDbParameter(string name, object value) protected override string CustomerOrderHistorySproc => throw new NotSupportedException(); protected override string CustomerOrderHistoryWithGeneratedParameterSproc => throw new NotSupportedException(); - [DoesNotHaveTheDataFact] - public override void Executes_stored_procedure() + [DoesNotHaveTheDataTheory] + [InlineData(false)] + [InlineData(true)] + public override Task Executes_stored_procedure(bool async) { - base.Executes_stored_procedure(); + return base.Executes_stored_procedure(async); } - [DoesNotHaveTheDataFact] - public override Task Executes_stored_procedure_async() + [DoesNotHaveTheDataTheory] + [InlineData(false)] + [InlineData(true)] + public override Task Executes_stored_procedure_with_generated_parameter(bool async) { - return base.Executes_stored_procedure_async(); + return base.Executes_stored_procedure_with_generated_parameter(async); } - [DoesNotHaveTheDataFact] - public override void Executes_stored_procedure_with_generated_parameter() + [DoesNotHaveTheDataTheory] + [InlineData(false)] + [InlineData(true)] + public override Task Executes_stored_procedure_with_parameter(bool async) { - base.Executes_stored_procedure_with_generated_parameter(); - } - - [DoesNotHaveTheDataFact] - public override Task Executes_stored_procedure_with_generated_parameter_async() - { - return base.Executes_stored_procedure_with_generated_parameter_async(); - } - - [DoesNotHaveTheDataFact] - public override void Executes_stored_procedure_with_parameter() - { - base.Executes_stored_procedure_with_parameter(); - } - - [DoesNotHaveTheDataFact] - public override Task Executes_stored_procedure_with_parameter_async() - { - return base.Executes_stored_procedure_with_parameter_async(); + return base.Executes_stored_procedure_with_parameter(async); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SqlQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SqlQueryFbTest.cs new file mode 100644 index 000000000..b5f827a2f --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SqlQueryFbTest.cs @@ -0,0 +1,148 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Data.Common; +using System.Threading.Tasks; +using FirebirdSql.Data.FirebirdClient; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class SqlQueryFbTest : SqlQueryTestBase> +{ + public SqlQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + [Theory(Skip = "Provider does the casting.")] + [MemberData(nameof(IsAsyncData))] + public override Task Bad_data_error_handling_invalid_cast(bool async) + { + return base.Bad_data_error_handling_invalid_cast(async); + } + + [Theory(Skip = "Provider does the casting.")] + [MemberData(nameof(IsAsyncData))] + public override Task Bad_data_error_handling_invalid_cast_key(bool async) + { + return base.Bad_data_error_handling_invalid_cast_key(async); + } + + [Theory(Skip = "Provider does the casting.")] + [MemberData(nameof(IsAsyncData))] + public override Task Bad_data_error_handling_invalid_cast_no_tracking(bool async) + { + return base.Bad_data_error_handling_invalid_cast_no_tracking(async); + } + + [Theory(Skip = "Provider does the casting.")] + [MemberData(nameof(IsAsyncData))] + public override Task Bad_data_error_handling_invalid_cast_projection(bool async) + { + return base.Bad_data_error_handling_invalid_cast_projection(async); + } + + [Theory(Skip = "Provider does the casting.")] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_queryable_simple_projection_composed(bool async) + { + return base.SqlQueryRaw_queryable_simple_projection_composed(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Multiple_occurrences_of_SqlQuery_with_db_parameter_adds_parameter_only_once(bool async) + { + return base.Multiple_occurrences_of_SqlQuery_with_db_parameter_adds_parameter_only_once(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_with_dbParameter_mixed_in_subquery(bool async) + { + return base.SqlQueryRaw_with_dbParameter_mixed_in_subquery(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_queryable_multiple_composed_with_parameters_and_closure_parameters(bool async) + { + return base.SqlQueryRaw_queryable_multiple_composed_with_parameters_and_closure_parameters(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_queryable_multiple_composed_with_closure_parameters(bool async) + { + return base.SqlQueryRaw_queryable_multiple_composed_with_closure_parameters(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_queryable_multiple_composed(bool async) + { + return base.SqlQueryRaw_queryable_multiple_composed(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_in_subquery_with_positional_dbParameter_without_name(bool async) + { + return base.SqlQueryRaw_in_subquery_with_positional_dbParameter_without_name(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_in_subquery_with_positional_dbParameter_with_name(bool async) + { + return base.SqlQueryRaw_in_subquery_with_positional_dbParameter_with_name(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_in_subquery_with_dbParameter(bool async) + { + return base.SqlQueryRaw_in_subquery_with_dbParameter(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_does_not_parameterize_interpolated_string(bool async) + { + return base.SqlQueryRaw_does_not_parameterize_interpolated_string(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQueryRaw_queryable_with_null_parameter(bool async) + { + return base.SqlQueryRaw_queryable_with_null_parameter(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SqlQuery_queryable_multiple_composed_with_parameters_and_closure_parameters_interpolated(bool async) + { + return base.SqlQuery_queryable_multiple_composed_with_parameters_and_closure_parameters_interpolated(async); + } + + protected override DbParameter CreateDbParameter(string name, object value) + => new FbParameter { ParameterName = name, Value = value }; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbFixture.cs index c3634770c..4ed46411a 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbFixture.cs @@ -19,5 +19,5 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class TPCFiltersInheritanceQueryFbFixture : TPCInheritanceQueryFbFixture { - protected override bool EnableFilters => true; + public override bool EnableFilters => true; } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbTest.cs index d93eab640..ef788f503 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbTest.cs @@ -20,7 +20,6 @@ using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; -using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; @@ -31,6 +30,31 @@ public TPCGearsOfWarQueryFbTest(TPCGearsOfWarQueryFbFixture fixture) : base(fixture) { } + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task ToString_boolean_property_non_nullable(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Select(w => w.IsAutomatic.ToString()), elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.OrdinalIgnoreCase)); }); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task ToString_boolean_property_nullable(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Select(lh => lh.Eradicated.ToString()), elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.OrdinalIgnoreCase)); }); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Group_by_on_StartsWith_with_null_parameter_as_argument(bool async) + { + return base.Group_by_on_StartsWith_with_null_parameter_as_argument(async); + } + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] public override Task Array_access_on_byte_array(bool async) @@ -220,6 +244,13 @@ public override Task Subquery_projecting_nullable_scalar_contains_nullable_value return base.Subquery_projecting_nullable_scalar_contains_nullable_value_needs_null_expansion_negated(async); } + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Subquery_inside_Take_argument(bool async) + { + return base.Subquery_inside_Take_argument(async); + } + [NotSupportedByProviderTheory] [MemberData(nameof(IsAsyncData))] public override Task Where_DateOnly_AddDays(bool async) @@ -416,20 +447,18 @@ public override Task Where_TimeOnly_subtract_TimeOnly(bool async) return base.Where_TimeOnly_subtract_TimeOnly(async); } - [Theory] + [NotSupportedByProviderTheory] [MemberData(nameof(IsAsyncData))] - public override Task ToString_boolean_property_nullable(bool async) + public override Task DateTimeOffset_to_unix_time_milliseconds(bool async) { - return AssertQuery(async, (ISetSource ss) => from lh in ss.Set() - select ((object)lh.Eradicated).ToString(), null, elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.InvariantCultureIgnoreCase)); }, assertOrder: false, 0, "ToString_boolean_property_nullable"); + return base.DateTimeOffset_to_unix_time_milliseconds(async); } - [Theory] + [NotSupportedByProviderTheory] [MemberData(nameof(IsAsyncData))] - public override Task ToString_boolean_property_non_nullable(bool async) + public override Task DateTimeOffset_to_unix_time_seconds(bool async) { - return AssertQuery(async, (ISetSource ss) => from w in ss.Set() - select w.IsAutomatic.ToString(), null, elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.InvariantCultureIgnoreCase)); }, assertOrder: false, 0, "ToString_boolean_property_non_nullable"); + return base.DateTimeOffset_to_unix_time_seconds(async); } [Theory(Skip = "Different implicit ordering on Firebird.")] diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixture.cs index eb47f9bd4..c0a9d8d06 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixture.cs @@ -19,5 +19,5 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class TPCInheritanceQueryFbFixture : TPCInheritanceQueryFbFixtureBase { - protected override bool UseGeneratedKeys => true; + public override bool UseGeneratedKeys => true; } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTest.cs index 36c293304..026610653 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTest.cs @@ -15,11 +15,13 @@ //$Authors = Jiri Cincura (jiri@cincura.net) +using Xunit.Abstractions; + namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class TPCInheritanceQueryFbTest : TPCInheritanceQueryFbTestBase { - public TPCInheritanceQueryFbTest(TPCInheritanceQueryFbFixture fixture) - : base(fixture) + public TPCInheritanceQueryFbTest(TPCInheritanceQueryFbFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture, testOutputHelper) { } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTestBase.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTestBase.cs index 71ed94862..4f2630de3 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTestBase.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTestBase.cs @@ -15,15 +15,15 @@ //$Authors = Jiri Cincura (jiri@cincura.net) -using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Query; +using Xunit.Abstractions; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public abstract class TPCInheritanceQueryFbTestBase : TPCInheritanceQueryTestBase where TFixture : TPCInheritanceQueryFbFixtureBase, new() { - protected TPCInheritanceQueryFbTestBase(TFixture fixture) - : base(fixture) + protected TPCInheritanceQueryFbTestBase(TFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture, testOutputHelper) { } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbTest.cs index 1edcc7360..39a6d588d 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbTest.cs @@ -15,11 +15,13 @@ //$Authors = Jiri Cincura (jiri@cincura.net) +using Xunit.Abstractions; + namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class TPCInheritanceQueryHiLoFbTest : TPCInheritanceQueryFbTestBase { - public TPCInheritanceQueryHiLoFbTest(TPCInheritanceQueryHiLoFbFixture fixture) - : base(fixture) + public TPCInheritanceQueryHiLoFbTest(TPCInheritanceQueryHiLoFbFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture, testOutputHelper) { } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FiltersInheritanceQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHFiltersInheritanceQueryFbFixture.cs similarity index 85% rename from src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FiltersInheritanceQueryFbFixture.cs rename to src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHFiltersInheritanceQueryFbFixture.cs index 7fcf769ec..e2e0ac7ca 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FiltersInheritanceQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHFiltersInheritanceQueryFbFixture.cs @@ -17,7 +17,7 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class FiltersInheritanceQueryFbFixture : InheritanceQueryFbFixture +public class TPHFiltersInheritanceQueryFbFixture : TPHInheritanceQueryFbFixture { - protected override bool EnableFilters => true; + public override bool EnableFilters => true; } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FiltersInheritanceQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHFiltersInheritanceQueryFbTest.cs similarity index 79% rename from src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FiltersInheritanceQueryFbTest.cs rename to src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHFiltersInheritanceQueryFbTest.cs index 714c79e5b..895bb9624 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FiltersInheritanceQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHFiltersInheritanceQueryFbTest.cs @@ -19,9 +19,9 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class FiltersInheritanceQueryFbTest : FiltersInheritanceQueryTestBase +public class TPHFiltersInheritanceQueryFbTest : FiltersInheritanceQueryTestBase { - public FiltersInheritanceQueryFbTest(FiltersInheritanceQueryFbFixture fixture) + public TPHFiltersInheritanceQueryFbTest(TPHFiltersInheritanceQueryFbFixture fixture) : base(fixture) { } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHInheritanceQueryFbFixture.cs similarity index 94% rename from src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceQueryFbFixture.cs rename to src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHInheritanceQueryFbFixture.cs index b1a9d94fe..b12c114b1 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHInheritanceQueryFbFixture.cs @@ -23,7 +23,7 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class InheritanceQueryFbFixture : InheritanceQueryRelationalFixture +public class TPHInheritanceQueryFbFixture : TPHInheritanceQueryFixture { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHInheritanceQueryFbTest.cs similarity index 74% rename from src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceQueryFbTest.cs rename to src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHInheritanceQueryFbTest.cs index 33063a50a..3b50b792f 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/InheritanceQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPHInheritanceQueryFbTest.cs @@ -16,12 +16,13 @@ //$Authors = Jiri Cincura (jiri@cincura.net) using Microsoft.EntityFrameworkCore.Query; +using Xunit.Abstractions; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class InheritanceQueryFbTest : InheritanceRelationalQueryTestBase +public class TPHInheritanceQueryFbTest : TPHInheritanceQueryTestBase { - public InheritanceQueryFbTest(InheritanceQueryFbFixture fixture) - : base(fixture) + public TPHInheritanceQueryFbTest(TPHInheritanceQueryFbFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture, testOutputHelper) { } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbFixture.cs index 056de0575..81ad223b0 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbFixture.cs @@ -22,7 +22,7 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class TPTFiltersInheritanceQueryFbFixture : TPTInheritanceQueryFbFixture { - protected override bool EnableFilters => true; + public override bool EnableFilters => true; protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) { diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTGearsOfWarQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTGearsOfWarQueryFbTest.cs index 3f0dc80d6..62886174e 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTGearsOfWarQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTGearsOfWarQueryFbTest.cs @@ -20,7 +20,6 @@ using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; -using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; @@ -31,6 +30,31 @@ public TPTGearsOfWarQueryFbTest(TPTGearsOfWarQueryFbFixture fixture) : base(fixture) { } + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task ToString_boolean_property_non_nullable(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Select(w => w.IsAutomatic.ToString()), elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.OrdinalIgnoreCase)); }); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task ToString_boolean_property_nullable(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Select(lh => lh.Eradicated.ToString()), elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.OrdinalIgnoreCase)); }); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Group_by_on_StartsWith_with_null_parameter_as_argument(bool async) + { + return base.Group_by_on_StartsWith_with_null_parameter_as_argument(async); + } + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] public override Task Correlated_collections_inner_subquery_predicate_references_outer_qsre(bool async) @@ -297,41 +321,46 @@ public override Task First_on_byte_array(bool async) return base.First_on_byte_array(async); } - [Theory] + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override Task ToString_boolean_property_nullable(bool async) + public override Task Where_TimeOnly_subtract_TimeOnly(bool async) { - return AssertQuery(async, (ISetSource ss) => from lh in ss.Set() - select ((object)lh.Eradicated).ToString(), null, elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.InvariantCultureIgnoreCase)); }, assertOrder: false, 0, "ToString_boolean_property_nullable"); + return base.Where_TimeOnly_subtract_TimeOnly(async); } - [Theory] + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override Task ToString_boolean_property_non_nullable(bool async) + public override Task Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(bool async) { - return AssertQuery(async, (ISetSource ss) => from w in ss.Set() - select w.IsAutomatic.ToString(), null, elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.InvariantCultureIgnoreCase)); }, assertOrder: false, 0, "ToString_boolean_property_non_nullable"); + return base.Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); } [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override Task Where_TimeOnly_subtract_TimeOnly(bool async) + public override Task DateTimeOffsetNow_minus_timespan(bool async) { - return base.Where_TimeOnly_subtract_TimeOnly(async); + return base.DateTimeOffsetNow_minus_timespan(async); } [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override Task Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(bool async) + public override Task Subquery_inside_Take_argument(bool async) { - return base.Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); + return base.Subquery_inside_Take_argument(async); } - [NotSupportedOnFirebirdTheory] + [NotSupportedByProviderTheory] [MemberData(nameof(IsAsyncData))] - public override Task DateTimeOffsetNow_minus_timespan(bool async) + public override Task DateTimeOffset_to_unix_time_milliseconds(bool async) { - return base.DateTimeOffsetNow_minus_timespan(async); + return base.DateTimeOffset_to_unix_time_milliseconds(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task DateTimeOffset_to_unix_time_seconds(bool async) + { + return base.DateTimeOffset_to_unix_time_seconds(async); } [Theory(Skip = "NETProvider#1008")] @@ -347,4 +376,11 @@ public override Task Where_TimeOnly_Add_TimeSpan(bool async) { return base.Where_TimeOnly_Add_TimeSpan(async); } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task String_concat_with_null_conditional_argument(bool async) + { + return base.String_concat_with_null_conditional_argument(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTInheritanceQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTInheritanceQueryFbTest.cs index c7e3a46a4..f6fa61657 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTInheritanceQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTInheritanceQueryFbTest.cs @@ -16,12 +16,13 @@ //$Authors = Jiri Cincura (jiri@cincura.net) using Microsoft.EntityFrameworkCore.Query; +using Xunit.Abstractions; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class TPTInheritanceQueryFbTest : TPTInheritanceQueryTestBase { - public TPTInheritanceQueryFbTest(TPTInheritanceQueryFbFixture fixture) - : base(fixture) + public TPTInheritanceQueryFbTest(TPTInheritanceQueryFbFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture, testOutputHelper) { } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/UdfDbFunctionFbTests.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/UdfDbFunctionFbTests.cs index 7d201a95d..fc05c2bf5 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/UdfDbFunctionFbTests.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/UdfDbFunctionFbTests.cs @@ -176,18 +176,6 @@ public override void QF_CrossJoin_Parameter() base.QF_CrossJoin_Parameter(); } - [Fact(Skip = "efcore#24228")] - public override void Nullable_navigation_property_access_preserves_schema_for_sql_function() - { - base.Nullable_navigation_property_access_preserves_schema_for_sql_function(); - } - - [Fact(Skip = "efcore#24228")] - public override void Compare_function_without_null_propagation_to_null() - { - base.Compare_function_without_null_propagation_to_null(); - } - protected class FbUDFSqlContext : UDFSqlContext { public FbUDFSqlContext(DbContextOptions options) @@ -319,6 +307,47 @@ returns boolean return true; end"); + context.Database.ExecuteSqlRaw( + @"create procedure ""GetTopTwoSellingProducts"" + returns + ( + ""ProductId"" int not null, + ""AmountSold"" int + ) + as + begin + for select first 2 ""ProductId"", sum(""Quantity"") as ""TotalSold"" + from ""LineItem"" + group by ""ProductId"" + order by ""TotalSold"" desc + into :""ProductId"", :""AmountSold"" do + begin + suspend; + end + end"); + + context.Database.ExecuteSqlRaw( + @"create procedure ""GetOrdersWithMultipleProducts""(customerId int) + returns + ( + ""OrderId"" int not null, + ""CustomerId"" int not null, + ""OrderDate"" timestamp + ) + as + begin + for select o.""Id"", :customerId, ""OrderDate"" + from ""Orders"" o + join ""LineItem"" li on o.""Id"" = li.""OrderId"" + where o.""CustomerId"" = :customerId + group by o.""Id"", ""OrderDate"" + having count(""ProductId"") > 1 + into :""OrderId"", :""CustomerId"", :""OrderDate"" do + begin + suspend; + end + end"); + context.SaveChanges(); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj index bc068fe0d..ce3ed3f3b 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj @@ -18,7 +18,6 @@ - diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/Migrations/MigrationsTests.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/Migrations/MigrationsTests.cs index cc9aaf8a9..eabcd1bcc 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/Migrations/MigrationsTests.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/Migrations/MigrationsTests.cs @@ -624,7 +624,20 @@ public async Task RestartSequence() }; var batch = await Generate(new[] { operation }); Assert.AreEqual(1, batch.Count()); - Assert.AreEqual(NewLineEnd(@"ALTER SEQUENCE ""MySequence"" START WITH 23;"), batch[0].CommandText); + Assert.AreEqual(NewLineEnd(@"ALTER SEQUENCE ""MySequence"" RESTART WITH 23;"), batch[0].CommandText); + } + + [Test] + public async Task RestartSequenceNoValue() + { + var operation = new RestartSequenceOperation() + { + Name = "MySequence", + StartValue = null, + }; + var batch = await Generate(new[] { operation }); + Assert.AreEqual(1, batch.Count()); + Assert.AreEqual(NewLineEnd(@"ALTER SEQUENCE ""MySequence"" RESTART;"), batch[0].CommandText); } [Test] diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyExtensions.cs index 85ab07c86..dc76ff76f 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyExtensions.cs @@ -41,7 +41,7 @@ public static FbValueGenerationStrategy GetValueGenerationStrategy(this IPropert return FbValueGenerationStrategy.None; } - var modelStrategy = property.DeclaringEntityType.Model.GetValueGenerationStrategy(); + var modelStrategy = property.DeclaringType.Model.GetValueGenerationStrategy(); if (modelStrategy == FbValueGenerationStrategy.SequenceTrigger && IsCompatibleSequenceTrigger(property)) { @@ -49,7 +49,7 @@ public static FbValueGenerationStrategy GetValueGenerationStrategy(this IPropert } if (modelStrategy == FbValueGenerationStrategy.IdentityColumn) { - if (property.DeclaringEntityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) + if (property.DeclaringType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) { return FbValueGenerationStrategy.SequenceTrigger; } @@ -83,7 +83,7 @@ public static FbValueGenerationStrategy GetValueGenerationStrategy(this IMutable return FbValueGenerationStrategy.None; } - var modelStrategy = property.DeclaringEntityType.Model.GetValueGenerationStrategy(); + var modelStrategy = property.DeclaringType.Model.GetValueGenerationStrategy(); if (modelStrategy == FbValueGenerationStrategy.SequenceTrigger && IsCompatibleSequenceTrigger(property)) { @@ -91,7 +91,7 @@ public static FbValueGenerationStrategy GetValueGenerationStrategy(this IMutable } if (modelStrategy == FbValueGenerationStrategy.IdentityColumn) { - if (property.DeclaringEntityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) + if (property.DeclaringType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) { return FbValueGenerationStrategy.SequenceTrigger; } @@ -125,7 +125,7 @@ public static FbValueGenerationStrategy GetValueGenerationStrategy(this IConvent return FbValueGenerationStrategy.None; } - var modelStrategy = property.DeclaringEntityType.Model.GetValueGenerationStrategy(); + var modelStrategy = property.DeclaringType.Model.GetValueGenerationStrategy(); if (modelStrategy == FbValueGenerationStrategy.SequenceTrigger && IsCompatibleSequenceTrigger(property)) { @@ -133,7 +133,7 @@ public static FbValueGenerationStrategy GetValueGenerationStrategy(this IConvent } if (modelStrategy == FbValueGenerationStrategy.IdentityColumn) { - if (property.DeclaringEntityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) + if (property.DeclaringType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) { return FbValueGenerationStrategy.SequenceTrigger; } @@ -231,7 +231,7 @@ public static string SetHiLoSequenceSchema(this IConventionProperty property, st public static IReadOnlySequence FindHiLoSequence(this IReadOnlyProperty property) { - var model = property.DeclaringEntityType.Model; + var model = property.DeclaringType.Model; var sequenceName = property.GetHiLoSequenceName() ?? model.GetHiLoSequenceName(); @@ -244,7 +244,7 @@ public static IReadOnlySequence FindHiLoSequence(this IReadOnlyProperty property public static IReadOnlySequence FindHiLoSequence(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject) { - var model = property.DeclaringEntityType.Model; + var model = property.DeclaringType.Model; var sequenceName = property.GetHiLoSequenceName(storeObject) ?? model.GetHiLoSequenceName(); @@ -329,7 +329,7 @@ public static string SetSequenceSchema(this IConventionProperty property, string public static IReadOnlySequence FindSequence(this IReadOnlyProperty property) { - var model = property.DeclaringEntityType.Model; + var model = property.DeclaringType.Model; var sequenceName = property.GetSequenceName() ?? model.GetSequenceNameSuffix(); @@ -342,7 +342,7 @@ public static IReadOnlySequence FindSequence(this IReadOnlyProperty property) public static IReadOnlySequence FindSequence(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject) { - var model = property.DeclaringEntityType.Model; + var model = property.DeclaringType.Model; var sequenceName = property.GetSequenceName(storeObject) ?? model.GetSequenceNameSuffix(); diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbServiceCollectionExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbServiceCollectionExtensions.cs index 505eeb563..787148fff 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbServiceCollectionExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbServiceCollectionExtensions.cs @@ -78,6 +78,7 @@ public static IServiceCollection AddEntityFrameworkFirebird(this IServiceCollect .TryAdd() .TryAdd() .TryAdd() + .TryAdd() .TryAdd() .TryAdd(p => p.GetService()) .TryAdd() diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj index b67d78537..69d85f5c2 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj @@ -1,6 +1,6 @@  - net6.0 + net8.0 FirebirdSql.EntityFrameworkCore.Firebird FirebirdSql.EntityFrameworkCore.Firebird true @@ -9,6 +9,7 @@ true + $(EFCoreProviderVersion) NETProvider - Entity Framework Core Provider (c) 2017-$(CopyrightEndYear) @@ -29,9 +30,12 @@ - + - + + + + diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs index fb0b3f91a..746b65945 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs @@ -272,8 +272,12 @@ protected override void Generate(RestartSequenceOperation operation, IModel mode { builder.Append("ALTER SEQUENCE "); builder.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name, operation.Schema)); - builder.Append(" START WITH "); - builder.Append(operation.StartValue.ToString(CultureInfo.InvariantCulture)); + builder.Append(" RESTART"); + if (operation.StartValue != null) + { + builder.Append(" WITH "); + builder.Append(((long)operation.StartValue).ToString(CultureInfo.InvariantCulture)); + } TerminateStatement(builder); } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbDateOnlyMethodTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbDateOnlyMethodTranslator.cs new file mode 100644 index 000000000..05dd34f40 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbDateOnlyMethodTranslator.cs @@ -0,0 +1,66 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.Query.ExpressionTranslators.Internal; + +public class SqlServerDateOnlyMethodTranslator : IMethodCallTranslator +{ + readonly Dictionary _methodInfoDatePartMapping = new() + { + { typeof(DateOnly).GetRuntimeMethod(nameof(DateOnly.AddYears), [typeof(int)]), "year" }, + { typeof(DateOnly).GetRuntimeMethod(nameof(DateOnly.AddMonths), [typeof(int)]), "month" }, + { typeof(DateOnly).GetRuntimeMethod(nameof(DateOnly.AddDays), [typeof(int)]), "day" } + }; + + readonly ISqlExpressionFactory _sqlExpressionFactory; + + public SqlServerDateOnlyMethodTranslator(ISqlExpressionFactory sqlExpressionFactory) + { + _sqlExpressionFactory = sqlExpressionFactory; + } + + public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList arguments, IDiagnosticsLogger logger) + { + if (_methodInfoDatePartMapping.TryGetValue(method, out var datePart) && instance != null) + { + instance = _sqlExpressionFactory.ApplyDefaultTypeMapping(instance); + + return _sqlExpressionFactory.Function( + "DATEADD", + new[] { _sqlExpressionFactory.Fragment(datePart), _sqlExpressionFactory.Convert(arguments[0], typeof(int)), instance }, + nullable: true, + argumentsPropagateNullability: new[] { false, true, true }, + instance.Type, + instance.TypeMapping); + } + + if (method.DeclaringType == typeof(DateOnly) && method.Name == nameof(DateOnly.FromDateTime) && arguments.Count == 1) + { + return _sqlExpressionFactory.Convert(arguments[0], typeof(DateOnly)); + } + + return null; + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringContainsTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringContainsTranslator.cs index 87ec77169..bc1905ad9 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringContainsTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringContainsTranslator.cs @@ -50,14 +50,15 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadO new[] { true, true }, typeof(int)), _fbSqlExpressionFactory.Constant(0)); - return patternExpression is SqlConstantExpression sqlConstantExpression + var matchingExpression = patternExpression is SqlConstantExpression sqlConstantExpression ? ((string)sqlConstantExpression.Value)?.Length == 0 ? (SqlExpression)_fbSqlExpressionFactory.Constant(true) - : positionExpression + : (SqlExpression)positionExpression : _fbSqlExpressionFactory.OrElse( positionExpression, _fbSqlExpressionFactory.Equal( _fbSqlExpressionFactory.Function("CHAR_LENGTH", new[] { patternExpression }, true, new[] { true }, typeof(int)), _fbSqlExpressionFactory.Constant(0))); + return _fbSqlExpressionFactory.AndAlso(matchingExpression, _fbSqlExpressionFactory.AndAlso(_fbSqlExpressionFactory.IsNotNull(instance), _fbSqlExpressionFactory.IsNotNull(patternExpression))); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringEndsWithTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringEndsWithTranslator.cs index a0353c0d6..0ddb1cdb1 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringEndsWithTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringEndsWithTranslator.cs @@ -57,14 +57,13 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadO new[] { true, true }, instance.Type)), patternExpression); - return patternExpression is SqlConstantExpression sqlConstantExpression - ? (string)sqlConstantExpression.Value == string.Empty - ? (SqlExpression)_fbSqlExpressionFactory.Constant(true) - : endsWithExpression - : _fbSqlExpressionFactory.OrElse( + var matchingExpression = patternExpression is SqlConstantExpression sqlConstantExpression + ? (SqlExpression)((string)sqlConstantExpression.Value == string.Empty ? (SqlExpression)_fbSqlExpressionFactory.Constant(true) : endsWithExpression) + : (SqlExpression)_fbSqlExpressionFactory.OrElse( endsWithExpression, _fbSqlExpressionFactory.Equal( _fbSqlExpressionFactory.Function("CHAR_LENGTH", new[] { patternExpression }, true, new[] { true }, typeof(int)), _fbSqlExpressionFactory.Constant(0))); + return _fbSqlExpressionFactory.AndAlso(matchingExpression, _fbSqlExpressionFactory.AndAlso(_fbSqlExpressionFactory.IsNotNull(instance), _fbSqlExpressionFactory.IsNotNull(patternExpression))); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringStartsWithTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringStartsWithTranslator.cs index b89294c30..0608835be 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringStartsWithTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringStartsWithTranslator.cs @@ -65,14 +65,13 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadO new[] { true, true }, instance.Type)), patternExpression)); - return patternConstantExpression != null - ? (string)patternConstantExpression.Value == string.Empty - ? _fbSqlExpressionFactory.Constant(true) - : startsWithExpression - : _fbSqlExpressionFactory.OrElse( + var matchingExpression = patternConstantExpression != null + ? (SqlExpression)((string)patternConstantExpression.Value == string.Empty ? _fbSqlExpressionFactory.Constant(true) : startsWithExpression) + : (SqlExpression)_fbSqlExpressionFactory.OrElse( startsWithExpression, _fbSqlExpressionFactory.Equal( _fbSqlExpressionFactory.Function("CHAR_LENGTH", new[] { patternExpression }, true, new[] { true }, typeof(int)), _fbSqlExpressionFactory.Constant(0))); + return _fbSqlExpressionFactory.AndAlso(matchingExpression, _fbSqlExpressionFactory.AndAlso(_fbSqlExpressionFactory.IsNotNull(instance), _fbSqlExpressionFactory.IsNotNull(patternExpression))); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryRootProcessor.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryRootProcessor.cs new file mode 100644 index 000000000..495717e39 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryRootProcessor.cs @@ -0,0 +1,33 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Query; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.Query.Internal; + +public class FbQueryRootProcessor : RelationalQueryRootProcessor +{ + public FbQueryRootProcessor(QueryTranslationPreprocessorDependencies dependencies, RelationalQueryTranslationPreprocessorDependencies relationalDependencies, QueryCompilationContext queryCompilationContext) + : base(dependencies, relationalDependencies, queryCompilationContext) + { } + + protected override bool ShouldConvertToParameterQueryRoot(ParameterExpression constantExpression) + { + return false; + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs index 51268e4f3..c8f203bff 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs @@ -65,31 +65,64 @@ protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpres Sql.Append(")"); return sqlBinaryExpression; } - else if (sqlBinaryExpression.OperatorType == ExpressionType.And && sqlBinaryExpression.TypeMapping.ClrType != typeof(bool)) + else if (sqlBinaryExpression.OperatorType == ExpressionType.And) { - Sql.Append("BIN_AND("); - Visit(sqlBinaryExpression.Left); - Sql.Append(", "); - Visit(sqlBinaryExpression.Right); - Sql.Append(")"); + if (sqlBinaryExpression.TypeMapping.ClrType == typeof(bool)) + { + Sql.Append("IIF(BIN_AND("); + BooleanToIntegralAndVisit(sqlBinaryExpression.Left); + Sql.Append(", "); + BooleanToIntegralAndVisit(sqlBinaryExpression.Right); + Sql.Append(") = 0, FALSE, TRUE)"); + } + else + { + Sql.Append("BIN_AND("); + Visit(sqlBinaryExpression.Left); + Sql.Append(", "); + Visit(sqlBinaryExpression.Right); + Sql.Append(")"); + } return sqlBinaryExpression; } - else if (sqlBinaryExpression.OperatorType == ExpressionType.Or && sqlBinaryExpression.TypeMapping.ClrType != typeof(bool)) + else if (sqlBinaryExpression.OperatorType == ExpressionType.Or) { - Sql.Append("BIN_OR("); - Visit(sqlBinaryExpression.Left); - Sql.Append(", "); - Visit(sqlBinaryExpression.Right); - Sql.Append(")"); + if (sqlBinaryExpression.TypeMapping.ClrType == typeof(bool)) + { + Sql.Append("IIF(BIN_OR("); + BooleanToIntegralAndVisit(sqlBinaryExpression.Left); + Sql.Append(", "); + BooleanToIntegralAndVisit(sqlBinaryExpression.Right); + Sql.Append(") = 0, FALSE, TRUE)"); + } + else + { + Sql.Append("BIN_OR("); + Visit(sqlBinaryExpression.Left); + Sql.Append(", "); + Visit(sqlBinaryExpression.Right); + Sql.Append(")"); + } return sqlBinaryExpression; } else if (sqlBinaryExpression.OperatorType == ExpressionType.ExclusiveOr) { - Sql.Append("BIN_XOR("); - Visit(sqlBinaryExpression.Left); - Sql.Append(", "); - Visit(sqlBinaryExpression.Right); - Sql.Append(")"); + if (sqlBinaryExpression.TypeMapping.ClrType == typeof(bool)) + { + Sql.Append("IIF(BIN_XOR("); + BooleanToIntegralAndVisit(sqlBinaryExpression.Left); + Sql.Append(", "); + BooleanToIntegralAndVisit(sqlBinaryExpression.Right); + Sql.Append(") = 0, FALSE, TRUE)"); + } + else + { + Sql.Append("BIN_XOR("); + Visit(sqlBinaryExpression.Left); + Sql.Append(", "); + Visit(sqlBinaryExpression.Right); + Sql.Append(")"); + } return sqlBinaryExpression; } else if (sqlBinaryExpression.OperatorType == ExpressionType.LeftShift) @@ -114,6 +147,13 @@ protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpres { return base.VisitSqlBinary(sqlBinaryExpression); } + + void BooleanToIntegralAndVisit(SqlExpression expression) + { + Sql.Append("IIF("); + Visit(expression); + Sql.Append(", 1, 0)"); + } } protected override Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryTranslationPreprocessor.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryTranslationPreprocessor.cs new file mode 100644 index 000000000..d95a444af --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryTranslationPreprocessor.cs @@ -0,0 +1,34 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Query; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.Query.Internal; + +public class FbQueryTranslationPreprocessor : RelationalQueryTranslationPreprocessor +{ + public FbQueryTranslationPreprocessor(QueryTranslationPreprocessorDependencies dependencies, RelationalQueryTranslationPreprocessorDependencies relationalDependencies, QueryCompilationContext queryCompilationContext) + : base(dependencies, relationalDependencies, queryCompilationContext) + { } + + protected override Expression ProcessQueryRoots(Expression expression) + { + return new FbQueryRootProcessor(Dependencies, RelationalDependencies, QueryCompilationContext) + .Visit(expression); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryTranslationPreprocessorFactory.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryTranslationPreprocessorFactory.cs new file mode 100644 index 000000000..ebc6092e0 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQueryTranslationPreprocessorFactory.cs @@ -0,0 +1,37 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using Microsoft.EntityFrameworkCore.Query; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.Query.Internal; + +public class FbQueryTranslationPreprocessorFactory : IQueryTranslationPreprocessorFactory +{ + readonly QueryTranslationPreprocessorDependencies _dependecies; + readonly RelationalQueryTranslationPreprocessorDependencies _relationalDependencies; + + public FbQueryTranslationPreprocessorFactory(QueryTranslationPreprocessorDependencies dependecies, RelationalQueryTranslationPreprocessorDependencies relationalDependencies) + { + _dependecies = dependecies; + _relationalDependencies = relationalDependencies; + } + + public QueryTranslationPreprocessor Create(QueryCompilationContext queryCompilationContext) + { + return new FbQueryTranslationPreprocessor(_dependecies, _relationalDependencies, queryCompilationContext); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbTypeMappingSource.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbTypeMappingSource.cs index e4d85de9c..9e41a9efb 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbTypeMappingSource.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbTypeMappingSource.cs @@ -168,7 +168,7 @@ RelationalTypeMapping FindRawMapping(RelationalTypeMappingInfo mappingInfo) var size = mappingInfo.Size ?? (mappingInfo.IsKeyOrIndex ? 256 : (int?)null); var maxSize = isUnicode ? UnicodeVarcharMaxSize : VarcharMaxSize; - if (size > maxSize) + if (size < 0 || size > maxSize) { size = isFixedLength ? maxSize : (int?)null; } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorCache.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorCache.cs index 1eb45a3a5..7c7137519 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorCache.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorCache.cs @@ -33,7 +33,7 @@ public FbValueGeneratorCache(ValueGeneratorCacheDependencies dependencies) public virtual FbSequenceValueGeneratorState GetOrAddSequenceState(IProperty property, IRelationalConnection connection) { - var tableIdentifier = StoreObjectIdentifier.Create(property.DeclaringEntityType, StoreObjectType.Table); + var tableIdentifier = StoreObjectIdentifier.Create(property.DeclaringType, StoreObjectType.Table); var sequence = tableIdentifier != null ? property.FindHiLoSequence(tableIdentifier.Value) : property.FindHiLoSequence(); diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorSelector.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorSelector.cs index 7f80548f4..dd01a34dc 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorSelector.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorSelector.cs @@ -44,7 +44,7 @@ public FbValueGeneratorSelector(ValueGeneratorSelectorDependencies dependencies, public new virtual IFbValueGeneratorCache Cache => (IFbValueGeneratorCache)base.Cache; - public override ValueGenerator Select(IProperty property, IEntityType entityType) + public override ValueGenerator Select(IProperty property, ITypeBase entityType) { if (property.GetValueGeneratorFactory() != null || property.GetValueGenerationStrategy() != FbValueGenerationStrategy.HiLo) @@ -87,10 +87,10 @@ public override ValueGenerator Select(IProperty property, IEntityType entityType throw new ArgumentException( CoreStrings.InvalidValueGeneratorFactoryProperty( - nameof(FbSequenceValueGeneratorFactory), property.Name, property.DeclaringEntityType.DisplayName())); + nameof(FbSequenceValueGeneratorFactory), property.Name, property.DeclaringType.DisplayName())); } - protected override ValueGenerator FindForType(IProperty property, IEntityType entityType, Type clrType) + protected override ValueGenerator FindForType(IProperty property, ITypeBase entityType, Type clrType) => property.ClrType.UnwrapNullableType() == typeof(Guid) ? property.ValueGenerated == ValueGenerated.Never || property.GetDefaultValueSql() != null ? new TemporaryGuidValueGenerator() diff --git a/src/NETProvider.sln b/src/NETProvider.sln index c7e674105..6c41c6e38 100644 --- a/src/NETProvider.sln +++ b/src/NETProvider.sln @@ -27,6 +27,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C68C23A7-AACE-4335-88F8-1060EDAB2131}" ProjectSection(SolutionItems) = preProject Directory.Build.props = Directory.Build.props + Versions.props = Versions.props EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests", "FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests\FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj", "{2925DB97-5B39-4D9E-90CC-F7470F9AA8F3}" @@ -39,7 +40,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Perf", "Perf", "{CE2BB2BB-4 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scratchpad", "Scratchpad", "{5F1D1BB9-4657-424C-B3DE-75818824940E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scratchpad", "Scratchpad\Scratchpad.csproj", "{C3F47B3D-FA1F-4665-A58D-63B6FFDCD65F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scratchpad", "Scratchpad\Scratchpad.csproj", "{C3F47B3D-FA1F-4665-A58D-63B6FFDCD65F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Versions.props b/src/Versions.props new file mode 100644 index 000000000..1f220849b --- /dev/null +++ b/src/Versions.props @@ -0,0 +1,18 @@ + + + + 10.0.0 + + + + 11.0.0-beta2 + 10.0.0 + 8.0.4 + + + + 10.0.0 + 10.0.0 + 6.4.4 + + diff --git a/tests.ps1 b/tests.ps1 index 391a9bee3..b293410ca 100644 --- a/tests.ps1 +++ b/tests.ps1 @@ -29,8 +29,9 @@ $FirebirdConfiguration = @{ } } +$frameworkVersion = 'net8.0' $testsBaseDir = "$baseDir\src\FirebirdSql.Data.FirebirdClient.Tests" -$testsProviderDir = "$testsBaseDir\bin\$Configuration\$(Get-UsedTargetFramework)" +$testsProviderDir = "$testsBaseDir\bin\$Configuration\$frameworkVersion" $firebirdProcess = $null @@ -131,7 +132,7 @@ function Tests-FirebirdClient($serverType, $compression, $wireCrypt) { } function Tests-EF6() { - pushd "$baseDir\src\EntityFramework.Firebird.Tests\bin\$Configuration\$(Get-UsedTargetFramework)" + pushd "$baseDir\src\EntityFramework.Firebird.Tests\bin\$Configuration\$frameworkVersion" try { .\EntityFramework.Firebird.Tests.exe --labels=All Check-ExitCode @@ -142,7 +143,7 @@ function Tests-EF6() { } function Tests-EFCore() { - pushd "$baseDir\src\FirebirdSql.EntityFrameworkCore.Firebird.Tests\bin\$Configuration\$(Get-UsedTargetFramework)" + pushd "$baseDir\src\FirebirdSql.EntityFrameworkCore.Firebird.Tests\bin\$Configuration\$frameworkVersion" try { .\FirebirdSql.EntityFrameworkCore.Firebird.Tests.exe --labels=All Check-ExitCode From bbd0dd2b08942dc505b222b1122cc74635910e88 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Tue, 21 May 2024 20:16:11 +0200 Subject: [PATCH 11/27] Bump versions --- src/Versions.props | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Versions.props b/src/Versions.props index 1f220849b..25f775271 100644 --- a/src/Versions.props +++ b/src/Versions.props @@ -1,18 +1,18 @@ - 10.0.0 + 10.1.0 - 11.0.0-beta2 - 10.0.0 + 11.0.0 + 10.1.0 8.0.4 - 10.0.0 - 10.0.0 + 10.0.1 + 10.1.0 6.4.4 From 1db20a0fbd502ea09b00156a0edbb01571534997 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Mon, 27 May 2024 09:14:57 +0200 Subject: [PATCH 12/27] Support for isc_spb_bkp_zip (#1171). --- .../FbServicesTests.cs | 20 +++++++++++++++++-- .../Services/FbBackupFlags.cs | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs b/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs index 96f388234..b0e9e483d 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs @@ -60,6 +60,22 @@ public async Task BackupRestoreTest() await Connection.CloseAsync(); } + [Test] + public async Task BackupRestoreZipTest() + { + if (!EnsureServerVersionAtLeast(new Version(4, 0, 0, 0))) + return; + + var backupName = $"{Guid.NewGuid()}.bak"; + var csb = BuildServicesConnectionStringBuilder(ServerType, Compression, WireCrypt, true); + var connectionString = csb.ToString(); + await BackupPartHelper(backupName, connectionString, FbBackupFlags.Zip); + await RestorePartHelper(backupName, connectionString); + // test the database was actually restored fine + await Connection.OpenAsync(); + await Connection.CloseAsync(); + } + [Test] public async Task BackupRestoreParallelTest() { @@ -453,11 +469,11 @@ public async Task NFixupTest() Assert.DoesNotThrowAsync(() => Connection.OpenAsync()); } - static Task BackupPartHelper(string backupName, string connectionString) + static Task BackupPartHelper(string backupName, string connectionString, FbBackupFlags backupFlags = FbBackupFlags.IgnoreLimbo) { var backupSvc = new FbBackup(); backupSvc.ConnectionString = connectionString; - backupSvc.Options = FbBackupFlags.IgnoreLimbo; + backupSvc.Options = backupFlags; backupSvc.BackupFiles.Add(new FbBackupFile(backupName, 2048)); backupSvc.Verbose = true; backupSvc.Statistics = FbBackupRestoreStatistics.TotalTime | FbBackupRestoreStatistics.TimeDelta; diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbBackupFlags.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbBackupFlags.cs index 73bb8873a..1c17c9f35 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbBackupFlags.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbBackupFlags.cs @@ -33,4 +33,5 @@ public enum FbBackupFlags Convert = IscCodes.isc_spb_bkp_convert, Expand = IscCodes.isc_spb_bkp_expand, NoDatabaseTriggers = IscCodes.isc_spb_bkp_no_triggers, + Zip = IscCodes.isc_spb_bkp_zip, } From e3bd67475b23eedd08af67f0e7ad9f0177acec56 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Mon, 27 May 2024 20:49:48 +0200 Subject: [PATCH 13/27] Bump version --- src/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Versions.props b/src/Versions.props index 25f775271..2dc2a9d06 100644 --- a/src/Versions.props +++ b/src/Versions.props @@ -1,7 +1,7 @@ - 10.1.0 + 10.2.0 From 73b0082bd253efb6e46cdb28b4f558632f431815 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Tue, 28 May 2024 14:22:29 +0200 Subject: [PATCH 14/27] Update docs --- docs/entity-framework-core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/entity-framework-core.md b/docs/entity-framework-core.md index e14899156..e5b2a5c30 100644 --- a/docs/entity-framework-core.md +++ b/docs/entity-framework-core.md @@ -1,4 +1,4 @@ -# Entity Framework Core 7.x +# Entity Framework Core 8.x * Install `FirebirdSql.EntityFrameworkCore.Firebird` from NuGet. * Create your `DbContext`. From 70ca5721086d8c91c2bd3c71ec0d4fb708151b72 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Sun, 9 Jun 2024 19:15:43 +0200 Subject: [PATCH 15/27] Implement verbint --- .../FbServicesTests.cs | 37 +++++++++++++++++-- .../Services/FbBackup.cs | 3 ++ .../Services/FbRestore.cs | 3 ++ .../Services/FbStreamingRestore.cs | 5 ++- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs b/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs index b0e9e483d..1213dcf20 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs @@ -69,13 +69,40 @@ public async Task BackupRestoreZipTest() var backupName = $"{Guid.NewGuid()}.bak"; var csb = BuildServicesConnectionStringBuilder(ServerType, Compression, WireCrypt, true); var connectionString = csb.ToString(); - await BackupPartHelper(backupName, connectionString, FbBackupFlags.Zip); + await BackupPartHelper(backupName, connectionString, x => + { + x.Options |= FbBackupFlags.Zip; + }); await RestorePartHelper(backupName, connectionString); // test the database was actually restored fine await Connection.OpenAsync(); await Connection.CloseAsync(); } + [Test] + public async Task BackupRestoreVerbIntTest() + { + if (!EnsureServerVersionAtLeast(new Version(3, 0, 0, 0))) + return; + + var backupName = $"{Guid.NewGuid()}.bak"; + var csb = BuildServicesConnectionStringBuilder(ServerType, Compression, WireCrypt, true); + var connectionString = csb.ToString(); + await BackupPartHelper(backupName, connectionString, x => + { + x.Verbose = true; + x.VerboseInterval = 1_000_000; + }); + await RestorePartHelper(backupName, connectionString, x => + { + x.Verbose = true; + x.VerboseInterval = 1_000_000; + }); + // test the database was actually restored fine + await Connection.OpenAsync(); + await Connection.CloseAsync(); + } + [Test] public async Task BackupRestoreParallelTest() { @@ -469,18 +496,19 @@ public async Task NFixupTest() Assert.DoesNotThrowAsync(() => Connection.OpenAsync()); } - static Task BackupPartHelper(string backupName, string connectionString, FbBackupFlags backupFlags = FbBackupFlags.IgnoreLimbo) + static Task BackupPartHelper(string backupName, string connectionString, Action configure = null) { var backupSvc = new FbBackup(); backupSvc.ConnectionString = connectionString; - backupSvc.Options = backupFlags; + backupSvc.Options = FbBackupFlags.IgnoreLimbo; backupSvc.BackupFiles.Add(new FbBackupFile(backupName, 2048)); backupSvc.Verbose = true; backupSvc.Statistics = FbBackupRestoreStatistics.TotalTime | FbBackupRestoreStatistics.TimeDelta; backupSvc.ServiceOutput += ServiceOutput; + configure?.Invoke(backupSvc); return backupSvc.ExecuteAsync(); } - static Task RestorePartHelper(string backupName, string connectionString) + static Task RestorePartHelper(string backupName, string connectionString, Action configure = null) { var restoreSvc = new FbRestore(); restoreSvc.ConnectionString = connectionString; @@ -490,6 +518,7 @@ static Task RestorePartHelper(string backupName, string connectionString) restoreSvc.Statistics = FbBackupRestoreStatistics.TotalTime | FbBackupRestoreStatistics.TimeDelta; restoreSvc.BackupFiles.Add(new FbBackupFile(backupName, 2048)); restoreSvc.ServiceOutput += ServiceOutput; + configure?.Invoke(restoreSvc); return restoreSvc.ExecuteAsync(); } diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs index 9d1768aa6..8aff08991 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs @@ -28,6 +28,7 @@ public sealed class FbBackup : FbService { public FbBackupFileCollection BackupFiles { get; } public bool Verbose { get; set; } + public int? VerboseInterval { get; set; } public int Factor { get; set; } public string SkipData { get; set; } public FbBackupFlags Options { get; set; } @@ -59,6 +60,8 @@ public void Execute() } if (Verbose) startSpb.Append(IscCodes.isc_spb_verbose); + if (VerboseInterval.HasValue) + startSpb.Append(IscCodes.isc_spb_verbint, (int)VerboseInterval); if (Factor > 0) startSpb.Append(IscCodes.isc_spb_bkp_factor, Factor); if (!string.IsNullOrEmpty(SkipData)) diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs index ce06317b2..6bd335d15 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs @@ -41,6 +41,7 @@ public int? PageSize public FbBackupFileCollection BackupFiles { get; } public bool Verbose { get; set; } + public int? VerboseInterval { get; set; } public int? PageBuffers { get; set; } public bool ReadOnly { get; set; } public string SkipData { get; set; } @@ -71,6 +72,8 @@ public void Execute() startSpb.Append2(IscCodes.isc_spb_dbname, ConnectionStringOptions.Database); if (Verbose) startSpb.Append(IscCodes.isc_spb_verbose); + if (VerboseInterval.HasValue) + startSpb.Append(IscCodes.isc_spb_verbint, (int)VerboseInterval); if (PageBuffers.HasValue) startSpb.Append(IscCodes.isc_spb_res_buffers, (int)PageBuffers); if (_pageSize.HasValue) diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs index a62a9a98f..2478a8ac5 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs @@ -45,6 +45,7 @@ public int? PageSize public Stream InputStream { get; set; } public bool Verbose { get; set; } + public int? VerboseInterval { get; set; } public int? PageBuffers { get; set; } public bool ReadOnly { get; set; } public string SkipData { get; set; } @@ -68,9 +69,9 @@ public void Execute() startSpb.Append2(IscCodes.isc_spb_bkp_file, "stdin"); startSpb.Append2(IscCodes.isc_spb_dbname, ConnectionStringOptions.Database); if (Verbose) - { startSpb.Append(IscCodes.isc_spb_verbose); - } + if (VerboseInterval.HasValue) + startSpb.Append(IscCodes.isc_spb_verbint, (int)VerboseInterval); if (PageBuffers.HasValue) startSpb.Append(IscCodes.isc_spb_res_buffers, (int)PageBuffers); if (_pageSize.HasValue) From 15aa93b7c985fbd277f652b2385027a850fccceb Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Sun, 9 Jun 2024 19:18:09 +0200 Subject: [PATCH 16/27] Bump version --- src/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Versions.props b/src/Versions.props index 2dc2a9d06..2cd424392 100644 --- a/src/Versions.props +++ b/src/Versions.props @@ -1,7 +1,7 @@ - 10.2.0 + 10.3.0 From 410bdbfedd898e83726c5ffb7af7b0d89b6b4435 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Mon, 10 Jun 2024 08:53:23 +0200 Subject: [PATCH 17/27] Fix output for verbint. --- .../FbServicesTests.cs | 4 ++-- src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs | 6 ++++-- src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs | 6 ++++-- .../Services/FbStreamingRestore.cs | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs b/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs index 1213dcf20..d667f2c48 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FbServicesTests.cs @@ -90,12 +90,12 @@ public async Task BackupRestoreVerbIntTest() var connectionString = csb.ToString(); await BackupPartHelper(backupName, connectionString, x => { - x.Verbose = true; + x.Verbose = false; x.VerboseInterval = 1_000_000; }); await RestorePartHelper(backupName, connectionString, x => { - x.Verbose = true; + x.Verbose = false; x.VerboseInterval = 1_000_000; }); // test the database was actually restored fine diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs index 8aff08991..35c833877 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs @@ -71,7 +71,7 @@ public void Execute() if (ConnectionStringOptions.ParallelWorkers > 0) startSpb.Append(IscCodes.isc_spb_bkp_parallel_workers, ConnectionStringOptions.ParallelWorkers); StartTask(startSpb); - if (Verbose) + if (Verbose || VerboseInterval.HasValue) { ProcessServiceOutput(new ServiceParameterBuffer2(Service.ParameterBufferEncoding)); } @@ -106,6 +106,8 @@ public async Task ExecuteAsync(CancellationToken cancellationToken = default) } if (Verbose) startSpb.Append(IscCodes.isc_spb_verbose); + if (VerboseInterval.HasValue) + startSpb.Append(IscCodes.isc_spb_verbint, (int)VerboseInterval); if (Factor > 0) startSpb.Append(IscCodes.isc_spb_bkp_factor, Factor); if (!string.IsNullOrEmpty(SkipData)) @@ -115,7 +117,7 @@ public async Task ExecuteAsync(CancellationToken cancellationToken = default) if (ConnectionStringOptions.ParallelWorkers > 0) startSpb.Append(IscCodes.isc_spb_bkp_parallel_workers, ConnectionStringOptions.ParallelWorkers); await StartTaskAsync(startSpb, cancellationToken).ConfigureAwait(false); - if (Verbose) + if (Verbose || VerboseInterval.HasValue) { await ProcessServiceOutputAsync(new ServiceParameterBuffer2(Service.ParameterBufferEncoding), cancellationToken).ConfigureAwait(false); } diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs index 6bd335d15..b52c01c67 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs @@ -86,7 +86,7 @@ public void Execute() if (ConnectionStringOptions.ParallelWorkers > 0) startSpb.Append(IscCodes.isc_spb_res_parallel_workers, ConnectionStringOptions.ParallelWorkers); StartTask(startSpb); - if (Verbose) + if (Verbose || VerboseInterval.HasValue) { ProcessServiceOutput(new ServiceParameterBuffer2(Service.ParameterBufferEncoding)); } @@ -119,6 +119,8 @@ public async Task ExecuteAsync(CancellationToken cancellationToken = default) startSpb.Append2(IscCodes.isc_spb_dbname, ConnectionStringOptions.Database); if (Verbose) startSpb.Append(IscCodes.isc_spb_verbose); + if (VerboseInterval.HasValue) + startSpb.Append(IscCodes.isc_spb_verbint, (int)VerboseInterval); if (PageBuffers.HasValue) startSpb.Append(IscCodes.isc_spb_res_buffers, (int)PageBuffers); if (_pageSize.HasValue) @@ -131,7 +133,7 @@ public async Task ExecuteAsync(CancellationToken cancellationToken = default) if (ConnectionStringOptions.ParallelWorkers > 0) startSpb.Append(IscCodes.isc_spb_res_parallel_workers, ConnectionStringOptions.ParallelWorkers); await StartTaskAsync(startSpb, cancellationToken).ConfigureAwait(false); - if (Verbose) + if (Verbose || VerboseInterval.HasValue) { await ProcessServiceOutputAsync(new ServiceParameterBuffer2(Service.ParameterBufferEncoding), cancellationToken).ConfigureAwait(false); } diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs index 2478a8ac5..c5e676611 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs @@ -109,9 +109,9 @@ public async Task ExecuteAsync(CancellationToken cancellationToken = default) startSpb.Append2(IscCodes.isc_spb_bkp_file, "stdin"); startSpb.Append2(IscCodes.isc_spb_dbname, ConnectionStringOptions.Database); if (Verbose) - { startSpb.Append(IscCodes.isc_spb_verbose); - } + if (VerboseInterval.HasValue) + startSpb.Append(IscCodes.isc_spb_verbint, (int)VerboseInterval); if (PageBuffers.HasValue) startSpb.Append(IscCodes.isc_spb_res_buffers, (int)PageBuffers); if (_pageSize.HasValue) From 74a2c1b69dcb26e3865b7c5086eec07312024b52 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Mon, 10 Jun 2024 08:54:41 +0200 Subject: [PATCH 18/27] Fix async reading in FbStreamingRestore. --- .../Services/FbStreamingRestore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs index c5e676611..90f60389d 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbStreamingRestore.cs @@ -179,7 +179,7 @@ async Task ReadInputAsync(CancellationToken cancellationToken = default) if (requestedLength > 0) { var data = new byte[requestedLength]; - var read = InputStream.Read(data, 0, requestedLength); + var read = await InputStream.ReadAsync(data, 0, requestedLength).ConfigureAwait(false); if (read > 0) { Array.Resize(ref data, read); From a5356c6ae84e9da00e773bb2cd0e68ccfcfb0e7b Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Mon, 10 Jun 2024 09:13:01 +0200 Subject: [PATCH 19/27] Bump version --- src/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Versions.props b/src/Versions.props index 2cd424392..bb8ae97e4 100644 --- a/src/Versions.props +++ b/src/Versions.props @@ -1,7 +1,7 @@ - 10.3.0 + 10.3.1 From b84a28df2fa7856b293555cbeddd17ba6fdd11d4 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Wed, 10 Jul 2024 11:45:35 +0200 Subject: [PATCH 20/27] Fix tags for packages --- src/EntityFramework.Firebird/EntityFramework.Firebird.csproj | 2 +- .../FirebirdSql.Data.FirebirdClient.csproj | 2 +- .../FirebirdSql.EntityFrameworkCore.Firebird.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj b/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj index 8457ebd6e..7a028340b 100644 --- a/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj +++ b/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj @@ -17,7 +17,7 @@ EntityFramework.Firebird Firebird Entity Framework Provider The Entity Framework provider for Firebird enables you to develop .NET applications that connect to the Firebird database using Entity Framework. - firebird;firebirsql;firebirdclient;entityframewor;adonet;database + firebird firebirsql firebirdclient entityframewor adonet database EF6;TRACE diff --git a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj index 25dcfcbb1..afc849886 100644 --- a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj +++ b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj @@ -18,7 +18,7 @@ FirebirdSql.Data.FirebirdClient Firebird ADO.NET Data provider Firebird ADO.NET data provider - firebird;firebirsql;firebirdclient;adonet;database + firebird firebirsql firebirdclient adonet database README.md diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj index 69d85f5c2..a8f28a98d 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj @@ -17,7 +17,7 @@ FirebirdSql.EntityFrameworkCore.Firebird Firebird Entity Framework Core Provider The Entity Framework Core provider for Firebird enables you to develop .NET applications that connect to the Firebird database using Entity Framework Core. - firebird;firebirsql;firebirdclient;entityframeworkcore;adonet;database + firebird firebirsql firebirdclient entityframeworkcore adonet database EFCORE;TRACE From 9d572eab622398c483e2daa70ef8175ac6a76f66 Mon Sep 17 00:00:00 2001 From: Mark Junker Date: Thu, 11 Jul 2024 21:26:01 +0200 Subject: [PATCH 21/27] Use a ConcurrentDictionary to remember which calls did work (#1147) --- .../Client/Native/FbClientFactory.cs | 2 +- .../Client/Native/FesStatement.cs | 24 +++++++++++-------- .../Common/NativeHelpers.cs | 21 ++++++++++++---- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Client/Native/FbClientFactory.cs b/src/FirebirdSql.Data.FirebirdClient/Client/Native/FbClientFactory.cs index 98bc44bd8..c816d19a6 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Client/Native/FbClientFactory.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Client/Native/FbClientFactory.cs @@ -83,7 +83,7 @@ public static IFbClient Create(string dllName) { result = BuildFbClient(dllName); cache.Add(dllName, result); - ShutdownHelper.RegisterFbClientShutdown(() => NativeHelpers.CallIfExists(() => result.fb_shutdown(0, 0))); + ShutdownHelper.RegisterFbClientShutdown(() => NativeHelpers.CallIfExists(nameof(IFbClient.fb_shutdown), () => result.fb_shutdown(0, 0))); return result; } finally diff --git a/src/FirebirdSql.Data.FirebirdClient/Client/Native/FesStatement.cs b/src/FirebirdSql.Data.FirebirdClient/Client/Native/FesStatement.cs index 8d29d76db..6dc7de2fb 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Client/Native/FesStatement.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Client/Native/FesStatement.cs @@ -371,11 +371,13 @@ public override void Execute(int timeout, IDescriptorFiller descriptorFiller) descriptorFiller.Fill(_parameters, 0); ClearStatusVector(); - NativeHelpers.CallIfExists(() => - { - _database.FbClient.fb_dsql_set_timeout(_statusVector, ref _handle, (uint)timeout); - _database.ProcessStatusVector(_statusVector); - }); + NativeHelpers.CallIfExists( + nameof(IFbClient.fb_dsql_set_timeout), + () => + { + _database.FbClient.fb_dsql_set_timeout(_statusVector, ref _handle, (uint)timeout); + _database.ProcessStatusVector(_statusVector); + }); ClearStatusVector(); @@ -441,11 +443,13 @@ public override async ValueTask ExecuteAsync(int timeout, IDescriptorFiller desc await descriptorFiller.FillAsync(_parameters, 0, cancellationToken).ConfigureAwait(false); ClearStatusVector(); - NativeHelpers.CallIfExists(() => - { - _database.FbClient.fb_dsql_set_timeout(_statusVector, ref _handle, (uint)timeout); - _database.ProcessStatusVector(_statusVector); - }); + NativeHelpers.CallIfExists( + nameof(IFbClient.fb_dsql_set_timeout), + () => + { + _database.FbClient.fb_dsql_set_timeout(_statusVector, ref _handle, (uint)timeout); + _database.ProcessStatusVector(_statusVector); + }); ClearStatusVector(); diff --git a/src/FirebirdSql.Data.FirebirdClient/Common/NativeHelpers.cs b/src/FirebirdSql.Data.FirebirdClient/Common/NativeHelpers.cs index f3450e781..25d65ae9d 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Common/NativeHelpers.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Common/NativeHelpers.cs @@ -16,18 +16,31 @@ //$Authors = Jiri Cincura (jiri@cincura.net) using System; +using System.Collections.Concurrent; namespace FirebirdSql.Data.Common; internal static class NativeHelpers { - public static void CallIfExists(Action action) + private static readonly ConcurrentDictionary _cache = new ConcurrentDictionary(StringComparer.Ordinal); + + public static void CallIfExists(string actionId, Action action) { - try + if (!_cache.TryGetValue(actionId, out var executionAllowed)) + { + try + { + action(); + _cache.TryAdd(actionId, true); + } + catch (EntryPointNotFoundException) + { + _cache.TryAdd(actionId, false); + } + } + else if (executionAllowed) { action(); } - catch (EntryPointNotFoundException) - { } } } From 69502b38b29bfe186bdb739d6ce361bc28925293 Mon Sep 17 00:00:00 2001 From: Osman Yavuz Date: Mon, 15 Jul 2024 11:17:31 +0300 Subject: [PATCH 22/27] Fix scaffolding error with Firebird 2.5 caused by boolean conversion (#1184) --- .../Scaffolding/Internal/FbDatabaseModelFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs index dd3710def..7bc317d15 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs @@ -311,7 +311,7 @@ private void GetPrimaryKeys(DbConnection connection, IReadOnlyList Date: Wed, 17 Jul 2024 13:35:28 +0200 Subject: [PATCH 23/27] Creation of backup and restore statistics can be switched off to support Firebird Server 2.0 (#1182) --- src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs | 8 +++++--- src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs index 35c833877..a7ea0e9dc 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbBackup.cs @@ -32,7 +32,7 @@ public sealed class FbBackup : FbService public int Factor { get; set; } public string SkipData { get; set; } public FbBackupFlags Options { get; set; } - public FbBackupRestoreStatistics Statistics { get; set; } + public FbBackupRestoreStatistics? Statistics { get; set; } public FbBackup(string connectionString = null) : base(connectionString) @@ -67,7 +67,8 @@ public void Execute() if (!string.IsNullOrEmpty(SkipData)) startSpb.Append2(IscCodes.isc_spb_bkp_skip_data, SkipData); startSpb.Append(IscCodes.isc_spb_options, (int)Options); - startSpb.Append2(IscCodes.isc_spb_bkp_stat, Statistics.BuildConfiguration()); + if (Statistics.HasValue) + startSpb.Append2(IscCodes.isc_spb_bkp_stat, Statistics.Value.BuildConfiguration()); if (ConnectionStringOptions.ParallelWorkers > 0) startSpb.Append(IscCodes.isc_spb_bkp_parallel_workers, ConnectionStringOptions.ParallelWorkers); StartTask(startSpb); @@ -113,7 +114,8 @@ public async Task ExecuteAsync(CancellationToken cancellationToken = default) if (!string.IsNullOrEmpty(SkipData)) startSpb.Append2(IscCodes.isc_spb_bkp_skip_data, SkipData); startSpb.Append(IscCodes.isc_spb_options, (int)Options); - startSpb.Append2(IscCodes.isc_spb_bkp_stat, Statistics.BuildConfiguration()); + if (Statistics.HasValue) + startSpb.Append2(IscCodes.isc_spb_bkp_stat, Statistics.Value.BuildConfiguration()); if (ConnectionStringOptions.ParallelWorkers > 0) startSpb.Append(IscCodes.isc_spb_bkp_parallel_workers, ConnectionStringOptions.ParallelWorkers); await StartTaskAsync(startSpb, cancellationToken).ConfigureAwait(false); diff --git a/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs b/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs index b52c01c67..86062c707 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Services/FbRestore.cs @@ -46,7 +46,7 @@ public int? PageSize public bool ReadOnly { get; set; } public string SkipData { get; set; } public FbRestoreFlags Options { get; set; } - public FbBackupRestoreStatistics Statistics { get; set; } + public FbBackupRestoreStatistics? Statistics { get; set; } public FbRestore(string connectionString = null) : base(connectionString) @@ -82,7 +82,8 @@ public void Execute() if (!string.IsNullOrEmpty(SkipData)) startSpb.Append2(IscCodes.isc_spb_res_skip_data, SkipData); startSpb.Append(IscCodes.isc_spb_options, (int)Options); - startSpb.Append2(IscCodes.isc_spb_res_stat, Statistics.BuildConfiguration()); + if (Statistics.HasValue) + startSpb.Append2(IscCodes.isc_spb_res_stat, Statistics.Value.BuildConfiguration()); if (ConnectionStringOptions.ParallelWorkers > 0) startSpb.Append(IscCodes.isc_spb_res_parallel_workers, ConnectionStringOptions.ParallelWorkers); StartTask(startSpb); @@ -129,7 +130,8 @@ public async Task ExecuteAsync(CancellationToken cancellationToken = default) if (!string.IsNullOrEmpty(SkipData)) startSpb.Append2(IscCodes.isc_spb_res_skip_data, SkipData); startSpb.Append(IscCodes.isc_spb_options, (int)Options); - startSpb.Append2(IscCodes.isc_spb_res_stat, Statistics.BuildConfiguration()); + if (Statistics.HasValue) + startSpb.Append2(IscCodes.isc_spb_res_stat, Statistics.Value.BuildConfiguration()); if (ConnectionStringOptions.ParallelWorkers > 0) startSpb.Append(IscCodes.isc_spb_res_parallel_workers, ConnectionStringOptions.ParallelWorkers); await StartTaskAsync(startSpb, cancellationToken).ConfigureAwait(false); From 795b51be0df5249695006903f57966585224bfc7 Mon Sep 17 00:00:00 2001 From: Gilson Joanelo Date: Thu, 26 Sep 2024 08:44:46 -0300 Subject: [PATCH 24/27] Add isUnicode parameter to StringLiteralQueryType function (#1192) --- .../Query/Internal/FbQuerySqlGenerator.cs | 3 ++- .../Storage/Internal/FbSqlGenerationHelper.cs | 6 +++--- .../Storage/Internal/IFbSqlGenerationHelper.cs | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs index c8f203bff..64a79623f 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs @@ -191,8 +191,9 @@ protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstant base.VisitSqlConstant(sqlConstantExpression); if (shouldExplicitStringLiteralTypes) { + var isUnicode = FbTypeMappingSource.IsUnicode(sqlConstantExpression.TypeMapping); Sql.Append(" AS "); - Sql.Append(((IFbSqlGenerationHelper)Dependencies.SqlGenerationHelper).StringLiteralQueryType(sqlConstantExpression.Value as string)); + Sql.Append(((IFbSqlGenerationHelper)Dependencies.SqlGenerationHelper).StringLiteralQueryType(sqlConstantExpression.Value as string, isUnicode)); Sql.Append(")"); } return sqlConstantExpression; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbSqlGenerationHelper.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbSqlGenerationHelper.cs index 3aa22fc4f..78bbff57d 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbSqlGenerationHelper.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbSqlGenerationHelper.cs @@ -27,11 +27,11 @@ public FbSqlGenerationHelper(RelationalSqlGenerationHelperDependencies dependenc : base(dependencies) { } - public virtual string StringLiteralQueryType(string s) + public virtual string StringLiteralQueryType(string s, bool isUnicode = true) { var length = MinimumStringQueryTypeLength(s); - EnsureStringLiteralQueryTypeLength(length); - return $"VARCHAR({length}) CHARACTER SET UTF8"; + var charset = isUnicode ? " CHARACTER SET UTF8" : string.Empty; + return $"VARCHAR({length}){charset}"; } public virtual string StringParameterQueryType(bool isUnicode) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/IFbSqlGenerationHelper.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/IFbSqlGenerationHelper.cs index 149cb2a92..56c4c1f57 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/IFbSqlGenerationHelper.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/IFbSqlGenerationHelper.cs @@ -22,7 +22,7 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.Storage.Internal; public interface IFbSqlGenerationHelper : ISqlGenerationHelper { - string StringLiteralQueryType(string s); + string StringLiteralQueryType(string s, bool isUnicode); string StringParameterQueryType(bool isUnicode); void GenerateBlockParameterName(StringBuilder builder, string name); string AlternativeStatementTerminator { get; } From c5b9fb9ea7cc7f5f70dcfff58b8685ae0eac3d9a Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Thu, 17 Oct 2024 00:43:01 -0700 Subject: [PATCH 25/27] Fix FbZonedDateTime invalid cast (#1194) --- .../FbZonedDateTimeTypeTests.cs | 8 ++++ .../Types/FbZonedDateTime.cs | 41 +++++++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs b/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs index ca94f33e2..b69dc7044 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedDateTimeTypeTests.cs @@ -47,6 +47,14 @@ public void EqualityFalse(FbZonedDateTime expected, FbZonedDateTime actual) Assert.AreNotEqual(expected, actual); } + [Test] + public void ConvertToDateTimeShouldNotThrow() + { + var fbZonedDateTime = new FbZonedDateTime(new DateTime(2020, 12, 4, 10, 38, 0, DateTimeKind.Utc), "UTC"); + + Assert.DoesNotThrow(() => Convert.ChangeType(fbZonedDateTime, typeof(DateTime))); + } + public void DateTimeShouldBeUtc() { Assert.Throws(() => diff --git a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs index b2eff99b1..78ad2c5a1 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs @@ -21,7 +21,7 @@ namespace FirebirdSql.Data.Types; [StructLayout(LayoutKind.Auto)] -public readonly struct FbZonedDateTime : IEquatable +public readonly struct FbZonedDateTime : IEquatable, IConvertible { public DateTime DateTime { get; } public string TimeZone { get; } @@ -72,8 +72,43 @@ public override int GetHashCode() } } - public bool Equals(FbZonedDateTime other) => DateTime.Equals(other.DateTime) && TimeZone.Equals(other.TimeZone, StringComparison.OrdinalIgnoreCase); - + public bool Equals(FbZonedDateTime other) => DateTime.Equals(other.DateTime) && TimeZone.Equals(other.TimeZone, StringComparison.OrdinalIgnoreCase); + + TypeCode IConvertible.GetTypeCode() => TypeCode.Object; + + DateTime IConvertible.ToDateTime(IFormatProvider provider) => DateTime; + + string IConvertible.ToString(IFormatProvider provider) => ToString(); + + object IConvertible.ToType(Type conversionType, IFormatProvider provider) + => ReferenceEquals(conversionType, typeof(FbZonedDateTime)) ? this : throw new InvalidCastException(conversionType?.FullName); + + bool IConvertible.ToBoolean(IFormatProvider provider) => throw new InvalidCastException(nameof(Boolean)); + + byte IConvertible.ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); + + char IConvertible.ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); + + decimal IConvertible.ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); + + double IConvertible.ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); + + short IConvertible.ToInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(Int16)); + + int IConvertible.ToInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(Int32)); + + long IConvertible.ToInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(Int64)); + + sbyte IConvertible.ToSByte(IFormatProvider provider) => throw new InvalidCastException(nameof(SByte)); + + float IConvertible.ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); + + ushort IConvertible.ToUInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt16)); + + uint IConvertible.ToUInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt32)); + + ulong IConvertible.ToUInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt64)); + public static bool operator ==(FbZonedDateTime lhs, FbZonedDateTime rhs) => lhs.Equals(rhs); public static bool operator !=(FbZonedDateTime lhs, FbZonedDateTime rhs) => lhs.Equals(rhs); From cb6293e563ad4857dc2bd2616619b1c3bd1fea09 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Thu, 17 Oct 2024 00:45:18 -0700 Subject: [PATCH 26/27] Implement IConvertible for FbZonedTime (#1195) --- .../FbZonedTimeTypeTests.cs | 8 ++++ .../Types/FbZonedTime.cs | 45 +++++++++++++++++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedTimeTypeTests.cs b/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedTimeTypeTests.cs index c0309b389..959c2a579 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedTimeTypeTests.cs +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FbZonedTimeTypeTests.cs @@ -46,4 +46,12 @@ public void EqualityFalse(FbZonedTime expected, FbZonedTime actual) { Assert.AreNotEqual(expected, actual); } + + [Test] + public void ConvertToTimeSpanShouldNotThrow() + { + var fbZonedTime = new FbZonedTime(TimeSpan.FromMinutes(142), "UTC"); + + Assert.DoesNotThrow(() => Convert.ChangeType(fbZonedTime, typeof(TimeSpan))); + } } diff --git a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedTime.cs b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedTime.cs index 560038544..476368933 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedTime.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedTime.cs @@ -21,7 +21,7 @@ namespace FirebirdSql.Data.Types; [StructLayout(LayoutKind.Auto)] -public readonly struct FbZonedTime : IEquatable +public readonly struct FbZonedTime : IEquatable, IConvertible { public TimeSpan Time { get; } public string TimeZone { get; } @@ -70,8 +70,47 @@ public override int GetHashCode() } } - public bool Equals(FbZonedTime other) => Time.Equals(other.Time) && TimeZone.Equals(other.TimeZone, StringComparison.OrdinalIgnoreCase); - + public bool Equals(FbZonedTime other) => Time.Equals(other.Time) && TimeZone.Equals(other.TimeZone, StringComparison.OrdinalIgnoreCase); + + TypeCode IConvertible.GetTypeCode() => TypeCode.Object; + + string IConvertible.ToString(IFormatProvider provider) => ToString(); + + object IConvertible.ToType(Type conversionType, IFormatProvider provider) + => ReferenceEquals(conversionType, typeof(FbZonedTime)) + ? this + : ReferenceEquals(conversionType, typeof(TimeSpan)) + ? Time + : throw new InvalidCastException(conversionType?.FullName); + + bool IConvertible.ToBoolean(IFormatProvider provider) => throw new InvalidCastException(nameof(Boolean)); + + byte IConvertible.ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); + + char IConvertible.ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); + + DateTime IConvertible.ToDateTime(IFormatProvider provider) => throw new InvalidCastException(nameof(DateTime)); + + decimal IConvertible.ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); + + double IConvertible.ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); + + short IConvertible.ToInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(Int16)); + + int IConvertible.ToInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(Int32)); + + long IConvertible.ToInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(Int64)); + + sbyte IConvertible.ToSByte(IFormatProvider provider) => throw new InvalidCastException(nameof(SByte)); + + float IConvertible.ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); + + ushort IConvertible.ToUInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt16)); + + uint IConvertible.ToUInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt32)); + + ulong IConvertible.ToUInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt64)); + public static bool operator ==(FbZonedTime lhs, FbZonedTime rhs) => lhs.Equals(rhs); public static bool operator !=(FbZonedTime lhs, FbZonedTime rhs) => lhs.Equals(rhs); From f00a9a9aba30c7622a1d375c2c020ca3c6fe1954 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Thu, 17 Oct 2024 09:47:47 +0200 Subject: [PATCH 27/27] Small cleanup after PRs. --- .../Types/FbZonedDateTime.cs | 172 +++++++++--------- .../Types/FbZonedTime.cs | 165 ++++++++--------- 2 files changed, 157 insertions(+), 180 deletions(-) diff --git a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs index 78ad2c5a1..54e7e5c7b 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedDateTime.cs @@ -1,77 +1,77 @@ -/* - * The contents of this file are subject to the Initial - * Developer's Public License Version 1.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. - * - * Software distributed under the License is distributed on - * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the License for the specific - * language governing rights and limitations under the License. - * - * All Rights Reserved. - */ - -//$Authors = Jiri Cincura (jiri@cincura.net) - -using System; -using System.Runtime.InteropServices; - -namespace FirebirdSql.Data.Types; - -[StructLayout(LayoutKind.Auto)] -public readonly struct FbZonedDateTime : IEquatable, IConvertible -{ - public DateTime DateTime { get; } - public string TimeZone { get; } - public TimeSpan? Offset { get; } - - internal FbZonedDateTime(DateTime dateTime, string timeZone, TimeSpan? offset) - { - if (dateTime.Kind != DateTimeKind.Utc) - throw new ArgumentException("Value must be in UTC.", nameof(dateTime)); - if (timeZone == null) - throw new ArgumentNullException(nameof(timeZone)); - if (string.IsNullOrWhiteSpace(timeZone)) - throw new ArgumentException(nameof(timeZone)); - - DateTime = dateTime; - TimeZone = timeZone; - Offset = offset; - } - - public FbZonedDateTime(DateTime dateTime, string timeZone) - : this(dateTime, timeZone, null) - { } - - public override string ToString() - { - if (Offset != null) - { - return $"{DateTime} {TimeZone} ({Offset})"; - } - return $"{DateTime} {TimeZone}"; - } - - public override bool Equals(object obj) - { - return obj is FbZonedDateTime fbZonedDateTime && Equals(fbZonedDateTime); - } - - public override int GetHashCode() - { - unchecked - { - var hash = (int)2166136261; - hash = (hash * 16777619) ^ DateTime.GetHashCode(); - hash = (hash * 16777619) ^ TimeZone.GetHashCode(); - if (Offset != null) - hash = (hash * 16777619) ^ Offset.GetHashCode(); - return hash; - } - } - +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Runtime.InteropServices; + +namespace FirebirdSql.Data.Types; + +[StructLayout(LayoutKind.Auto)] +public readonly struct FbZonedDateTime : IEquatable, IConvertible +{ + public DateTime DateTime { get; } + public string TimeZone { get; } + public TimeSpan? Offset { get; } + + internal FbZonedDateTime(DateTime dateTime, string timeZone, TimeSpan? offset) + { + if (dateTime.Kind != DateTimeKind.Utc) + throw new ArgumentException("Value must be in UTC.", nameof(dateTime)); + if (timeZone == null) + throw new ArgumentNullException(nameof(timeZone)); + if (string.IsNullOrWhiteSpace(timeZone)) + throw new ArgumentException(nameof(timeZone)); + + DateTime = dateTime; + TimeZone = timeZone; + Offset = offset; + } + + public FbZonedDateTime(DateTime dateTime, string timeZone) + : this(dateTime, timeZone, null) + { } + + public override string ToString() + { + if (Offset != null) + { + return $"{DateTime} {TimeZone} ({Offset})"; + } + return $"{DateTime} {TimeZone}"; + } + + public override bool Equals(object obj) + { + return obj is FbZonedDateTime fbZonedDateTime && Equals(fbZonedDateTime); + } + + public override int GetHashCode() + { + unchecked + { + var hash = (int)2166136261; + hash = (hash * 16777619) ^ DateTime.GetHashCode(); + hash = (hash * 16777619) ^ TimeZone.GetHashCode(); + if (Offset != null) + hash = (hash * 16777619) ^ Offset.GetHashCode(); + return hash; + } + } + public bool Equals(FbZonedDateTime other) => DateTime.Equals(other.DateTime) && TimeZone.Equals(other.TimeZone, StringComparison.OrdinalIgnoreCase); TypeCode IConvertible.GetTypeCode() => TypeCode.Object; @@ -81,35 +81,25 @@ public override int GetHashCode() string IConvertible.ToString(IFormatProvider provider) => ToString(); object IConvertible.ToType(Type conversionType, IFormatProvider provider) - => ReferenceEquals(conversionType, typeof(FbZonedDateTime)) ? this : throw new InvalidCastException(conversionType?.FullName); + => ReferenceEquals(conversionType, typeof(FbZonedDateTime)) + ? this + : throw new InvalidCastException(conversionType?.FullName); bool IConvertible.ToBoolean(IFormatProvider provider) => throw new InvalidCastException(nameof(Boolean)); - byte IConvertible.ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); - char IConvertible.ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); - decimal IConvertible.ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); - double IConvertible.ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); - short IConvertible.ToInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(Int16)); - int IConvertible.ToInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(Int32)); - long IConvertible.ToInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(Int64)); - sbyte IConvertible.ToSByte(IFormatProvider provider) => throw new InvalidCastException(nameof(SByte)); - float IConvertible.ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); - ushort IConvertible.ToUInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt16)); - uint IConvertible.ToUInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt32)); - ulong IConvertible.ToUInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt64)); - public static bool operator ==(FbZonedDateTime lhs, FbZonedDateTime rhs) => lhs.Equals(rhs); - - public static bool operator !=(FbZonedDateTime lhs, FbZonedDateTime rhs) => lhs.Equals(rhs); -} + public static bool operator ==(FbZonedDateTime lhs, FbZonedDateTime rhs) => lhs.Equals(rhs); + + public static bool operator !=(FbZonedDateTime lhs, FbZonedDateTime rhs) => lhs.Equals(rhs); +} diff --git a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedTime.cs b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedTime.cs index 476368933..f4f34506f 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedTime.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Types/FbZonedTime.cs @@ -1,75 +1,75 @@ -/* - * The contents of this file are subject to the Initial - * Developer's Public License Version 1.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. - * - * Software distributed under the License is distributed on - * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See the License for the specific - * language governing rights and limitations under the License. - * - * All Rights Reserved. - */ - -//$Authors = Jiri Cincura (jiri@cincura.net) - -using System; -using System.Runtime.InteropServices; - -namespace FirebirdSql.Data.Types; - -[StructLayout(LayoutKind.Auto)] -public readonly struct FbZonedTime : IEquatable, IConvertible -{ - public TimeSpan Time { get; } - public string TimeZone { get; } - public TimeSpan? Offset { get; } - - internal FbZonedTime(TimeSpan time, string timeZone, TimeSpan? offset) - { - if (timeZone == null) - throw new ArgumentNullException(nameof(timeZone)); - if (string.IsNullOrWhiteSpace(timeZone)) - throw new ArgumentException(nameof(timeZone)); - - Time = time; - TimeZone = timeZone; - Offset = offset; - } - - public FbZonedTime(TimeSpan time, string timeZone) - : this(time, timeZone, null) - { } - - public override string ToString() - { - if (Offset != null) - { - return $"{Time} {TimeZone} ({Offset})"; - } - return $"{Time} {TimeZone}"; - } - - public override bool Equals(object obj) - { - return obj is FbZonedTime fbZonedTime && Equals(fbZonedTime); - } - - public override int GetHashCode() - { - unchecked - { - var hash = (int)2166136261; - hash = (hash * 16777619) ^ Time.GetHashCode(); - hash = (hash * 16777619) ^ TimeZone.GetHashCode(); - if (Offset != null) - hash = (hash * 16777619) ^ Offset.GetHashCode(); - return hash; - } - } - +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Runtime.InteropServices; + +namespace FirebirdSql.Data.Types; + +[StructLayout(LayoutKind.Auto)] +public readonly struct FbZonedTime : IEquatable, IConvertible +{ + public TimeSpan Time { get; } + public string TimeZone { get; } + public TimeSpan? Offset { get; } + + internal FbZonedTime(TimeSpan time, string timeZone, TimeSpan? offset) + { + if (timeZone == null) + throw new ArgumentNullException(nameof(timeZone)); + if (string.IsNullOrWhiteSpace(timeZone)) + throw new ArgumentException(nameof(timeZone)); + + Time = time; + TimeZone = timeZone; + Offset = offset; + } + + public FbZonedTime(TimeSpan time, string timeZone) + : this(time, timeZone, null) + { } + + public override string ToString() + { + if (Offset != null) + { + return $"{Time} {TimeZone} ({Offset})"; + } + return $"{Time} {TimeZone}"; + } + + public override bool Equals(object obj) + { + return obj is FbZonedTime fbZonedTime && Equals(fbZonedTime); + } + + public override int GetHashCode() + { + unchecked + { + var hash = (int)2166136261; + hash = (hash * 16777619) ^ Time.GetHashCode(); + hash = (hash * 16777619) ^ TimeZone.GetHashCode(); + if (Offset != null) + hash = (hash * 16777619) ^ Offset.GetHashCode(); + return hash; + } + } + public bool Equals(FbZonedTime other) => Time.Equals(other.Time) && TimeZone.Equals(other.TimeZone, StringComparison.OrdinalIgnoreCase); TypeCode IConvertible.GetTypeCode() => TypeCode.Object; @@ -84,34 +84,21 @@ object IConvertible.ToType(Type conversionType, IFormatProvider provider) : throw new InvalidCastException(conversionType?.FullName); bool IConvertible.ToBoolean(IFormatProvider provider) => throw new InvalidCastException(nameof(Boolean)); - byte IConvertible.ToByte(IFormatProvider provider) => throw new InvalidCastException(nameof(Byte)); - char IConvertible.ToChar(IFormatProvider provider) => throw new InvalidCastException(nameof(Char)); - DateTime IConvertible.ToDateTime(IFormatProvider provider) => throw new InvalidCastException(nameof(DateTime)); - decimal IConvertible.ToDecimal(IFormatProvider provider) => throw new InvalidCastException(nameof(Decimal)); - double IConvertible.ToDouble(IFormatProvider provider) => throw new InvalidCastException(nameof(Double)); - short IConvertible.ToInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(Int16)); - int IConvertible.ToInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(Int32)); - long IConvertible.ToInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(Int64)); - sbyte IConvertible.ToSByte(IFormatProvider provider) => throw new InvalidCastException(nameof(SByte)); - float IConvertible.ToSingle(IFormatProvider provider) => throw new InvalidCastException(nameof(Single)); - ushort IConvertible.ToUInt16(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt16)); - uint IConvertible.ToUInt32(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt32)); - ulong IConvertible.ToUInt64(IFormatProvider provider) => throw new InvalidCastException(nameof(UInt64)); - public static bool operator ==(FbZonedTime lhs, FbZonedTime rhs) => lhs.Equals(rhs); - - public static bool operator !=(FbZonedTime lhs, FbZonedTime rhs) => lhs.Equals(rhs); -} + public static bool operator ==(FbZonedTime lhs, FbZonedTime rhs) => lhs.Equals(rhs); + + public static bool operator !=(FbZonedTime lhs, FbZonedTime rhs) => lhs.Equals(rhs); +}