Skip to content

Commit

Permalink
SqlClient: Fix BulkCopy double and single null widening handling (dot…
Browse files Browse the repository at this point in the history
…net/corefx#37603)

* change BulkCopy double and single handling to handle Null values when converting to decimal without throwing and add tests

* address feedback


Commit migrated from dotnet/corefx@97ddad9
  • Loading branch information
Wraith2 authored and cheenamalhotra committed Aug 12, 2019
1 parent 6a988c7 commit 7356b91
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -891,10 +891,10 @@ private object GetValueFromSourceRow(int destRowIndex, out bool isSqlType, out b
value = _SqlDataReaderRowSource.GetSqlDecimal(sourceOrdinal);
break;
case ValueMethod.SqlTypeSqlDouble:
value = new SqlDecimal(_SqlDataReaderRowSource.GetSqlDouble(sourceOrdinal).Value);
value = (SqlDecimal)_SqlDataReaderRowSource.GetSqlDouble(sourceOrdinal); // use cast to handle IsNull correctly because no public constructor allows it
break;
case ValueMethod.SqlTypeSqlSingle:
value = new SqlDecimal(_SqlDataReaderRowSource.GetSqlSingle(sourceOrdinal).Value);
value = (SqlDecimal)_SqlDataReaderRowSource.GetSqlSingle(sourceOrdinal); // use cast to handle IsNull correctly because no public constructor allows it
break;
default:
Debug.Fail($"Current column is marked as being a SqlType, but no SqlType compatible method was provided. Method: {_currentRowMetadata[destRowIndex].Method}");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Xunit;

namespace System.Data.SqlClient.ManualTesting.Tests
{
public class CopyWidenNullInexactNumerics
{
public static void Test(string sourceDatabaseConnectionString, string destinationDatabaseConnectionString)
{
// this test copies float and real inexact numeric types into decimal targets using bulk copy to check that the widening of the type succeeds.

using (var sourceConnection = new SqlConnection(sourceDatabaseConnectionString))
using (var destinationConnection = new SqlConnection(destinationDatabaseConnectionString))
{
sourceConnection.Open();
destinationConnection.Open();

RunCommands(sourceConnection,
new[]
{
"drop table if exists dbo.__SqlBulkCopyBug_Source",
"create table dbo.__SqlBulkCopyBug_Source (floatVal float null, realVal real null)",
"insert dbo.__SqlBulkCopyBug_Source(floatVal,realVal) values(1,1),(2,2),(null,null),(0.00000000000001,0.00000000000001)"
}
);

RunCommands(destinationConnection,
new[]
{
"drop table if exists dbo.__SqlBulkCopyBug_Destination",
"create table dbo.__SqlBulkCopyBug_Destination (floatVal decimal(18,10) null,realVal decimal(18,10) null)"
}
);

Exception error = null;
try
{
var bulkCopy = new SqlBulkCopy(destinationConnection, SqlBulkCopyOptions.Default, null);
bulkCopy.DestinationTableName = "dbo.__SqlBulkCopyBug_Destination";
using (var sourceCommand = new SqlCommand("select * from dbo.__SqlBulkCopyBug_Source", sourceConnection, null))
using (var sourceReader = sourceCommand.ExecuteReader())
{
bulkCopy.WriteToServer(sourceReader);
}
}
catch (Exception ex)
{
error = ex;
}
finally
{
try
{
RunCommands(sourceConnection,
new[]
{
"drop table if exists dbo.__SqlBulkCopyBug_Source",
"drop table if exists dbo.__SqlBulkCopyBug_Destination",
}
);
}
catch
{
}
}

Assert.Null(error);
}
}

public static void RunCommands(SqlConnection connection, IEnumerable<string> commands)
{
using (var sqlCommand = connection.CreateCommand())
{
foreach (var command in commands)
{
Helpers.TryExecute(sqlCommand, command);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ public void ColumnCollationTest()
ColumnCollation.Test(dstConstr, AddGuid("SqlBulkCopyTest_ColumnCollation"));
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
public void CopyWidenNullInexactNumericsTest()
{
CopyWidenNullInexactNumerics.Test(srcConstr, dstConstr);
}

[ConditionalFact(typeof(DataTestUtility),nameof(DataTestUtility.AreConnStringsSetup))]
public void CopyAllFromReaderAsyncTest()
{
Expand Down Expand Up @@ -235,4 +241,4 @@ public void TransactionTestAsyncTest()
TransactionTestAsync.Test(srcConstr, dstConstr, AddGuid("SqlBulkCopyTest_TransactionTestAsync")); //Async + Transaction rollback
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{45DB5F86-7AE3-45C6-870D-F9357B66BDB5}</ProjectGuid>
<Configurations>netcoreapp-Debug;netcoreapp-Release;uap-Debug;uap-Release</Configurations>
Expand Down Expand Up @@ -60,6 +60,7 @@
<Compile Include="SQL\MARSTest\MARSTest.cs" />
<Compile Include="SQL\MirroringTest\ConnectionOnMirroringTest.cs" />
<Compile Include="SQL\ParallelTransactionsTest\ParallelTransactionsTest.cs" />
<Compile Include="SQL\SqlBulkCopyTest\CopyWidenNullInexactNumerics.cs" />
<Compile Include="SQL\SqlCredentialTest\SqlCredentialTest.cs" />
<Compile Include="SQL\SqlSchemaInfoTest\SqlSchemaInfoTest.cs" />
<Compile Include="SQL\SqlBulkCopyTest\AdjustPrecScaleForBulkCopy.cs" />
Expand Down

0 comments on commit 7356b91

Please sign in to comment.