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; + } + } +}