Skip to content

Commit 509e7b8

Browse files
authored
SqlBulkCopy: Explicitly state column name that mismatches(#3170) (#3183)
1 parent 3f4e486 commit 509e7b8

File tree

7 files changed

+105
-3
lines changed

7 files changed

+105
-3
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs

+20-1
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ private string AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet i
547547

548548
HashSet<string> destColumnNames = new HashSet<string>();
549549

550+
Dictionary<string, bool> columnMappingStatusLookup = new Dictionary<string, bool>();
550551
// Loop over the metadata for each column
551552
_SqlMetaDataSet metaDataSet = internalResults[MetaDataResultId].MetaData;
552553
_sortedColumnMappings = new List<_ColumnMapping>(metaDataSet.Length);
@@ -569,9 +570,16 @@ private string AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet i
569570
int assocId;
570571
for (assocId = 0; assocId < _localColumnMappings.Count; assocId++)
571572
{
573+
if (!columnMappingStatusLookup.ContainsKey(_localColumnMappings[assocId].DestinationColumn))
574+
{
575+
columnMappingStatusLookup.Add(_localColumnMappings[assocId].DestinationColumn, false);
576+
}
577+
572578
if ((_localColumnMappings[assocId]._destinationColumnOrdinal == metadata.ordinal) ||
573579
(UnquotedName(_localColumnMappings[assocId]._destinationColumnName) == metadata.column))
574580
{
581+
columnMappingStatusLookup[_localColumnMappings[assocId].DestinationColumn] = true;
582+
575583
if (rejectColumn)
576584
{
577585
nrejected++; // Count matched columns only
@@ -703,6 +711,7 @@ private string AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet i
703711
break;
704712
}
705713
}
714+
706715
if (assocId == _localColumnMappings.Count)
707716
{
708717
// Remove metadata for unmatched columns
@@ -713,7 +722,17 @@ private string AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet i
713722
// All columnmappings should have matched up
714723
if (nmatched + nrejected != _localColumnMappings.Count)
715724
{
716-
throw (SQL.BulkLoadNonMatchingColumnMapping());
725+
List<string> unmatchedColumns = new List<string>();
726+
727+
foreach(KeyValuePair<string, bool> keyValuePair in columnMappingStatusLookup)
728+
{
729+
if (!keyValuePair.Value)
730+
{
731+
unmatchedColumns.Add(keyValuePair.Key);
732+
}
733+
}
734+
735+
throw SQL.BulkLoadNonMatchingColumnName(unmatchedColumns);
717736
}
718737

719738
updateBulkCommandText.Append(")");

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs

+19-1
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,7 @@ private string AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet i
582582

583583
HashSet<string> destColumnNames = new HashSet<string>();
584584

585+
Dictionary<string, bool> columnMappingStatusLookup = new Dictionary<string, bool>();
585586
// Loop over the metadata for each column
586587
_SqlMetaDataSet metaDataSet = internalResults[MetaDataResultId].MetaData;
587588
_sortedColumnMappings = new List<_ColumnMapping>(metaDataSet.Length);
@@ -604,9 +605,16 @@ private string AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet i
604605
int assocId;
605606
for (assocId = 0; assocId < _localColumnMappings.Count; assocId++)
606607
{
608+
if (!columnMappingStatusLookup.ContainsKey(_localColumnMappings[assocId].DestinationColumn))
609+
{
610+
columnMappingStatusLookup.Add(_localColumnMappings[assocId].DestinationColumn, false);
611+
}
612+
607613
if ((_localColumnMappings[assocId]._destinationColumnOrdinal == metadata.ordinal) ||
608614
(UnquotedName(_localColumnMappings[assocId]._destinationColumnName) == metadata.column))
609615
{
616+
columnMappingStatusLookup[_localColumnMappings[assocId].DestinationColumn] = true;
617+
610618
if (rejectColumn)
611619
{
612620
nrejected++; // Count matched columns only
@@ -754,7 +762,17 @@ private string AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet i
754762
// All columnmappings should have matched up
755763
if (nmatched + nrejected != _localColumnMappings.Count)
756764
{
757-
throw (SQL.BulkLoadNonMatchingColumnMapping());
765+
List<string> unmatchedColumns = new List<string>();
766+
767+
foreach(KeyValuePair<string, bool> keyValuePair in columnMappingStatusLookup)
768+
{
769+
if (!keyValuePair.Value)
770+
{
771+
unmatchedColumns.Add(keyValuePair.Key);
772+
}
773+
}
774+
775+
throw SQL.BulkLoadNonMatchingColumnName(unmatchedColumns);
758776
}
759777

760778
updateBulkCommandText.Append(")");

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs

+4
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,10 @@ internal static Exception BulkLoadNonMatchingColumnName(string columnName)
12571257
{
12581258
return BulkLoadNonMatchingColumnName(columnName, null);
12591259
}
1260+
internal static Exception BulkLoadNonMatchingColumnName(IEnumerable<string> columns)
1261+
{
1262+
return BulkLoadNonMatchingColumnName(String.Join(",", columns), null);
1263+
}
12601264
internal static Exception BulkLoadNonMatchingColumnName(string columnName, Exception e)
12611265
{
12621266
return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadNonMatchingColumnName, columnName), e);

src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@
145145
<Compile Include="SQL\SqlBulkCopyTest\FireTrigger.cs" />
146146
<Compile Include="SQL\SqlBulkCopyTest\Helpers.cs" />
147147
<Compile Include="SQL\SqlBulkCopyTest\MissingTargetColumn.cs" />
148+
<Compile Include="SQL\SqlBulkCopyTest\MissingTargetColumns.cs" />
148149
<Compile Include="SQL\SqlBulkCopyTest\MissingTargetTable.cs" />
149150
<Compile Include="SQL\SqlBulkCopyTest\SqlBulkCopyTest.cs" />
150151
<Compile Include="SQL\SqlBulkCopyTest\Transaction.cs" />

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/MissingTargetColumn.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ public static void Test(string srcConstr, string dstConstr, string dstTable)
3535
ColumnMappings.Add("LastName", "col2"); // this column does not exist
3636
ColumnMappings.Add("FirstName", "col3");
3737

38-
string errorMsg = SystemDataResourceManager.Instance.SQL_BulkLoadNonMatchingColumnMapping;
38+
string errorMsg = SystemDataResourceManager.Instance.SQL_BulkLoadNonMatchingColumnName;
39+
errorMsg = string.Format(errorMsg, "col2");
40+
3941
DataTestUtility.AssertThrowsWrapper<InvalidOperationException>(() => bulkcopy.WriteToServer(reader), exceptionMessage: errorMsg);
4042
}
4143
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Data.Common;
7+
8+
namespace Microsoft.Data.SqlClient.ManualTesting.Tests
9+
{
10+
public class MissingTargetColumns
11+
{
12+
public static void Test(string srcConstr, string dstConstr, string dstTable)
13+
{
14+
using (SqlConnection dstConn = new SqlConnection(dstConstr))
15+
using (SqlCommand dstCmd = dstConn.CreateCommand())
16+
{
17+
dstConn.Open();
18+
19+
try
20+
{
21+
Helpers.TryExecute(dstCmd, "create table " + dstTable + " (col1 int, col2 nvarchar(10))");
22+
23+
using (SqlConnection srcConn = new SqlConnection(srcConstr))
24+
using (SqlCommand srcCmd = new SqlCommand("select top 5 EmployeeID, LastName, FirstName from employees", srcConn))
25+
{
26+
srcConn.Open();
27+
28+
using (DbDataReader reader = srcCmd.ExecuteReader())
29+
using (SqlBulkCopy bulkcopy = new SqlBulkCopy(dstConn))
30+
{
31+
bulkcopy.DestinationTableName = dstTable;
32+
SqlBulkCopyColumnMappingCollection ColumnMappings = bulkcopy.ColumnMappings;
33+
34+
ColumnMappings.Add("EmployeeID", "col1");
35+
ColumnMappings.Add("LastName", "col3"); // this column does not exist
36+
ColumnMappings.Add("FirstName", "col4"); // this column does not exist
37+
38+
string errorMsg = SystemDataResourceManager.Instance.SQL_BulkLoadNonMatchingColumnName;
39+
errorMsg = string.Format(errorMsg, "col3,col4");
40+
41+
DataTestUtility.AssertThrowsWrapper<InvalidOperationException>(() => bulkcopy.WriteToServer(reader), exceptionMessage: errorMsg);
42+
}
43+
}
44+
}
45+
finally
46+
{
47+
Helpers.TryExecute(dstCmd, "drop table " + dstTable);
48+
}
49+
}
50+
}
51+
}
52+
}

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs

+6
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ public void MissingTargetColumnTest()
104104
MissingTargetColumn.Test(_connStr, _connStr, AddGuid("SqlBulkCopyTest_MissingTargetColumn"));
105105
}
106106

107+
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))]
108+
public void MissingTargetColumnsTest()
109+
{
110+
MissingTargetColumns.Test(_connStr, _connStr, AddGuid("SqlBulkCopyTest_MissingTargetColumns"));
111+
}
112+
107113
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))]
108114
public void Bug85007Test()
109115
{

0 commit comments

Comments
 (0)