From beaab34581b2f38ba08a340ac96112939f10ed20 Mon Sep 17 00:00:00 2001 From: Robin Sue Date: Wed, 23 Oct 2019 00:33:42 +0200 Subject: [PATCH] Improve truncation error message (#258) --- .../Microsoft/Data/SqlClient/SqlBulkCopy.cs | 17 ++++++++++++++--- .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 4 ++-- .../netcore/src/Resources/SR.Designer.cs | 2 +- .../netcore/src/Resources/SR.resx | 2 +- .../Microsoft/Data/SqlClient/SqlBulkCopy.cs | 19 +++++++++++++++---- .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 4 ++-- .../netfx/src/Resources/Strings.Designer.cs | 2 +- .../netfx/src/Resources/Strings.resx | 2 +- 8 files changed, 37 insertions(+), 15 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 01bb741ca1..2fa49eb310 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 @@ -1518,10 +1518,21 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re value = SqlParameter.CoerceValue(value, mt, out coercedToDataFeed, out typeChanged, false); if (!coercedToDataFeed) { // We do not need to test for TextDataFeed as it is only assigned to (N)VARCHAR(MAX) - int len = ((isSqlType) && (!typeChanged)) ? ((SqlString)value).Value.Length : ((string)value).Length; - if (len > length / 2) + string str = ((isSqlType) && (!typeChanged)) ? ((SqlString)value).Value : ((string)value); + int maxStringLength = length / 2; + if (str.Length > maxStringLength) { - throw SQL.BulkLoadStringTooLong(); + if (metadata.isEncrypted) + { + str = ""; + } + else + { + // We truncate to at most 100 characters to match SQL Servers behavior as described in + // https://blogs.msdn.microsoft.com/sql_server_team/string-or-binary-data-would-be-truncated-replacing-the-infamous-error-8152/ + str = str.Remove(Math.Min(maxStringLength, 100)); + } + throw SQL.BulkLoadStringTooLong(_destinationTableName, metadata.column, str); } } break; 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 b5a1293310..9d79238cb6 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 @@ -822,9 +822,9 @@ internal static Exception BulkLoadNonMatchingColumnName(string columnName, Excep { return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadNonMatchingColumnName, columnName), e); } - internal static Exception BulkLoadStringTooLong() + internal static Exception BulkLoadStringTooLong(string tableName, string columnName, string truncatedValue) { - return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadStringTooLong)); + return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_BulkLoadStringTooLong, tableName, columnName, truncatedValue)); } internal static Exception BulkLoadInvalidVariantValue() { 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 0cf76a5c07..a240b1b799 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs @@ -2131,7 +2131,7 @@ internal static string SQL_BulkLoadPendingOperation { } /// - /// Looks up a localized string similar to String or binary data would be truncated.. + /// Looks up a localized string similar to String or binary data would be truncated in table '{0}', column '{1}'. Truncated value: '{2}'.. /// internal static string SQL_BulkLoadStringTooLong { get { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx index 86dea9b809..fc407f9764 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx @@ -631,7 +631,7 @@ The given ColumnName '{0}' does not match up with any column in data source. - String or binary data would be truncated. + String or binary data would be truncated in table '{0}', column '{1}'. Truncated value: '{2}'. Timeout Value '{0}' is less than 0. 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 fae47dacd4..e5c48dc159 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 @@ -1669,11 +1669,22 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re mt = MetaType.GetMetaTypeFromSqlDbType(type.SqlDbType, false); value = SqlParameter.CoerceValue(value, mt, out coercedToDataFeed, out typeChanged, false); if (!coercedToDataFeed) - { // We do not need to test for TextDataFeed as it is only assigned to (N)VARCHAR(MAX) - int len = ((isSqlType) && (!typeChanged)) ? ((SqlString)value).Value.Length : ((string)value).Length; - if (len > length / 2) + { // We do not need to test for TextDataFeed as it is only assigned to (N)VARCHAR(MAX) + string str = ((isSqlType) && (!typeChanged)) ? ((SqlString)value).Value : ((string)value); + int maxStringLength = length / 2; + if (str.Length > maxStringLength) { - throw SQL.BulkLoadStringTooLong(); + if (metadata.isEncrypted) + { + str = ""; + } + else + { + // We truncate to at most 100 characters to match SQL Servers behavior as described in + // https://blogs.msdn.microsoft.com/sql_server_team/string-or-binary-data-would-be-truncated-replacing-the-infamous-error-8152/ + str = str.Remove(Math.Min(maxStringLength, 100)); + } + throw SQL.BulkLoadStringTooLong(_destinationTableName, metadata.column, str); } } break; 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 6b1527c5df..4b8ccc280a 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 @@ -975,9 +975,9 @@ static internal Exception BulkLoadNonMatchingColumnName(string columnName, Excep { return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadNonMatchingColumnName, columnName), e); } - static internal Exception BulkLoadStringTooLong() + static internal Exception BulkLoadStringTooLong(string tableName, string columnName, string truncatedValue) { - return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadStringTooLong)); + return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_BulkLoadStringTooLong, tableName, columnName, truncatedValue)); } static internal Exception BulkLoadInvalidVariantValue() { 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 62512ad38f..e705b16e8e 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 static string SQL_BulkLoadPendingOperation { } /// - /// Looks up a localized string similar to String or binary data would be truncated.. + /// Looks up a localized string similar to String or binary data would be truncated in table '{0}', column '{1}'. Truncated value: '{2}'.. /// internal static string SQL_BulkLoadStringTooLong { get { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx index feba5eef50..02cb545fbb 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -2818,7 +2818,7 @@ The given ColumnName '{0}' does not match up with any column in data source. - String or binary data would be truncated. + String or binary data would be truncated in table '{0}', column '{1}'. Truncated value: '{2}'. Timeout Value '{0}' is less than 0.