From 8c0356ea64eb9b824ad9c07be362b30433d1181f Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 19 Feb 2020 17:18:42 -0800 Subject: [PATCH 01/11] Improved sqlBulkCopy data conversion's error message-netfx added the unit test. --- .../Microsoft/Data/SqlClient/SqlBulkCopy.cs | 8 +- .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 9 +- .../netfx/src/Resources/Strings.resx | 4 +- ....Data.SqlClient.ManualTesting.Tests.csproj | 1 + .../DataConversionErrorMessage.cs | 116 ++++++++++++++++++ .../SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs | 6 + 6 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessage.cs 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..fa45e0aeaf 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 @@ -1629,11 +1629,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, 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, metadata.isEncrypted, metadata.column, value.ToString(), e); } } @@ -1722,7 +1722,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, metadata.isEncrypted, metadata.column, value.ToString(), null); } if (typeChanged) @@ -1739,7 +1739,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, 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..48eda73e2d 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,14 @@ 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, bool isEncrypted, string columnName, string value, Exception e) { - return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadCannotConvertValue, sourcetype.Name, metatype.TypeName), e); + string quotedValue = "given value"; + + if (!isEncrypted) + quotedValue = string.Format("'{0}'", (value.Length > 100 ? value.Substring(0, 100) : value)); + + return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadCannotConvertValue, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName), e); } static internal Exception BulkLoadNonMatchingColumnMapping() { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx index 572be5cd8b..a3890a6072 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -2809,7 +2809,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 {0} of type {1} from the data source cannot be converted to type {2} for colid {3} [{4}]. The given ColumnMapping does not match up with any column in the source or destination. @@ -4524,4 +4524,4 @@ Error occurred when generating enclave package. Attestation Protocol has not been specified in the connection string, but the query requires enclave computations. - + \ No newline at end of file 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..0641b0c81b 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 @@ -95,6 +95,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessage.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessage.cs new file mode 100644 index 0000000000..3788a20d4e --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessage.cs @@ -0,0 +1,116 @@ +// 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 +{ + public class DataConversionErrorMessage + { + private enum ColumnsEnum + { + _int = 0, + _varChar3 = 1 + } + + public static void StringToIntTest(string dstConstr, string targetTable) + { + var value = "abcde"; + + using (var sqlConnection = new SqlConnection(dstConstr)) + { + sqlConnection.Open(); + + InitialTable(sqlConnection, targetTable); + + var table = PrepareDataTable(targetTable, ColumnsEnum._varChar3, value); + + bool hitException = false; + try + { + using (SqlBulkCopy bulkcopy = new SqlBulkCopy(sqlConnection)) + { + bulkcopy.DestinationTableName = targetTable; + bulkcopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping((int)ColumnsEnum._varChar3, (int)ColumnsEnum._int)); + + bulkcopy.WriteToServer(table); + bulkcopy.Close(); + } + } + catch (Exception ex) + { + object[] args = new object[] { string.Format("'{0}'", value), value.GetType().Name, "int", (int)ColumnsEnum._int, Enum.GetName(typeof(ColumnsEnum), ColumnsEnum._int) }; + string expectedErrorMsg = string.Format(SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValue, args); + Assert.True(ex.Message.Contains(expectedErrorMsg), "Unexpected error message: " + ex.Message); + hitException = true; + } + finally + { + DropTable(sqlConnection, targetTable); + } + Assert.True(hitException, "Did not get any exceptions!"); + } + } + + #region table manupulations + private static 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 static 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; + } + + private static void InitialTable(SqlConnection sqlConnection, string targetTable) + { + using (var command = new SqlCommand()) + { + command.Connection = sqlConnection; + command.CommandText = CreateTableCommand(command, targetTable); + command.CommandType = CommandType.Text; + command.ExecuteNonQuery(); + } + } + + private static 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 + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs index 4219838302..34cb43da4e 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs @@ -247,5 +247,11 @@ public void DestinationTableNameWithSpecialCharTest() { DestinationTableNameWithSpecialChar.Test(srcConstr, AddGuid("SqlBulkCopyTest_DestinationTableNameWithSpecialChar")); } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public void CopyStringToIntTest() + { + DataConversionErrorMessage.StringToIntTest(srcConstr, AddGuid("SqlBulkCopyTest_CopyStringToIntTest")); + } } } From 4e9b0486c0a147c905445a090cecc7f04e1f7f87 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 19 Feb 2020 17:19:37 -0800 Subject: [PATCH 02/11] Improved sqlBulkCopy data conversion's error message-netcore --- .../netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs | 6 +++--- .../netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs | 9 +++++++-- .../netcore/src/Resources/SR.Designer.cs | 2 +- .../netcore/src/Resources/SR.resx | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) 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..e5e7a5d16c 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 @@ -1477,7 +1477,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, metadata.isEncrypted, metadata.column, value.ToString(), ADP.ParameterValueOutOfRange(sqlValue)); } } @@ -1566,7 +1566,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(), metadata.metaType, metadata.ordinal, metadata.isEncrypted, metadata.column, value.ToString(), null); } if (typeChanged) @@ -1583,7 +1583,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(), metadata.metaType, metadata.ordinal, 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..cebc5ac04c 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,14 @@ 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, bool isEncrypted, string columnName, string value, Exception e) { - return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadCannotConvertValue, sourcetype.Name, metatype.TypeName), e); + string quotedValue = "given value"; + + if (!isEncrypted) + quotedValue = string.Format("'{0}'", (value.Length > 100 ? value.Substring(0, 100) : value)); + + return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadCannotConvertValue, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName), 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..0de9729dc7 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 {0} of type {1} from the data source cannot be converted to type {2} for colid {3} [{4}].. /// internal static string SQL_BulkLoadCannotConvertValue { get { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx index a2fdb29cfd..84ecfe3b76 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 {0} of type {1} from the data source cannot be converted to type {2} for colid {3} [{4}]. The given ColumnMapping does not match up with any column in the source or destination. @@ -1860,4 +1860,4 @@ UDT size must be less than {1}, size: {0} - + \ No newline at end of file From 339c7e6f155b2b6e95ddf7c72f544fe9f41000d7 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Thu, 20 Feb 2020 18:39:47 -0800 Subject: [PATCH 03/11] Improved sqlBulkCopy data conversion's error message support RowID for DataTable and DataRow[] --- .../Microsoft/Data/SqlClient/SqlBulkCopy.cs | 31 +++- .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 8 +- .../netcore/src/Resources/SR.Designer.cs | 2 +- .../netcore/src/Resources/SR.resx | 2 +- .../netfx/src/Microsoft.Data.SqlClient.csproj | 6 +- .../Microsoft/Data/SqlClient/SqlBulkCopy.cs | 33 +++- .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 8 +- .../netfx/src/Resources/Strings.Designer.cs | 2 +- .../netfx/src/Resources/Strings.resx | 2 +- ....Data.SqlClient.ManualTesting.Tests.csproj | 2 +- .../DataConversionErrorMessage.cs | 116 ------------ .../DataConversionErrorMessageTest.cs | 169 ++++++++++++++++++ .../SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs | 6 - 13 files changed, 242 insertions(+), 145 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessage.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessageTest.cs 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 e5e7a5d16c..7dcbdc2a60 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,31 @@ 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 +1502,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re } catch (SqlTruncateException) { - throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, metadata.ordinal, metadata.isEncrypted, metadata.column, value.ToString(), ADP.ParameterValueOutOfRange(sqlValue)); + throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), ADP.ParameterValueOutOfRange(sqlValue)); } } @@ -1566,7 +1591,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, metadata.ordinal, metadata.isEncrypted, metadata.column, value.ToString(), null); + throw SQL.BulkLoadCannotConvertValue(value.GetType(), metadata.metaType, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), null); } if (typeChanged) @@ -1583,7 +1608,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re { throw; } - throw SQL.BulkLoadCannotConvertValue(value.GetType(), metadata.metaType, metadata.ordinal, metadata.isEncrypted, metadata.column, value.ToString(), e); + throw SQL.BulkLoadCannotConvertValue(value.GetType(), metadata.metaType, 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 cebc5ac04c..b75bb34f1b 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,14 +812,14 @@ internal static Exception BulkLoadMappingsNamesOrOrdinalsOnly() { return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadMappingsNamesOrOrdinalsOnly)); } - internal static Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, int ordinal, bool isEncrypted, string columnName, string value, Exception e) + internal static Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, int ordinal, int rowNumber, bool isEncrypted, string columnName, string value, Exception e) { - string quotedValue = "given value"; + string quotedValue = string.Empty; if (!isEncrypted) - quotedValue = string.Format("'{0}'", (value.Length > 100 ? value.Substring(0, 100) : value)); + quotedValue = string.Format(" '{0}'", (value.Length > 100 ? value.Substring(0, 100) : value)); - return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadCannotConvertValue, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName), e); + 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 0de9729dc7..4a52017060 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 {0} of type {1} from the data source cannot be converted to type {2} for colid {3} [{4}].. + /// 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 { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx index 84ecfe3b76..e14cec79b6 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 {0} of type {1} from the data source cannot be converted to type {2} for colid {3} [{4}]. + 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. diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index ed6135157b..18684da92e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -313,10 +313,10 @@ - + True True - $(ResxFileName).resx + Strings.resx @@ -372,4 +372,4 @@ - + \ No newline at end of file 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 fa45e0aeaf..d96ed1136c 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,31 @@ 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 +1654,11 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re } catch (SqlTruncateException) { - throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, metadata.ordinal, metadata.isEncrypted, metadata.column, value.ToString(), 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, metadata.ordinal, metadata.isEncrypted, metadata.column, value.ToString(), e); + throw SQL.BulkLoadCannotConvertValue(value.GetType(), mt, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), e); } } @@ -1722,7 +1747,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, metadata.ordinal, metadata.isEncrypted, metadata.column, value.ToString(), null); + throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), null); } if (typeChanged) @@ -1739,7 +1764,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re { throw; } - throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, metadata.ordinal, metadata.isEncrypted, metadata.column, value.ToString(), 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 48eda73e2d..42ad218721 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,14 +959,14 @@ static internal Exception BulkLoadMappingsNamesOrOrdinalsOnly() { return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadMappingsNamesOrOrdinalsOnly)); } - static internal Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, int ordinal, bool isEncrypted, string columnName, string value, Exception e) + static internal Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, int ordinal, int rowNumber, bool isEncrypted, string columnName, string value, Exception e) { - string quotedValue = "given value"; + string quotedValue = string.Empty; if (!isEncrypted) - quotedValue = string.Format("'{0}'", (value.Length > 100 ? value.Substring(0, 100) : value)); + quotedValue = string.Format(" '{0}'", (value.Length > 100 ? value.Substring(0, 100) : value)); - return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadCannotConvertValue, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName), e); + 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..0346e59100 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 { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx index a3890a6072..061aa1c619 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -2809,7 +2809,7 @@ Mappings must be either all name or all ordinal based. - The {0} of type {1} from the data source cannot be converted to type {2} for colid {3} [{4}]. + 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. 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 0641b0c81b..3e4ba9a748 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 @@ -95,7 +95,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessage.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessage.cs deleted file mode 100644 index 3788a20d4e..0000000000 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessage.cs +++ /dev/null @@ -1,116 +0,0 @@ -// 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 -{ - public class DataConversionErrorMessage - { - private enum ColumnsEnum - { - _int = 0, - _varChar3 = 1 - } - - public static void StringToIntTest(string dstConstr, string targetTable) - { - var value = "abcde"; - - using (var sqlConnection = new SqlConnection(dstConstr)) - { - sqlConnection.Open(); - - InitialTable(sqlConnection, targetTable); - - var table = PrepareDataTable(targetTable, ColumnsEnum._varChar3, value); - - bool hitException = false; - try - { - using (SqlBulkCopy bulkcopy = new SqlBulkCopy(sqlConnection)) - { - bulkcopy.DestinationTableName = targetTable; - bulkcopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping((int)ColumnsEnum._varChar3, (int)ColumnsEnum._int)); - - bulkcopy.WriteToServer(table); - bulkcopy.Close(); - } - } - catch (Exception ex) - { - object[] args = new object[] { string.Format("'{0}'", value), value.GetType().Name, "int", (int)ColumnsEnum._int, Enum.GetName(typeof(ColumnsEnum), ColumnsEnum._int) }; - string expectedErrorMsg = string.Format(SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValue, args); - Assert.True(ex.Message.Contains(expectedErrorMsg), "Unexpected error message: " + ex.Message); - hitException = true; - } - finally - { - DropTable(sqlConnection, targetTable); - } - Assert.True(hitException, "Did not get any exceptions!"); - } - } - - #region table manupulations - private static 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 static 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; - } - - private static void InitialTable(SqlConnection sqlConnection, string targetTable) - { - using (var command = new SqlCommand()) - { - command.Connection = sqlConnection; - command.CommandText = CreateTableCommand(command, targetTable); - command.CommandType = CommandType.Text; - command.ExecuteNonQuery(); - } - } - - private static 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 - } -} 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..aec8aaa59d --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessageTest.cs @@ -0,0 +1,169 @@ +// 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 = $"SqlBulkCopyTest_CopyStringToIntTest_{Guid.NewGuid().ToString().Replace('-', '_')}"; + 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 + } + + public DataConversionErrorMessageTest(InitialDatabase fixture) + { + _fixture = fixture; + } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public void StringToIntDataTableTest() + { + StringToIntTest(_fixture.Connection, _fixture.TableName, SourceType.DataTable); + } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public void StringToIntDataRowArrayTest() + { + StringToIntTest(_fixture.Connection, _fixture.TableName, SourceType.DataRows); + } + + private void StringToIntTest(SqlConnection cnn, string targetTable, SourceType sourceType) + { + var value = "abcde"; + + 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: + bulkcopy.WriteToServer(table); + break; + case SourceType.DataRows: + bulkcopy.WriteToServer(table.Select()); + break; + default: + break; + } + + bulkcopy.Close(); + } + } + catch (Exception ex) + { + object[] args = + new object[] { string.Format(" '{0}'", value), value.GetType().Name, "int", (int)ColumnsEnum._int, Enum.GetName(typeof(ColumnsEnum), ColumnsEnum._int), table.Rows.Count }; + string expectedErrorMsg = string.Format(SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValue, args); + Assert.True(ex.Message.Contains(expectedErrorMsg), "Unexpected error message: " + ex.Message); + hitException = true; + } + Assert.True(hitException, "Did not get any exceptions!"); + } + + 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; + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs index 34cb43da4e..4219838302 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs @@ -247,11 +247,5 @@ public void DestinationTableNameWithSpecialCharTest() { DestinationTableNameWithSpecialChar.Test(srcConstr, AddGuid("SqlBulkCopyTest_DestinationTableNameWithSpecialChar")); } - - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - public void CopyStringToIntTest() - { - DataConversionErrorMessage.StringToIntTest(srcConstr, AddGuid("SqlBulkCopyTest_CopyStringToIntTest")); - } } } From d82f33874bdfe89af3cd174bbc4ef3ce8173971a Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Fri, 21 Feb 2020 16:38:54 -0800 Subject: [PATCH 04/11] Updated base lines according to bulk copy error message. --- .../SQL/ParameterTest/SqlParameterTest_DebugMode.bsl | 8 ++++---- .../ParameterTest/SqlParameterTest_DebugMode_Azure.bsl | 8 ++++---- .../SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl | 8 ++++---- .../ParameterTest/SqlParameterTest_ReleaseMode_Azure.bsl | 8 ++++---- .../tests/ManualTests/SQL/ParameterTest/TvpTest.cs | 5 +++++ 5 files changed, 21 insertions(+), 16 deletions(-) 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..f676cf96cb 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>>> EXCEPTION: [System.InvalidOperationException] The given value '1/1/0001 12:00:00 AM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '1/1/0001 12:00:00 AM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '12/31/9999 11:59:59 PM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '12/31/9999 11:59:59 PM' 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..7298929a2f 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>>> EXCEPTION: [System.InvalidOperationException] The given value '1/1/0001 12:00:00 AM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '1/1/0001 12:00:00 AM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '12/31/9999 11:59:59 PM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '12/31/9999 11:59:59 PM' 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..b99de79568 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>>> EXCEPTION: [System.InvalidOperationException] The given value '1/1/0001 12:00:00 AM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '1/1/0001 12:00:00 AM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '12/31/9999 11:59:59 PM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '12/31/9999 11:59:59 PM' 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..499c4c280b 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>>> EXCEPTION: [System.InvalidOperationException] The given value '1/1/0001 12:00:00 AM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '1/1/0001 12:00:00 AM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '12/31/9999 11:59:59 PM' 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>>> EXCEPTION: [System.InvalidOperationException] The given value '12/31/9999 11:59:59 PM' 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/TvpTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs index c10e84bc4d..4c842f418a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs @@ -41,7 +41,12 @@ public class TvpTest // data value and server consts private string _connStr; + /// + /// ToDo: This test is marked as windows only for now, cause of different short date pattern behaviour in linux as two digits for year. + /// Probably solution is adding a separate base line for linux. + /// [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [PlatformSpecific(TestPlatforms.Windows)] public void TestMain() { Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); // To keep things consistent since we output dates as strings From d7c49dc87fd6369a113cd2b58ff326692025f668 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 25 Feb 2020 08:41:24 -0800 Subject: [PATCH 05/11] Fixed bulk copy error message netcore & AE enabled --- .../netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 7dcbdc2a60..3feea9c6e3 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 @@ -1591,7 +1591,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, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), null); + throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), null); } if (typeChanged) @@ -1608,7 +1608,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re { throw; } - throw SQL.BulkLoadCannotConvertValue(value.GetType(), metadata.metaType, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), e); + throw SQL.BulkLoadCannotConvertValue(value.GetType(), type, metadata.ordinal, RowNumber, metadata.isEncrypted, metadata.column, value.ToString(), e); } } From 11ba3c700011594434d78b6626983220150b2de8 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 25 Feb 2020 08:52:32 -0800 Subject: [PATCH 06/11] Added unit test for AE enabled bulk copy error message --- .../AlwaysEncrypted/BulkCopyAEErrorMessage.cs | 107 ++++++++++++++++++ .../TestFixtures/SQLSetupStrategy.cs | 4 + .../Setup/BulkCopyAEErrorMessageTestTable.cs | 35 ++++++ ....Data.SqlClient.ManualTesting.Tests.csproj | 2 + 4 files changed, 148 insertions(+) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/BulkCopyAEErrorMessageTestTable.cs 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..2563b9c3f1 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs @@ -0,0 +1,107 @@ +// 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 Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup; +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, IDisposable + { + private SQLSetupStrategyCertStoreProvider fixture; + + private readonly string _tableName; + private readonly string _columnName; + + public BulkCopyAEErrorMessage(SQLSetupStrategyCertStoreProvider fixture) + { + this.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 = CreateTable(value); + + Assert.True(StringToIntTest(connectionString, _tableName, dataTable, value, dataTable.Rows.Count), "Did not get any exceptions for DataTable!"); + Assert.True(StringToIntTest(connectionString, _tableName, dataTable.Select(), value, dataTable.Rows.Count),"Did not get any exceptions for DataRow[]!"); + } + + private DataTable CreateTable(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); + + bulkCopy.Close(); + } + } + catch (Exception ex) + { + object[] args = + new object[] { string.Empty, value.GetType().Name, targetType, 0, _columnName, rowNo}; + string expectedErrorMsg = string.Format(SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValue, args); + Assert.True(ex.Message.Contains(expectedErrorMsg), "Unexpected error message: " + ex.Message); + hitException = true; + } + return hitException; + } + + public void Dispose() + { + foreach (string connection in DataTestUtility.AEConnStringsSetup) + { + using (SqlConnection sqlConnection = new SqlConnection(connection)) + { + sqlConnection.Open(); + Table.DeleteData(_tableName, sqlConnection); + } + } + } + } +} 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 3e4ba9a748..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 @@ + From 832806d44aa857f063f1380b5e2fcfe3218a54d3 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 26 Feb 2020 13:13:50 -0800 Subject: [PATCH 07/11] Update src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs Co-Authored-By: Cheena Malhotra --- .../tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs index 2563b9c3f1..710665ce1d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs @@ -36,7 +36,7 @@ public void TextToIntErrorMessageTest(string connectionString) DataTable dataTable = CreateTable(value); Assert.True(StringToIntTest(connectionString, _tableName, dataTable, value, dataTable.Rows.Count), "Did not get any exceptions for DataTable!"); - Assert.True(StringToIntTest(connectionString, _tableName, dataTable.Select(), value, dataTable.Rows.Count),"Did not get any exceptions for DataRow[]!"); + 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!"); } private DataTable CreateTable(string value) From 616d4384f3601477ba93e99b99303274fe29eb5c Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 26 Feb 2020 13:18:08 -0800 Subject: [PATCH 08/11] Update BulkCopyAEErrorMessage.cs --- .../tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs index 710665ce1d..715b9307cc 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs @@ -35,7 +35,7 @@ public void TextToIntErrorMessageTest(string connectionString) string value = "stringValue"; DataTable dataTable = CreateTable(value); - Assert.True(StringToIntTest(connectionString, _tableName, dataTable, value, dataTable.Rows.Count), "Did not get any exceptions for DataTable!"); + 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!"); } From 2b6ef2e4f3323ab3dfa82b7d85322fd8d3bf5cc0 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 26 Feb 2020 13:20:12 -0800 Subject: [PATCH 09/11] Update BulkCopyAEErrorMessage.cs --- .../tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs index 715b9307cc..b077b19b13 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs @@ -77,8 +77,6 @@ private bool StringToIntTest(string connectionString, string targetTable, object bulkCopy.WriteToServer((DataTable)dataSet); if (dataSet as DataRow[] != null) bulkCopy.WriteToServer((DataRow[])dataSet); - - bulkCopy.Close(); } } catch (Exception ex) From 9c20720400b40305ae0cdcbecf93ad86b215fb8a Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 26 Feb 2020 13:28:55 -0800 Subject: [PATCH 10/11] Update BulkCopyAEErrorMessage.cs --- .../ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs index b077b19b13..fadbb2c49a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs @@ -33,13 +33,13 @@ public BulkCopyAEErrorMessage(SQLSetupStrategyCertStoreProvider fixture) public void TextToIntErrorMessageTest(string connectionString) { string value = "stringValue"; - DataTable dataTable = CreateTable(value); + 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!"); } - private DataTable CreateTable(string value) + private DataTable CreateDataTable(string value) { var dataTable = new DataTable(); dataTable.Columns.Add(_columnName, typeof(string)); From 928d023df9dc7ba972c266d4d543cb6287376a3e Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 26 Feb 2020 18:42:00 -0800 Subject: [PATCH 11/11] Improved bulk copy unit tests plus support short date issue at Linux --- .../Microsoft/Data/SqlClient/SqlBulkCopy.cs | 1 - .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 13 ++++-- .../netcore/src/Resources/SR.Designer.cs | 9 ++++ .../netcore/src/Resources/SR.resx | 3 ++ .../Microsoft/Data/SqlClient/SqlBulkCopy.cs | 1 - .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 13 ++++-- .../netfx/src/Resources/Strings.Designer.cs | 9 ++++ .../netfx/src/Resources/Strings.resx | 3 ++ .../AlwaysEncrypted/BulkCopyAEErrorMessage.cs | 46 +++++++++++-------- .../SQL/ParameterTest/DateTimeVariantTest.cs | 43 +++++++++++++++++ .../SqlParameterTest_DebugMode.bsl | 8 ++-- .../SqlParameterTest_DebugMode_Azure.bsl | 8 ++-- .../SqlParameterTest_ReleaseMode.bsl | 8 ++-- .../SqlParameterTest_ReleaseMode_Azure.bsl | 8 ++-- .../ManualTests/SQL/ParameterTest/TvpTest.cs | 5 -- .../DataConversionErrorMessageTest.cs | 44 ++++++++++++------ 16 files changed, 159 insertions(+), 63 deletions(-) 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 3feea9c6e3..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 @@ -220,7 +220,6 @@ private int RowNumber case ValueSourceType.DataTable: rowNo = ((DataTable)_rowSource).Rows.IndexOf(_rowEnumerator.Current as DataRow); break; - case ValueSourceType.DbDataReader: case ValueSourceType.IDataReader: case ValueSourceType.Unspecified: 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 b75bb34f1b..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 @@ -815,11 +815,18 @@ internal static Exception BulkLoadMappingsNamesOrOrdinalsOnly() internal static Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, int ordinal, int rowNumber, bool isEncrypted, string columnName, string value, Exception e) { string quotedValue = string.Empty; - if (!isEncrypted) + { quotedValue = string.Format(" '{0}'", (value.Length > 100 ? value.Substring(0, 100) : value)); - - return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadCannotConvertValue, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName, rowNumber), e); + } + 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 4a52017060..a7e178d7e6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs @@ -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 a6dc90f0b5..afba6427ca 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx @@ -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 d96ed1136c..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 @@ -280,7 +280,6 @@ private int RowNumber case ValueSourceType.DataTable: rowNo = ((DataTable)_rowSource).Rows.IndexOf(_rowEnumerator.Current as DataRow); break; - case ValueSourceType.DbDataReader: case ValueSourceType.IDataReader: case ValueSourceType.Unspecified: 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 42ad218721..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 @@ -962,11 +962,18 @@ static internal Exception BulkLoadMappingsNamesOrOrdinalsOnly() static internal Exception BulkLoadCannotConvertValue(Type sourcetype, MetaType metatype, int ordinal, int rowNumber, bool isEncrypted, string columnName, string value, Exception e) { string quotedValue = string.Empty; - if (!isEncrypted) + { quotedValue = string.Format(" '{0}'", (value.Length > 100 ? value.Substring(0, 100) : value)); - - return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadCannotConvertValue, quotedValue, sourcetype.Name, metatype.TypeName, ordinal, columnName, rowNumber), e); + } + 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 0346e59100..0e7cf7910a 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs @@ -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 eb16c024a1..20193d1e49 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -2811,6 +2811,9 @@ 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 index fadbb2c49a..111c64fd43 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/BulkCopyAEErrorMessage.cs @@ -4,7 +4,6 @@ using System; using System.Data; -using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted @@ -14,16 +13,16 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted /// 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, IDisposable + public class BulkCopyAEErrorMessage : IClassFixture { - private SQLSetupStrategyCertStoreProvider fixture; + private SQLSetupStrategyCertStoreProvider _fixture; private readonly string _tableName; private readonly string _columnName; public BulkCopyAEErrorMessage(SQLSetupStrategyCertStoreProvider fixture) { - this.fixture = fixture; + _fixture = fixture; _tableName = fixture.BulkCopyAEErrorMessageTestTable.Name; _columnName = "c1"; } @@ -37,6 +36,7 @@ public void TextToIntErrorMessageTest(string connectionString) 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) @@ -74,32 +74,40 @@ private bool StringToIntTest(string connectionString, string targetTable, object 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) { - object[] args = - new object[] { string.Empty, value.GetType().Name, targetType, 0, _columnName, rowNo}; - string expectedErrorMsg = string.Format(SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValue, args); + 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; } - - public void Dispose() - { - foreach (string connection in DataTestUtility.AEConnStringsSetup) - { - using (SqlConnection sqlConnection = new SqlConnection(connection)) - { - sqlConnection.Open(); - Table.DeleteData(_tableName, sqlConnection); - } - } - } } } 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 f676cf96cb..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 '1/1/0001 12:00:00 AM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '1/1/0001 12:00:00 AM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '12/31/9999 11:59:59 PM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '12/31/9999 11:59:59 PM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 7298929a2f..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 '1/1/0001 12:00:00 AM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '1/1/0001 12:00:00 AM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '12/31/9999 11:59:59 PM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '12/31/9999 11:59:59 PM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 b99de79568..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 '1/1/0001 12:00:00 AM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '1/1/0001 12:00:00 AM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '12/31/9999 11:59:59 PM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '12/31/9999 11:59:59 PM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 499c4c280b..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 '1/1/0001 12:00:00 AM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '1/1/0001 12:00:00 AM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '12/31/9999 11:59:59 PM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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 '12/31/9999 11:59:59 PM' of type DateTime from the data source cannot be converted to type time for Column 0 [f1] Row 1. +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/TvpTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs index 4c842f418a..c10e84bc4d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs @@ -41,12 +41,7 @@ public class TvpTest // data value and server consts private string _connStr; - /// - /// ToDo: This test is marked as windows only for now, cause of different short date pattern behaviour in linux as two digits for year. - /// Probably solution is adding a separate base line for linux. - /// [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - [PlatformSpecific(TestPlatforms.Windows)] public void TestMain() { Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); // To keep things consistent since we output dates as strings diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessageTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessageTest.cs index 5f220fa3ae..9b56183ccf 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessageTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/DataConversionErrorMessageTest.cs @@ -27,7 +27,7 @@ public InitialDatabase() { srcConstr = DataTestUtility.TCPConnectionString; - Connection = new SqlConnection(srcConstr); + Connection = new SqlConnection(srcConstr); TableName = DataTestUtility.GetUniqueNameForSqlServer("SqlBulkCopyTest_CopyStringToIntTest_"); InitialTable(Connection, TableName); } @@ -92,7 +92,8 @@ public class DataConversionErrorMessageTest : IClassFixture private enum SourceType { DataTable, - DataRows + DataRows, + DataReader } public DataConversionErrorMessageTest(InitialDatabase fixture) @@ -101,20 +102,17 @@ public DataConversionErrorMessageTest(InitialDatabase fixture) } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - public void StringToIntDataTableTest() + public void StringToIntErrorMessageTest() { - StringToIntTest(_fixture.Connection, _fixture.TableName, SourceType.DataTable); + 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!"); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - public void StringToIntDataRowArrayTest() - { - StringToIntTest(_fixture.Connection, _fixture.TableName, SourceType.DataRows); - } - - private void StringToIntTest(SqlConnection cnn, string targetTable, SourceType sourceType) + private bool StringToIntTest(SqlConnection cnn, string targetTable, SourceType sourceType) { var value = "abcde"; + int rowNo = -1; DataTable table = PrepareDataTable(targetTable, ColumnsEnum._varChar3, value); @@ -128,11 +126,16 @@ private void StringToIntTest(SqlConnection cnn, string targetTable, SourceType s 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; } @@ -142,13 +145,24 @@ private void StringToIntTest(SqlConnection cnn, string targetTable, SourceType s } catch (Exception ex) { - object[] args = - new object[] { string.Format(" '{0}'", value), value.GetType().Name, "int", (int)ColumnsEnum._int, Enum.GetName(typeof(ColumnsEnum), ColumnsEnum._int), table.Rows.Count }; - string expectedErrorMsg = string.Format(SystemDataResourceManager.Instance.SQL_BulkLoadCannotConvertValue, args); + 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; } - Assert.True(hitException, "Did not get any exceptions!"); + return hitException; } private DataTable PrepareDataTable(string tableName, ColumnsEnum selectedColumn, object value)