From d7c16035d2d6314bddcbdbbf6db4f35218f3ac9d Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Tue, 2 Jan 2024 15:32:04 +0000 Subject: [PATCH] fix codegen error in value-type multimap #2005 (#2022) in horizontal multi-map, don't "returnValueLocal = null" for value-types (invalid IL) fix #2005 --- Dapper/SqlMapper.cs | 11 ++++--- Directory.Build.props | 2 +- Directory.Packages.props | 30 +++++++++---------- appveyor.yml | 2 +- .../DapperCacheImpact.cs | 2 +- .../Dapper.Tests.Performance/LegacyTests.cs | 1 + global.json | 5 ++++ tests/Dapper.Tests/Dapper.Tests.csproj | 4 +-- tests/Dapper.Tests/MiscTests.cs | 11 +++++++ tests/Dapper.Tests/Providers/FirebirdTests.cs | 2 +- .../Dapper.Tests/Providers/PostgresqlTests.cs | 4 +-- 11 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 global.json diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs index b5b6c2ae4..e23502b77 100644 --- a/Dapper/SqlMapper.cs +++ b/Dapper/SqlMapper.cs @@ -1944,7 +1944,7 @@ private static Func GetDeserializer(Type type, DbDataReade } return GetTypeDeserializer(type, reader, startBound, length, returnNullIfFirstMissing); } - return GetStructDeserializer(type, underlyingType ?? type, startBound, useGetFieldValue); + return GetSimpleValueDeserializer(type, underlyingType ?? type, startBound, useGetFieldValue); } private static Func GetHandlerDeserializer(ITypeHandler handler, Type type, int startBound) @@ -3049,7 +3049,7 @@ private static DbDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefi return paramReader; } - private static Func GetStructDeserializer(Type type, Type effectiveType, int index, bool useGetFieldValue) + private static Func GetSimpleValueDeserializer(Type type, Type effectiveType, int index, bool useGetFieldValue) { // no point using special per-type handling here; it boils down to the same, plus not all are supported anyway (see: SqlDataReader.GetChar - not supported!) #pragma warning disable 618 @@ -3578,8 +3578,11 @@ private static void GenerateDeserializerFromMap(Type type, DbDataReader reader, if (first && returnNullIfFirstMissing) { il.Emit(OpCodes.Pop); - il.Emit(OpCodes.Ldnull); // stack is now [null] - il.Emit(OpCodes.Stloc, returnValueLocal); + if (!type.IsValueType) // for struct, the retval is already initialized as default + { + il.Emit(OpCodes.Ldnull); // stack is now [null] + il.Emit(OpCodes.Stloc, returnValueLocal); + } il.Emit(OpCodes.Br, allDone); } diff --git a/Directory.Build.props b/Directory.Build.props index e9ebe949c..6a4b94e1c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -21,7 +21,7 @@ false true true - 11 + 12 false true readme.md diff --git a/Directory.Packages.props b/Directory.Packages.props index 2664f9ede..4ddd3896f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,11 +1,10 @@ - - + @@ -13,34 +12,35 @@ - + - - - + + + + - + - + - - - - + + + + - + - - + + \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 6197828f6..e766f8a28 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ skip_commits: - '**/*.md' install: - - choco install dotnet-sdk --version 7.0.402 + - choco install dotnet-sdk --version 8.0.100 environment: Appveyor: true diff --git a/benchmarks/Dapper.Tests.Performance/DapperCacheImpact.cs b/benchmarks/Dapper.Tests.Performance/DapperCacheImpact.cs index 9e17249bf..5386a2833 100644 --- a/benchmarks/Dapper.Tests.Performance/DapperCacheImpact.cs +++ b/benchmarks/Dapper.Tests.Performance/DapperCacheImpact.cs @@ -10,7 +10,7 @@ public class DapperCacheImpact : BenchmarkBase [GlobalSetup] public void Setup() => BaseSetup(); - private object args = new { Id = 42, Name = "abc" }; + private readonly object args = new { Id = 42, Name = "abc" }; public class Foo { diff --git a/benchmarks/Dapper.Tests.Performance/LegacyTests.cs b/benchmarks/Dapper.Tests.Performance/LegacyTests.cs index ebd899dfb..dd9588b43 100644 --- a/benchmarks/Dapper.Tests.Performance/LegacyTests.cs +++ b/benchmarks/Dapper.Tests.Performance/LegacyTests.cs @@ -128,6 +128,7 @@ private static void Try(Action action, string blame) } } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1806:Do not ignore method results", Justification = "Intentional - just make sure we have something")] public async Task RunAsync(int iterations) { using (var connection = GetOpenConnection()) diff --git a/global.json b/global.json new file mode 100644 index 000000000..f3365c418 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "8.0.100" + } +} \ No newline at end of file diff --git a/tests/Dapper.Tests/Dapper.Tests.csproj b/tests/Dapper.Tests/Dapper.Tests.csproj index 8a003f7bd..5863bc8ed 100644 --- a/tests/Dapper.Tests/Dapper.Tests.csproj +++ b/tests/Dapper.Tests/Dapper.Tests.csproj @@ -2,9 +2,9 @@ Dapper.Tests Dapper Core Test Suite - net472;net6.0;net7.0 + net472;net6.0;net8.0 $(DefineConstants);MSSQLCLIENT - $(NoWarn);IDE0017;IDE0034;IDE0037;IDE0039;IDE0042;IDE0044;IDE0051;IDE0052;IDE0059;IDE0060;IDE0063;IDE1006;xUnit1004;CA1806;CA1816;CA1822;CA1825;CA2208 + $(NoWarn);IDE0017;IDE0034;IDE0037;IDE0039;IDE0042;IDE0044;IDE0051;IDE0052;IDE0059;IDE0060;IDE0063;IDE1006;xUnit1004;CA1806;CA1816;CA1822;CA1825;CA2208;CA1861 enable diff --git a/tests/Dapper.Tests/MiscTests.cs b/tests/Dapper.Tests/MiscTests.cs index aaaf8e978..cc762bf89 100644 --- a/tests/Dapper.Tests/MiscTests.cs +++ b/tests/Dapper.Tests/MiscTests.cs @@ -1310,5 +1310,16 @@ public HazGetOnlyAndCtor(int idProperty, string nameProperty) NameProperty = nameProperty; } } + + internal record struct One(int OID); + internal record struct Two(int OID, string Name); + + [Fact] + public async Task QuerySplitStruct() // https://github.com/DapperLib/Dapper/issues/2005 + { + var results = await connection.QueryAsync(@"SELECT 1 AS OID, 2 AS OID, 'Name' AS Name", (x,y) => (x,y), splitOn: "OID"); + + Assert.Single(results); + } } } diff --git a/tests/Dapper.Tests/Providers/FirebirdTests.cs b/tests/Dapper.Tests/Providers/FirebirdTests.cs index f63df6219..d234a8676 100644 --- a/tests/Dapper.Tests/Providers/FirebirdTests.cs +++ b/tests/Dapper.Tests/Providers/FirebirdTests.cs @@ -33,7 +33,7 @@ public void Issue178_Firebird() connection.Execute("insert into Issue178(id) values(42)"); // raw ADO.net using (var sqlCmd = new FbCommand(sql, connection)) - using (IDataReader reader1 = sqlCmd.ExecuteReader()) + using (var reader1 = sqlCmd.ExecuteReader()) { Assert.True(reader1.Read()); Assert.Equal(1, reader1.GetInt32(0)); diff --git a/tests/Dapper.Tests/Providers/PostgresqlTests.cs b/tests/Dapper.Tests/Providers/PostgresqlTests.cs index 32114370e..261490a53 100644 --- a/tests/Dapper.Tests/Providers/PostgresqlTests.cs +++ b/tests/Dapper.Tests/Providers/PostgresqlTests.cs @@ -49,7 +49,7 @@ public void TestPostgresqlArrayParameters() { using var conn = GetOpenNpgsqlConnection(); - IDbTransaction transaction = conn.BeginTransaction(); + var transaction = conn.BeginTransaction(); conn.Execute("create table tcat ( id serial not null, breed character varying(20) not null, name character varying (20) not null);"); conn.Execute("insert into tcat(breed, name) values(:Breed, :Name) ", Cats); @@ -66,7 +66,7 @@ public void TestPostgresqlListParameters() { using var conn = GetOpenNpgsqlConnection(); - IDbTransaction transaction = conn.BeginTransaction(); + var transaction = conn.BeginTransaction(); conn.Execute("create table tcat ( id serial not null, breed character varying(20) not null, name character varying (20) not null);"); conn.Execute("insert into tcat(breed, name) values(:Breed, :Name) ", new List(Cats));