diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs
index 22297b4dc7..d64b478f1a 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs
@@ -206,6 +206,30 @@ public SourceColumnMetadata(ValueMethod method, bool isSqlType, bool isDataFeed)
private DataRowState _rowStateToSkip;
private IEnumerator _rowEnumerator;
+ private int RowNumber
+ {
+ get
+ {
+ int rowNo;
+
+ switch (_rowSourceType)
+ {
+ case ValueSourceType.RowArray:
+ rowNo = ((DataTable)_dataTableSource).Rows.IndexOf(_rowEnumerator.Current as DataRow);
+ break;
+ case ValueSourceType.DataTable:
+ rowNo = ((DataTable)_rowSource).Rows.IndexOf(_rowEnumerator.Current as DataRow);
+ break;
+ case ValueSourceType.DbDataReader:
+ case ValueSourceType.IDataReader:
+ case ValueSourceType.Unspecified:
+ default:
+ return -1;
+ }
+ return ++rowNo;
+ }
+ }
+
private TdsParser _parser;
private TdsParserStateObject _stateObj;
private List<_ColumnMapping> _sortedColumnMappings;
@@ -1477,7 +1501,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re
}
catch (SqlTruncateException)
{
- throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, ADP.ParameterValueOutOfRange(sqlValue));
+ throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), ADP.ParameterValueOutOfRange(sqlValue));
}
}
@@ -1566,7 +1590,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re
default:
Debug.Fail("Unknown TdsType!" + type.NullableType.ToString("x2", (IFormatProvider)null));
- throw SQL.BulkLoadCannotConvertValue(value.GetType(), metadata.metaType, null);
+ throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), null);
}
if (typeChanged)
@@ -1583,7 +1607,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re
{
throw;
}
- throw SQL.BulkLoadCannotConvertValue(value.GetType(), metadata.metaType, e);
+ throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), e);
}
}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs
index 69102c3619..d0f640f863 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs
@@ -812,9 +812,21 @@ internal static Exception BulkLoadMappingsNamesOrOrdinalsOnly()
{
return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadMappingsNamesOrOrdinalsOnly));
}
- internal static Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, Exception e)
+ internal static Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, int ordinal, int rowNumber, bool isEncrypted, string columnName, string value, Exception e)
{
- return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadCannotConvertValue, sourcetype.Name, metatype.TypeName), e);
+ string quotedValue = string.Empty;
+ if (!isEncrypted)
+ {
+ quotedValue = string.Format(" '{0}'", (value.Length > 100 ? value.Substring(0, 100) : value));
+ }
+ if (rowNumber == -1)
+ {
+ return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadCannotConvertValueWithoutRowNo, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName), e);
+ }
+ else
+ {
+ return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadCannotConvertValue, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName, rowNumber), e);
+ }
}
internal static Exception BulkLoadNonMatchingColumnMapping()
{
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs
index 4454cb49df..a7e178d7e6 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs
@@ -2140,7 +2140,7 @@ internal class SR {
}
///
- /// Looks up a localized string similar to The given value of type {0} from the data source cannot be converted to type {1} of the specified target column..
+ /// Looks up a localized string similar to The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}] Row {5}..
///
internal static string SQL_BulkLoadCannotConvertValue {
get {
@@ -2148,6 +2148,15 @@ internal class SR {
}
}
+ ///
+ /// Looks up a localized string similar to The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}]..
+ ///
+ internal static string SQL_BulkLoadCannotConvertValueWithoutRowNo {
+ get {
+ return ResourceManager.GetString("SQL_BulkLoadCannotConvertValueWithoutRowNo", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Must not specify SqlBulkCopyOption.UseInternalTransaction and pass an external Transaction at the same time..
///
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx
index a2fdb29cfd..afba6427ca 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx
@@ -625,7 +625,7 @@
Mappings must be either all name or all ordinal based.
- The given value of type {0} from the data source cannot be converted to type {1} of the specified target column.
+ The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}] Row {5}.
The given ColumnMapping does not match up with any column in the source or destination.
@@ -1860,4 +1860,7 @@
UDT size must be less than {1}, size: {0}
+
+ The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}].
+
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs
index ca46138662..cc1862395c 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs
@@ -266,6 +266,30 @@ public SourceColumnMetadata(ValueMethod method, bool isSqlType, bool isDataFeed)
private DataRowState _rowStateToSkip;
private IEnumerator _rowEnumerator;
+ private int RowNumber
+ {
+ get
+ {
+ int rowNo;
+
+ switch (_rowSourceType)
+ {
+ case ValueSourceType.RowArray:
+ rowNo = ((DataTable)_dataTableSource).Rows.IndexOf(_rowEnumerator.Current as DataRow);
+ break;
+ case ValueSourceType.DataTable:
+ rowNo = ((DataTable)_rowSource).Rows.IndexOf(_rowEnumerator.Current as DataRow);
+ break;
+ case ValueSourceType.DbDataReader:
+ case ValueSourceType.IDataReader:
+ case ValueSourceType.Unspecified:
+ default:
+ return -1;
+ }
+ return ++rowNo;
+ }
+ }
+
private TdsParser _parser;
private TdsParserStateObject _stateObj;
private List<_ColumnMapping> _sortedColumnMappings;
@@ -1629,11 +1653,11 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re
}
catch (SqlTruncateException)
{
- throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, ADP.ParameterValueOutOfRange(sqlValue));
+ throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), ADP.ParameterValueOutOfRange(sqlValue));
}
catch (Exception e)
{
- throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, e);
+ throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), e);
}
}
@@ -1722,7 +1746,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re
default:
Debug.Assert(false, "Unknown TdsType!" + type.NullableType.ToString("x2", (IFormatProvider)null));
- throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, null);
+ throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), null);
}
if (typeChanged)
@@ -1739,7 +1763,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re
{
throw;
}
- throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, e);
+ throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), e);
}
}
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs
index 86826ee9bb..2c43a9b253 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs
@@ -959,9 +959,21 @@ static internal Exception BulkLoadMappingsNamesOrOrdinalsOnly()
{
return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadMappingsNamesOrOrdinalsOnly));
}
- static internal Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, Exception e)
+ static internal Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, int ordinal, int rowNumber, bool isEncrypted, string columnName, string value, Exception e)
{
- return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadCannotConvertValue, sourcetype.Name, metatype.TypeName), e);
+ string quotedValue = string.Empty;
+ if (!isEncrypted)
+ {
+ quotedValue = string.Format(" '{0}'", (value.Length > 100 ? value.Substring(0, 100) : value));
+ }
+ if (rowNumber == -1)
+ {
+ return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadCannotConvertValueWithoutRowNo, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName), e);
+ }
+ else
+ {
+ return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadCannotConvertValue, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName, rowNumber), e);
+ }
}
static internal Exception BulkLoadNonMatchingColumnMapping()
{
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs
index 146c442ddb..0e7cf7910a 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs
@@ -8857,7 +8857,7 @@ internal class Strings {
}
///
- /// Looks up a localized string similar to The given value of type {0} from the data source cannot be converted to type {1} of the specified target column..
+ /// Looks up a localized string similar to The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}] Row {5}..
///
internal static string SQL_BulkLoadCannotConvertValue {
get {
@@ -8865,6 +8865,15 @@ internal class Strings {
}
}
+ ///
+ /// Looks up a localized string similar to The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}]..
+ ///
+ internal static string SQL_BulkLoadCannotConvertValueWithoutRowNo {
+ get {
+ return ResourceManager.GetString("SQL_BulkLoadCannotConvertValueWithoutRowNo", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Must not specify SqlBulkCopyOption.UseInternalTransaction and pass an external Transaction at the same time..
///
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx
index 572be5cd8b..20193d1e49 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx
@@ -2809,7 +2809,10 @@
Mappings must be either all name or all ordinal based.
- The given value of type {0} from the data source cannot be converted to type {1} of the specified target column.
+ The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}] Row {5}.
+
+
+ The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}].
The given ColumnMapping does not match up with any column in the source or destination.
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs
new file mode 100644
index 0000000000..111c64fd43
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs
@@ -0,0 +1,113 @@
+// 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;
+using System.Data;
+using Xunit;
+
+namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted
+{
+ ///
+ /// Always Encrypted public API Manual tests.
+ /// TODO: These tests are marked as Windows only for now but should be run for all platforms once the Master Key is accessible to this app from Azure Key Vault.
+ ///
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public class BulkCopyAEErrorMessage : IClassFixture
+ {
+ private SQLSetupStrategyCertStoreProvider _fixture;
+
+ private readonly string _tableName;
+ private readonly string _columnName;
+
+ public BulkCopyAEErrorMessage(SQLSetupStrategyCertStoreProvider fixture)
+ {
+ _fixture = fixture;
+ _tableName = fixture.BulkCopyAEErrorMessageTestTable.Name;
+ _columnName = "c1";
+ }
+
+ [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringSetupForAE))]
+ [ClassData(typeof(AEConnectionStringProvider))]
+ public void TextToIntErrorMessageTest(string connectionString)
+ {
+ string value = "stringValue";
+ DataTable dataTable = CreateDataTable(value);
+
+ Assert.True(StringToIntTest(connectionString, _tableName, dataTable, value, dataTable.Rows.Count), "Did not get any exceptions for DataTable when converting data from 'string' to 'int' datatype!");
+ Assert.True(StringToIntTest(connectionString, _tableName, dataTable.Select(), value, dataTable.Rows.Count),"Did not get any exceptions for DataRow[] when converting data from 'string' to 'int' datatype!");
+ Assert.True(StringToIntTest(connectionString, _tableName, dataTable.CreateDataReader(), value, -1),"Did not get any exceptions for DataReader when converting data from 'string' to 'int' datatype!");
+ }
+
+ private DataTable CreateDataTable(string value)
+ {
+ var dataTable = new DataTable();
+ dataTable.Columns.Add(_columnName, typeof(string));
+
+ var dataRow = dataTable.NewRow();
+ dataRow[_columnName] = value;
+ dataTable.Rows.Add(dataRow);
+ dataTable.AcceptChanges();
+
+ return dataTable;
+ }
+
+ private bool StringToIntTest(string connectionString, string targetTable, object dataSet, string value, int rowNo, string targetType = "int")
+ {
+ var encryptionEnabledConnectionString = new SqlConnectionStringBuilder(connectionString)
+ {
+ ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled
+ }.ConnectionString;
+
+ bool hitException = false;
+ try
+ {
+ using (var connection = new SqlConnection(encryptionEnabledConnectionString))
+ using (var bulkCopy = new SqlBulkCopy(connection)
+ {
+ EnableStreaming = true,
+ BatchSize = 1,
+ DestinationTableName = "[" + _tableName + "]"
+ })
+ {
+ connection.Open();
+ bulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(0, 0));
+
+ if (dataSet as DataTable != null)
+ {
+ bulkCopy.WriteToServer((DataTable)dataSet);
+ }
+ if (dataSet as DataRow[] != null)
+ {
+ bulkCopy.WriteToServer((DataRow[])dataSet);
+ }
+ if (dataSet as IDataReader != null)
+ {
+ bulkCopy.WriteToServer((IDataReader)dataSet);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ string pattern;
+ object[] args =
+ new object[] { string.Empty, value.GetType().Name, targetType, 0, _columnName, rowNo };
+ if (rowNo == -1)
+ {
+ Array.Resize(ref args, args.Length - 1);
+ pattern = SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValueWithoutRowNo;
+ }
+ else
+ {
+ pattern = SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValue;
+ }
+
+ string expectedErrorMsg = string.Format(pattern, args);
+
+ Assert.True(ex.Message.Contains(expectedErrorMsg), "Unexpected error message: " + ex.Message);
+ hitException = true;
+ }
+ return hitException;
+ }
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs
index 8567dc3b0f..dc165a2747 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs
@@ -17,6 +17,7 @@ public class SQLSetupStrategy : IDisposable
protected internal readonly X509Certificate2 certificate;
public string keyPath { get; internal set; }
public Table ApiTestTable { get; private set; }
+ public Table BulkCopyAEErrorMessageTestTable { get; private set; }
public Table BulkCopyAETestTable { get; private set; }
public Table SqlParameterPropertiesTable { get; private set; }
public Table End2EndSmokeTable { get; private set; }
@@ -112,6 +113,9 @@ protected List CreateTables(IList columnEncryptionKe
ApiTestTable = new ApiTestTable(GenerateUniqueName("ApiTestTable"), columnEncryptionKeys[0], columnEncryptionKeys[1]);
tables.Add(ApiTestTable);
+ BulkCopyAEErrorMessageTestTable = new BulkCopyAEErrorMessageTestTable(GenerateUniqueName("BulkCopyAEErrorMessageTestTable"), columnEncryptionKeys[0], columnEncryptionKeys[1]);
+ tables.Add(BulkCopyAEErrorMessageTestTable);
+
BulkCopyAETestTable = new BulkCopyAETestTable(GenerateUniqueName("BulkCopyAETestTable"), columnEncryptionKeys[0], columnEncryptionKeys[1]);
tables.Add(BulkCopyAETestTable);
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/BulkCopyAEErrorMessageTestTable.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/BulkCopyAEErrorMessageTestTable.cs
new file mode 100644
index 0000000000..50f94881ab
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/BulkCopyAEErrorMessageTestTable.cs
@@ -0,0 +1,35 @@
+// 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.
+
+namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup
+{
+ public class BulkCopyAEErrorMessageTestTable : Table
+ {
+ private const string ColumnEncryptionAlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA_256";
+ private ColumnEncryptionKey columnEncryptionKey1;
+ private ColumnEncryptionKey columnEncryptionKey2;
+
+ public BulkCopyAEErrorMessageTestTable(string tableName, ColumnEncryptionKey columnEncryptionKey1, ColumnEncryptionKey columnEncryptionKey2) : base(tableName)
+ {
+ this.columnEncryptionKey1 = columnEncryptionKey1;
+ this.columnEncryptionKey2 = columnEncryptionKey2;
+ }
+
+ public override void Create(SqlConnection sqlConnection)
+ {
+ string encryptionType = DataTestUtility.EnclaveEnabled ? "RANDOMIZED" : "DETERMINISTIC";
+ string sql =
+ $@"CREATE TABLE [dbo].[{Name}]
+ (
+ [c1] int ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{columnEncryptionKey1.Name}], ENCRYPTION_TYPE = {encryptionType}, ALGORITHM = '{ColumnEncryptionAlgorithmName}')
+ )";
+
+ using (SqlCommand command = sqlConnection.CreateCommand())
+ {
+ command.CommandText = sql;
+ command.ExecuteNonQuery();
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
index eb9afe1731..d75f3de3e9 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
@@ -20,6 +20,7 @@
+
@@ -29,6 +30,7 @@
+
@@ -95,6 +97,7 @@
+
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTest.cs
index d747657738..141f861030 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTest.cs
@@ -907,9 +907,17 @@ private static void SqlBulkCopyDataTable_Type(object paramValue, string expected
catch (Exception e)
{
if (IsExpectedException(e, paramValue, expectedTypeName, expectedBaseTypeName))
+ {
LogMessage(tag, "[EXPECTED EXPECTION] " + e.Message);
+ }
+ else if (IsExpectedInvalidOperationException(e, expectedBaseTypeName))
+ {
+ LogMessage(tag, "[EXPECTED INVALID OPERATION EXCEPTION] " + AmendTheGivenMessageDateValueException(e.Message, paramValue));
+ }
else
+ {
DisplayError(tag, e);
+ }
}
finally
{
@@ -1024,9 +1032,17 @@ private static void SqlBulkCopyDataRow_Type(object paramValue, string expectedTy
catch (Exception e)
{
if (IsExpectedException(e, paramValue, expectedTypeName, expectedBaseTypeName))
+ {
LogMessage(tag, "[EXPECTED EXPECTION] " + e.Message);
+ }
+ else if (IsExpectedInvalidOperationException(e, expectedBaseTypeName))
+ {
+ LogMessage(tag, "[EXPECTED INVALID OPERATION EXCEPTION] " + AmendTheGivenMessageDateValueException(e.Message, paramValue));
+ }
else
+ {
DisplayError(tag, e);
+ }
}
finally
{
@@ -1272,6 +1288,33 @@ private static bool IsExpectedException(Exception e, object paramValue, string e
return false;
}
}
+
+ private static bool IsExpectedInvalidOperationException(Exception e, string expectedBaseTypeName)
+ {
+ return ((e.GetType() == typeof(InvalidOperationException)) &&
+ (expectedBaseTypeName == "time") &&
+ (e.Message.Contains("The given value ")));
+ }
+
+ private static string AmendTheGivenMessageDateValueException(string message, object paramValue)
+ {
+ string value = string.Empty;
+ if (paramValue.GetType() == typeof(System.DateTimeOffset))
+ {
+ DateTime dt = ((System.DateTimeOffset)paramValue).UtcDateTime;
+ value = dt.ToString("M/d/yyyy") + " " + dt.TimeOfDay;
+ }
+ else if (paramValue.GetType() == typeof(System.TimeSpan))
+ {
+ value = ((System.TimeSpan)paramValue).ToString();
+ }
+ else
+ {
+ value = ((System.DateTime)paramValue).ToString("M/d/yyyy") + " " + ((System.DateTime)paramValue).TimeOfDay;
+ }
+
+ return message.Replace(paramValue.ToString(), value);
+ }
// NOTE: Logging and Display
private static void DisplayHeader(string tag, object paramValue, string expectedBaseTypeName)
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode.bsl b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode.bsl
index a28b9103fd..a982cfc20b 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode.bsl
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode.bsl
@@ -2139,13 +2139,13 @@ Base Type => Expected : Actual == time : time
SqlBulkCopySqlDataReader_Variant>>> EXCEPTION: [System.InvalidCastException] Specified cast is not valid.
------------------------------ SqlBulkCopyDataTable_Type [type: time value:1/1/0001 00:00:00] ------------------------------
-SqlBulkCopyDataTable_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataTable_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '1/1/0001 00:00:00' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataTable_Variant [type: time value:1/1/0001 00:00:00] ------------------------------
SqlBulkCopyDataTable_Variant>>> EXCEPTION: [System.Data.SqlTypes.SqlTypeException] SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
------------------------------ SqlBulkCopyDataRow_Type [type: time value:1/1/0001 00:00:00] ------------------------------
-SqlBulkCopyDataRow_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataRow_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '1/1/0001 00:00:00' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataRow_Variant [type: time value:1/1/0001 00:00:00] ------------------------------
SqlBulkCopyDataRow_Variant>>> EXCEPTION: [System.Data.SqlTypes.SqlTypeException] SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
@@ -2211,7 +2211,7 @@ Base Type => Expected : Actual == time : time
SqlBulkCopySqlDataReader_Variant>>> EXCEPTION: [System.InvalidCastException] Specified cast is not valid.
------------------------------ SqlBulkCopyDataTable_Type [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
-SqlBulkCopyDataTable_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataTable_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '12/31/9999 23:59:59.9999999' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataTable_Variant [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
Type => Expected : Actual == System.DateTime : System.DateTime
@@ -2221,7 +2221,7 @@ SqlBulkCopy From Data Table [Variant Type]>>> ERROR: VARIANT BASE TYPE MISMATCH!
SqlBulkCopy From Data Table [Variant Type]>>> ERROR: VALUE MISMATCH!!! [Actual = 12/31/9999 11:59:59 PM] [Expected = 12/31/9999 11:59:59 PM]
------------------------------ SqlBulkCopyDataRow_Type [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
-SqlBulkCopyDataRow_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataRow_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '12/31/9999 23:59:59.9999999' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataRow_Variant [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
Type => Expected : Actual == System.DateTime : System.DateTime
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode_Azure.bsl b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode_Azure.bsl
index c4f21cb8fa..882aa2bc0f 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode_Azure.bsl
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode_Azure.bsl
@@ -2139,13 +2139,13 @@ Base Type => Expected : Actual == time : time
SqlBulkCopySqlDataReader_Variant>>> EXCEPTION: [System.InvalidCastException] Specified cast is not valid.
------------------------------ SqlBulkCopyDataTable_Type [type: time value:1/1/0001 00:00:00] ------------------------------
-SqlBulkCopyDataTable_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataTable_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '1/1/0001 00:00:00' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataTable_Variant [type: time value:1/1/0001 00:00:00] ------------------------------
SqlBulkCopyDataTable_Variant>>> EXCEPTION: [System.Data.SqlTypes.SqlTypeException] SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
------------------------------ SqlBulkCopyDataRow_Type [type: time value:1/1/0001 00:00:00] ------------------------------
-SqlBulkCopyDataRow_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataRow_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '1/1/0001 00:00:00' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataRow_Variant [type: time value:1/1/0001 00:00:00] ------------------------------
SqlBulkCopyDataRow_Variant>>> EXCEPTION: [System.Data.SqlTypes.SqlTypeException] SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
@@ -2211,7 +2211,7 @@ Base Type => Expected : Actual == time : time
SqlBulkCopySqlDataReader_Variant>>> EXCEPTION: [System.InvalidCastException] Specified cast is not valid.
------------------------------ SqlBulkCopyDataTable_Type [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
-SqlBulkCopyDataTable_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataTable_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '12/31/9999 23:59:59.9999999' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataTable_Variant [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
Type => Expected : Actual == System.DateTime : System.DateTime
@@ -2221,7 +2221,7 @@ SqlBulkCopy From Data Table [Variant Type]>>> ERROR: VARIANT BASE TYPE MISMATCH!
SqlBulkCopy From Data Table [Variant Type]>>> ERROR: VALUE MISMATCH!!! [Actual = 12/31/9999 11:59:59 PM] [Expected = 12/31/9999 11:59:59 PM]
------------------------------ SqlBulkCopyDataRow_Type [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
-SqlBulkCopyDataRow_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataRow_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '12/31/9999 23:59:59.9999999' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataRow_Variant [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
Type => Expected : Actual == System.DateTime : System.DateTime
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl
index 7fac9219bc..533901f356 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl
@@ -1678,13 +1678,13 @@ Base Type => Expected : Actual == time : time
SqlBulkCopySqlDataReader_Variant>>> EXCEPTION: [System.InvalidCastException] Specified cast is not valid.
------------------------------ SqlBulkCopyDataTable_Type [type: time value:1/1/0001 00:00:00] ------------------------------
-SqlBulkCopyDataTable_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataTable_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '1/1/0001 00:00:00' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataTable_Variant [type: time value:1/1/0001 00:00:00] ------------------------------
SqlBulkCopyDataTable_Variant>>> EXCEPTION: [System.Data.SqlTypes.SqlTypeException] SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
------------------------------ SqlBulkCopyDataRow_Type [type: time value:1/1/0001 00:00:00] ------------------------------
-SqlBulkCopyDataRow_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataRow_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '1/1/0001 00:00:00' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataRow_Variant [type: time value:1/1/0001 00:00:00] ------------------------------
SqlBulkCopyDataRow_Variant>>> EXCEPTION: [System.Data.SqlTypes.SqlTypeException] SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
@@ -1750,7 +1750,7 @@ Base Type => Expected : Actual == time : time
SqlBulkCopySqlDataReader_Variant>>> EXCEPTION: [System.InvalidCastException] Specified cast is not valid.
------------------------------ SqlBulkCopyDataTable_Type [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
-SqlBulkCopyDataTable_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataTable_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '12/31/9999 23:59:59.9999999' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataTable_Variant [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
Type => Expected : Actual == System.DateTime : System.DateTime
@@ -1760,7 +1760,7 @@ SqlBulkCopy From Data Table [Variant Type]>>> ERROR: VARIANT BASE TYPE MISMATCH!
SqlBulkCopy From Data Table [Variant Type]>>> ERROR: VALUE MISMATCH!!! [Actual = 12/31/9999 11:59:59 PM] [Expected = 12/31/9999 11:59:59 PM]
------------------------------ SqlBulkCopyDataRow_Type [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
-SqlBulkCopyDataRow_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataRow_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '12/31/9999 23:59:59.9999999' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataRow_Variant [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
Type => Expected : Actual == System.DateTime : System.DateTime
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode_Azure.bsl b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode_Azure.bsl
index 34e60aff41..b080cee9fb 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode_Azure.bsl
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode_Azure.bsl
@@ -1678,13 +1678,13 @@ Base Type => Expected : Actual == time : time
SqlBulkCopySqlDataReader_Variant>>> EXCEPTION: [System.InvalidCastException] Specified cast is not valid.
------------------------------ SqlBulkCopyDataTable_Type [type: time value:1/1/0001 00:00:00] ------------------------------
-SqlBulkCopyDataTable_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataTable_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '1/1/0001 00:00:00' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataTable_Variant [type: time value:1/1/0001 00:00:00] ------------------------------
SqlBulkCopyDataTable_Variant>>> EXCEPTION: [System.Data.SqlTypes.SqlTypeException] SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
------------------------------ SqlBulkCopyDataRow_Type [type: time value:1/1/0001 00:00:00] ------------------------------
-SqlBulkCopyDataRow_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataRow_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '1/1/0001 00:00:00' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataRow_Variant [type: time value:1/1/0001 00:00:00] ------------------------------
SqlBulkCopyDataRow_Variant>>> EXCEPTION: [System.Data.SqlTypes.SqlTypeException] SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
@@ -1750,7 +1750,7 @@ Base Type => Expected : Actual == time : time
SqlBulkCopySqlDataReader_Variant>>> EXCEPTION: [System.InvalidCastException] Specified cast is not valid.
------------------------------ SqlBulkCopyDataTable_Type [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
-SqlBulkCopyDataTable_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataTable_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '12/31/9999 23:59:59.9999999' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataTable_Variant [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
Type => Expected : Actual == System.DateTime : System.DateTime
@@ -1760,7 +1760,7 @@ SqlBulkCopy From Data Table [Variant Type]>>> ERROR: VARIANT BASE TYPE MISMATCH!
SqlBulkCopy From Data Table [Variant Type]>>> ERROR: VALUE MISMATCH!!! [Actual = 12/31/9999 11:59:59 PM] [Expected = 12/31/9999 11:59:59 PM]
------------------------------ SqlBulkCopyDataRow_Type [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
-SqlBulkCopyDataRow_Type>>> EXCEPTION: [System.InvalidOperationException] The given value of type DateTime from the data source cannot be converted to type time of the specified target column.
+SqlBulkCopyDataRow_Type[EXPECTED INVALID OPERATION EXCEPTION] The given value '12/31/9999 23:59:59.9999999' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1.
------------------------------ SqlBulkCopyDataRow_Variant [type: time value:12/31/9999 23:59:59.9999999] ------------------------------
Type => Expected : Actual == System.DateTime : System.DateTime
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessageTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessageTest.cs
new file mode 100644
index 0000000000..9b56183ccf
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessageTest.cs
@@ -0,0 +1,183 @@
+// 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;
+using System.Data;
+using System.Text;
+using Xunit;
+
+namespace Microsoft.Data.SqlClient.ManualTesting.Tests
+{
+ internal enum ColumnsEnum
+ {
+ _int = 0,
+ _varChar3 = 1
+ }
+
+ public class InitialDatabase : IDisposable
+ {
+ private string srcConstr { get; }
+
+ public SqlConnection Connection { get; }
+
+ public string TableName { get; }
+
+ public InitialDatabase()
+ {
+ srcConstr = DataTestUtility.TCPConnectionString;
+
+ Connection = new SqlConnection(srcConstr);
+ TableName = DataTestUtility.GetUniqueNameForSqlServer("SqlBulkCopyTest_CopyStringToIntTest_");
+ InitialTable(Connection, TableName);
+ }
+
+ #region database manupulation
+ private string CreateTableCommand(SqlCommand command, string tableName)
+ {
+ using (command)
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine($"IF(OBJECT_ID('{tableName}') IS NULL)");
+ sb.AppendLine("BEGIN");
+ sb.AppendLine($"\tCREATE TABLE {tableName}");
+ sb.AppendLine($"\t(\t");
+ sb.AppendLine($"\t\t{Enum.GetName(typeof(ColumnsEnum), ColumnsEnum._int)} int NULL");
+ sb.AppendLine($"\t\t,{Enum.GetName(typeof(ColumnsEnum), ColumnsEnum._varChar3)} varchar(3) NULL");
+ sb.AppendLine($"\t)");
+ sb.AppendLine("END");
+
+ return sb.ToString();
+ }
+ }
+
+ private void InitialTable(SqlConnection sqlConnection, string targetTable)
+ {
+ sqlConnection.Open();
+
+ using (var command = new SqlCommand())
+ {
+ command.Connection = sqlConnection;
+ command.CommandText = CreateTableCommand(command, targetTable);
+ command.CommandType = CommandType.Text;
+ command.ExecuteNonQuery();
+ }
+ }
+
+ private void DropTable(SqlConnection sqlConnection, string targetTable)
+ {
+ using (var command = new SqlCommand())
+ {
+ command.Connection = sqlConnection;
+ command.CommandText = string.Format("DROP TABLE {0}", targetTable);
+ command.CommandType = CommandType.Text;
+ command.ExecuteNonQuery();
+ }
+ }
+ #endregion
+
+ public void Dispose()
+ {
+ DropTable(Connection, TableName);
+
+ Connection.Close();
+ Connection.Dispose();
+ }
+ }
+
+ public class DataConversionErrorMessageTest : IClassFixture
+ {
+ private readonly InitialDatabase _fixture;
+
+ private enum SourceType
+ {
+ DataTable,
+ DataRows,
+ DataReader
+ }
+
+ public DataConversionErrorMessageTest(InitialDatabase fixture)
+ {
+ _fixture = fixture;
+ }
+
+ [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
+ public void StringToIntErrorMessageTest()
+ {
+ Assert.True(StringToIntTest(_fixture.Connection, _fixture.TableName, SourceType.DataTable), "Did not get any exceptions for DataTable when converting data from 'string' to 'int' datatype!");
+ Assert.True(StringToIntTest(_fixture.Connection, _fixture.TableName, SourceType.DataRows), "Did not get any exceptions for DataRow[] when converting data from 'string' to 'int' datatype!");
+ Assert.True(StringToIntTest(_fixture.Connection, _fixture.TableName, SourceType.DataReader), "Did not get any exceptions for DataReader when converting data from 'string' to 'int' datatype!");
+ }
+
+ private bool StringToIntTest(SqlConnection cnn, string targetTable, SourceType sourceType)
+ {
+ var value = "abcde";
+ int rowNo = -1;
+
+ DataTable table = PrepareDataTable(targetTable, ColumnsEnum._varChar3, value);
+
+ bool hitException = false;
+ try
+ {
+ using (SqlBulkCopy bulkcopy = new SqlBulkCopy(cnn))
+ {
+ bulkcopy.DestinationTableName = targetTable;
+ bulkcopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping((int)ColumnsEnum._varChar3, (int)ColumnsEnum._int));
+ switch (sourceType)
+ {
+ case SourceType.DataTable:
+ rowNo = table.Rows.Count;
+ bulkcopy.WriteToServer(table);
+ break;
+ case SourceType.DataRows:
+ rowNo = table.Rows.Count;
+ bulkcopy.WriteToServer(table.Select());
+ break;
+ case SourceType.DataReader:
+ bulkcopy.WriteToServer(table.CreateDataReader());
+ break;
+ default:
+ break;
+ }
+
+ bulkcopy.Close();
+ }
+ }
+ catch (Exception ex)
+ {
+ string pattern;
+ object[] args = new object[] { string.Format(" '{0}'", value), value.GetType().Name, "int", (int)ColumnsEnum._int, Enum.GetName(typeof(ColumnsEnum), ColumnsEnum._int), rowNo };
+ if (rowNo == -1)
+ {
+ Array.Resize(ref args, args.Length - 1);
+ pattern = SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValueWithoutRowNo;
+ }
+ else
+ {
+ pattern = SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValue;
+ }
+
+ string expectedErrorMsg = string.Format(pattern, args);
+
+ Assert.True(ex.Message.Contains(expectedErrorMsg), "Unexpected error message: " + ex.Message);
+ hitException = true;
+ }
+ return hitException;
+ }
+
+ private DataTable PrepareDataTable(string tableName, ColumnsEnum selectedColumn, object value)
+ {
+ var table = new DataTable(tableName);
+
+ table.Columns.Add(Enum.GetName(typeof(ColumnsEnum), ColumnsEnum._int), typeof(int));
+ table.Columns.Add(Enum.GetName(typeof(ColumnsEnum), ColumnsEnum._varChar3), typeof(string));
+
+ var row = table.NewRow();
+ row[(int)selectedColumn] = value;
+
+ table.Rows.Add(row);
+
+ return table;
+ }
+ }
+}