diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml index d696b24933..a61803e8c7 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml @@ -889,5 +889,29 @@ Unable to retrieve value for null key. To set the value to null, use . + + Gets or sets a Boolean value that indicates how the decimal scale conversion applies when using either the type or type. + The value of the property, or if none has been supplied. + + 's digits, or as defined in target table in property. Otherwise, the result will be rounded like Microsoft SQL Server does. + +> [!NOTE] +> This feature is added to cover the backwards compatibility. + + ]]> + + + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs index 8cf67f1aca..e8159f1321 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs @@ -668,6 +668,7 @@ internal static partial class DbConnectionStringDefaults internal const SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled; internal const string EnclaveAttestationUrl = ""; internal const SqlConnectionAttestationProtocol AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified; + internal const bool TruncateScaledDecimal = false; } @@ -704,6 +705,7 @@ internal static partial class DbConnectionStringKeywords internal const string ColumnEncryptionSetting = "Column Encryption Setting"; internal const string EnclaveAttestationUrl = "Enclave Attestation Url"; internal const string AttestationProtocol = "Attestation Protocol"; + internal const string TruncateScaledDecimal = "Truncate Scaled Decimal"; // common keywords (OleDb, OracleClient, SqlClient) internal const string DataSource = "Data Source"; 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 207acedc85..c4e841c5e2 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 @@ -205,6 +205,7 @@ public SourceColumnMetadata(ValueMethod method, bool isSqlType, bool isDataFeed) private int _currentRowLength; private DataRowState _rowStateToSkip; private IEnumerator _rowEnumerator; + private bool _truncateScaledDecimal; private int RowNumber { @@ -230,6 +231,17 @@ private int RowNumber } } + private SqlConnection Connection + { + get { return _connection; } + set + { + var cnnStringBuilder = new SqlConnectionStringBuilder(value.ConnectionString); + _truncateScaledDecimal = cnnStringBuilder.TruncateScaledDecimal; + _connection = value; + } + } + private TdsParser _parser; private TdsParserStateObject _stateObj; private List<_ColumnMapping> _sortedColumnMappings; @@ -267,7 +279,7 @@ public SqlBulkCopy(SqlConnection connection) { throw ADP.ArgumentNull(nameof(connection)); } - _connection = connection; + Connection = connection; _columnMappings = new SqlBulkCopyColumnMappingCollection(); } @@ -294,7 +306,7 @@ public SqlBulkCopy(string connectionString) { throw ADP.ArgumentNull(nameof(connectionString)); } - _connection = new SqlConnection(connectionString); + Connection = new SqlConnection(connectionString); _columnMappings = new SqlBulkCopyColumnMappingCollection(); _ownConnection = true; } @@ -1499,7 +1511,8 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re if (sqlValue.Scale != scale) { - sqlValue = TdsParser.AdjustSqlDecimalScale(sqlValue, scale); + bool roundDecimal = !_truncateScaledDecimal; + sqlValue = TdsParser.AdjustSqlDecimalScale(sqlValue, scale, roundDecimal); } if (sqlValue.Precision > precision) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionString.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionString.cs index b4ffa82e81..c5b2801f55 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionString.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionString.cs @@ -51,6 +51,7 @@ internal static partial class DEFAULT internal const SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled; internal const string EnclaveAttestationUrl = ""; internal static readonly SqlConnectionAttestationProtocol AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified; + internal const bool Truncate_Scaled_Decimal = false; } // SqlConnection ConnectionString Options @@ -97,6 +98,7 @@ internal static class KEY internal const string Connect_Retry_Count = "connectretrycount"; internal const string Connect_Retry_Interval = "connectretryinterval"; internal const string Authentication = "authentication"; + internal const string Truncate_Scaled_Decimal = "truncate scaled decimal"; } // Constant for the number of duplicate options in the connection string @@ -222,6 +224,8 @@ internal static class TRANSACTIONBINDING private readonly string _expandedAttachDBFilename; // expanded during construction so that CreatePermissionSet & Expand are consistent + private readonly bool _truncateScaledDecimal; + internal SqlConnectionString(string connectionString) : base(connectionString, GetParseSynonyms()) { ThrowUnsupportedIfKeywordSet(KEY.AsynchronousProcessing); @@ -277,6 +281,7 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G _userID = ConvertValueToString(KEY.User_ID, DEFAULT.User_ID); _workstationId = ConvertValueToString(KEY.Workstation_Id, null); + _truncateScaledDecimal = ConvertValueToBoolean(KEY.Truncate_Scaled_Decimal, DEFAULT.Truncate_Scaled_Decimal); if (_loadBalanceTimeout < 0) @@ -501,6 +506,7 @@ internal SqlConnectionString(SqlConnectionString connectionOptions, string dataS _columnEncryptionSetting = connectionOptions._columnEncryptionSetting; _enclaveAttestationUrl = connectionOptions._enclaveAttestationUrl; _attestationProtocol = connectionOptions._attestationProtocol; + _truncateScaledDecimal = connectionOptions._truncateScaledDecimal; ValidateValueLength(_dataSource, TdsEnums.MAXLEN_SERVERNAME, KEY.Data_Source); } @@ -526,6 +532,7 @@ internal SqlConnectionString(SqlConnectionString connectionOptions, string dataS internal bool Pooling { get { return _pooling; } } internal bool Replication { get { return _replication; } } internal bool UserInstance { get { return _userInstance; } } + internal bool TruncateScaledDecimal { get { return _truncateScaledDecimal; } } internal int ConnectTimeout { get { return _connectTimeout; } } internal int LoadBalanceTimeout { get { return _loadBalanceTimeout; } } @@ -648,6 +655,7 @@ internal static Dictionary GetParseSynonyms() { KEY.Connect_Retry_Count, KEY.Connect_Retry_Count }, { KEY.Connect_Retry_Interval, KEY.Connect_Retry_Interval }, { KEY.Authentication, KEY.Authentication }, + { KEY.Truncate_Scaled_Decimal, KEY.Truncate_Scaled_Decimal }, { SYNONYM.APP, KEY.Application_Name }, { SYNONYM.Async, KEY.AsynchronousProcessing }, diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs index be99f295ed..720ce5edb6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs @@ -69,6 +69,8 @@ private enum Keywords EnclaveAttestationUrl, AttestationProtocol, + TruncateScaledDecimal, + // keep the count value last KeywordsCount } @@ -92,6 +94,7 @@ private enum Keywords private string _typeSystemVersion = DbConnectionStringDefaults.TypeSystemVersion; private string _userID = DbConnectionStringDefaults.UserID; private string _workstationID = DbConnectionStringDefaults.WorkstationID; + private bool _truncateScaledDecimal = DbConnectionStringDefaults.TruncateScaledDecimal; private int _connectTimeout = DbConnectionStringDefaults.ConnectTimeout; private int _loadBalanceTimeout = DbConnectionStringDefaults.LoadBalanceTimeout; @@ -156,6 +159,7 @@ private static string[] CreateValidKeywords() validKeywords[(int)Keywords.ColumnEncryptionSetting] = DbConnectionStringKeywords.ColumnEncryptionSetting; validKeywords[(int)Keywords.EnclaveAttestationUrl] = DbConnectionStringKeywords.EnclaveAttestationUrl; validKeywords[(int)Keywords.AttestationProtocol] = DbConnectionStringKeywords.AttestationProtocol; + validKeywords[(int)Keywords.TruncateScaledDecimal] = DbConnectionStringKeywords.TruncateScaledDecimal; return validKeywords; } @@ -199,6 +203,7 @@ private static Dictionary CreateKeywordsDictionary() hash.Add(DbConnectionStringKeywords.ColumnEncryptionSetting, Keywords.ColumnEncryptionSetting); hash.Add(DbConnectionStringKeywords.EnclaveAttestationUrl, Keywords.EnclaveAttestationUrl); hash.Add(DbConnectionStringKeywords.AttestationProtocol, Keywords.AttestationProtocol); + hash.Add(DbConnectionStringKeywords.TruncateScaledDecimal, Keywords.TruncateScaledDecimal); hash.Add(DbConnectionStringSynonyms.APP, Keywords.ApplicationName); hash.Add(DbConnectionStringSynonyms.EXTENDEDPROPERTIES, Keywords.AttachDBFilename); @@ -356,6 +361,9 @@ public override object this[string keyword] case Keywords.ConnectRetryInterval: ConnectRetryInterval = ConvertToInt32(value); break; + case Keywords.TruncateScaledDecimal: + TruncateScaledDecimal = ConvertToBoolean(value); + break; default: Debug.Fail("unexpected keyword"); @@ -821,6 +829,17 @@ public override ICollection Values } } + /// + public bool TruncateScaledDecimal + { + get { return _truncateScaledDecimal; } + set + { + SetValue(DbConnectionStringKeywords.TruncateScaledDecimal, value); + _truncateScaledDecimal = value; + } + } + /// public override void Clear() { @@ -957,6 +976,8 @@ private object GetAt(Keywords index) return EnclaveAttestationUrl; case Keywords.AttestationProtocol: return AttestationProtocol; + case Keywords.TruncateScaledDecimal: + return TruncateScaledDecimal; default: Debug.Fail("unexpected keyword"); @@ -1102,6 +1123,9 @@ private void Reset(Keywords index) case Keywords.AttestationProtocol: _attestationProtocol = DbConnectionStringDefaults.AttestationProtocol; break; + case Keywords.TruncateScaledDecimal: + _truncateScaledDecimal = DbConnectionStringDefaults.TruncateScaledDecimal; + break; default: Debug.Fail("unexpected keyword"); throw UnsupportedKeyword(s_validKeywords[(int)index]); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index cd15505ac2..50474abed6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -179,6 +179,14 @@ internal SqlInternalConnectionTds Connection } } + internal bool TruncateScaledDecimal + { + get + { + return _connHandler.ConnectionOptions.TruncateScaledDecimal; + } + } + internal SqlInternalTransaction CurrentTransaction { get @@ -6902,17 +6910,17 @@ private bool TryReadDecimalBits(int length, TdsParserStateObject stateObj, out i return true; } - internal static SqlDecimal AdjustSqlDecimalScale(SqlDecimal d, int newScale) + internal static SqlDecimal AdjustSqlDecimalScale(SqlDecimal d, int newScale, bool round) { if (d.Scale != newScale) { - return SqlDecimal.AdjustScale(d, newScale - d.Scale, false /* Don't round, truncate. */); + return SqlDecimal.AdjustScale(d, newScale - d.Scale, round); } return d; } - internal static decimal AdjustDecimalScale(decimal value, int newScale) + internal static decimal AdjustDecimalScale(decimal value, int newScale, bool round) { int oldScale = (decimal.GetBits(value)[3] & 0x00ff0000) >> 0x10; @@ -6920,7 +6928,7 @@ internal static decimal AdjustDecimalScale(decimal value, int newScale) { SqlDecimal num = new SqlDecimal(value); - num = SqlDecimal.AdjustScale(num, newScale - oldScale, false /* Don't round, truncate. */); + num = SqlDecimal.AdjustScale(num, newScale - oldScale, round); return num.Value; } @@ -8966,9 +8974,10 @@ private Task TDSExecuteRPCAddParameter(TdsParserStateObject stateObj, SqlParamet // bug 49512, make sure the value matches the scale the user enters if (!isNull) { + bool roundDecimal = !TruncateScaledDecimal; if (isSqlVal) { - value = AdjustSqlDecimalScale((SqlDecimal)value, scale); + value = AdjustSqlDecimalScale((SqlDecimal)value, scale, roundDecimal); // If Precision is specified, verify value precision vs param precision if (precision != 0) @@ -8981,7 +8990,7 @@ private Task TDSExecuteRPCAddParameter(TdsParserStateObject stateObj, SqlParamet } else { - value = AdjustDecimalScale((Decimal)value, scale); + value = AdjustDecimalScale((Decimal)value, scale, roundDecimal); SqlDecimal sqlValue = new SqlDecimal((Decimal)value); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs index 08857968cb..a285a7e017 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs @@ -1027,6 +1027,7 @@ internal static class DbConnectionStringDefaults internal const SqlConnectionAttestationProtocol AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified; internal const string Certificate = ""; internal const PoolBlockingPeriod PoolBlockingPeriod = SqlClient.PoolBlockingPeriod.Auto; + internal const bool TruncateScaledDecimal = false; } internal static class DbConnectionOptionKeywords @@ -1099,6 +1100,7 @@ internal static class DbConnectionStringKeywords internal const string EnclaveAttestationUrl = "Enclave Attestation Url"; internal const string AttestationProtocol = "Attestation Protocol"; internal const string PoolBlockingPeriod = "PoolBlockingPeriod"; + internal const string TruncateScaledDecimal = "Truncate Scaled Decimal"; // common keywords (OleDb, OracleClient, SqlClient) internal const string DataSource = "Data Source"; 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 11f3d2f49e..29c165f427 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 @@ -265,6 +265,7 @@ public SourceColumnMetadata(ValueMethod method, bool isSqlType, bool isDataFeed) private int _currentRowLength; private DataRowState _rowStateToSkip; private IEnumerator _rowEnumerator; + private bool _truncateScaledDecimal; private int RowNumber { @@ -290,6 +291,17 @@ private int RowNumber } } + private SqlConnection Connection + { + get { return _connection; } + set + { + var cnnStringBuilder = new SqlConnectionStringBuilder(value.ConnectionString); + _truncateScaledDecimal = cnnStringBuilder.TruncateScaledDecimal; + _connection = value; + } + } + private TdsParser _parser; private TdsParserStateObject _stateObj; private List<_ColumnMapping> _sortedColumnMappings; @@ -333,7 +345,7 @@ public SqlBulkCopy(SqlConnection connection) { throw ADP.ArgumentNull("connection"); } - _connection = connection; + Connection = connection; _columnMappings = new SqlBulkCopyColumnMappingCollection(); } @@ -361,7 +373,7 @@ public SqlBulkCopy(string connectionString) : this(new SqlConnection(connectionS { throw ADP.ArgumentNull("connectionString"); } - _connection = new SqlConnection(connectionString); + Connection = new SqlConnection(connectionString); _columnMappings = new SqlBulkCopyColumnMappingCollection(); _ownConnection = true; } @@ -1647,8 +1659,9 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re } if (sqlValue.Scale != scale) - { - sqlValue = TdsParser.AdjustSqlDecimalScale(sqlValue, scale); + { + bool roundDecimal = !_truncateScaledDecimal; + sqlValue = TdsParser.AdjustSqlDecimalScale(sqlValue, scale, roundDecimal); } if (sqlValue.Precision > precision) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs index 9249f01995..7c013cc2e9 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs @@ -56,6 +56,7 @@ internal static class DEFAULT internal static readonly SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled; internal const string EnclaveAttestationUrl = ""; internal static readonly SqlConnectionAttestationProtocol AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified; + internal const bool Truncate_Scaled_Decimal = false; #if ADONET_CERT_AUTH internal const string Certificate = ""; #endif @@ -104,6 +105,7 @@ internal static class KEY internal const string Connect_Retry_Count = "connectretrycount"; internal const string Connect_Retry_Interval = "connectretryinterval"; internal const string Authentication = "authentication"; + internal const string Truncate_Scaled_Decimal = "truncate scaled decimal"; #if ADONET_CERT_AUTH internal const string Certificate = "certificate"; #endif @@ -252,6 +254,7 @@ internal static class TRANSACIONBINDING private readonly string _expandedAttachDBFilename; // expanded during construction so that CreatePermissionSet & Expand are consistent + private readonly bool _truncateScaledDecimal; // SxS: reading Software\\Microsoft\\MSSQLServer\\Client\\SuperSocketNetLib\Encrypt value from registry [ResourceExposure(ResourceScope.None)] @@ -303,6 +306,8 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G _enclaveAttestationUrl = ConvertValueToString(KEY.EnclaveAttestationUrl, DEFAULT.EnclaveAttestationUrl); _attestationProtocol = ConvertValueToAttestationProtocol(); + _truncateScaledDecimal = ConvertValueToBoolean(KEY.Truncate_Scaled_Decimal, DEFAULT.Truncate_Scaled_Decimal); + #if ADONET_CERT_AUTH _certificate = ConvertValueToString(KEY.Certificate, DEFAULT.Certificate); #endif @@ -610,6 +615,7 @@ internal SqlConnectionString(SqlConnectionString connectionOptions, string dataS _columnEncryptionSetting = connectionOptions._columnEncryptionSetting; _enclaveAttestationUrl = connectionOptions._enclaveAttestationUrl; _attestationProtocol = connectionOptions._attestationProtocol; + _truncateScaledDecimal = connectionOptions._truncateScaledDecimal; #if ADONET_CERT_AUTH _certificate = connectionOptions._certificate; #endif @@ -649,6 +655,7 @@ internal SqlConnectionString(SqlConnectionString connectionOptions, string dataS internal bool Pooling { get { return _pooling; } } internal bool Replication { get { return _replication; } } internal bool UserInstance { get { return _userInstance; } } + internal bool TruncateScaledDecimal { get { return _truncateScaledDecimal; } } internal int ConnectTimeout { get { return _connectTimeout; } } internal int LoadBalanceTimeout { get { return _loadBalanceTimeout; } } @@ -776,6 +783,7 @@ internal static Hashtable GetParseSynonyms() hash.Add(KEY.Connect_Retry_Count, KEY.Connect_Retry_Count); hash.Add(KEY.Connect_Retry_Interval, KEY.Connect_Retry_Interval); hash.Add(KEY.Authentication, KEY.Authentication); + hash.Add(KEY.Truncate_Scaled_Decimal, KEY.Truncate_Scaled_Decimal); #if ADONET_CERT_AUTH hash.Add(KEY.Certificate, KEY.Certificate); #endif diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs index b5d458d7a6..c2fb3026d1 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs @@ -16,7 +16,7 @@ namespace Microsoft.Data.SqlClient { - /// + /// [DefaultProperty("DataSource")] [System.ComponentModel.TypeConverterAttribute(typeof(SqlConnectionStringBuilder.SqlConnectionStringBuilderConverter))] public sealed class SqlConnectionStringBuilder : DbConnectionStringBuilder @@ -81,6 +81,8 @@ private enum Keywords EnclaveAttestationUrl, AttestationProtocol, + TruncateScaledDecimal, + #if ADONET_CERT_AUTH Certificate, #endif @@ -107,6 +109,7 @@ private enum Keywords private string _typeSystemVersion = DbConnectionStringDefaults.TypeSystemVersion; private string _userID = DbConnectionStringDefaults.UserID; private string _workstationID = DbConnectionStringDefaults.WorkstationID; + private bool _truncateScaledDecimal = DbConnectionStringDefaults.TruncateScaledDecimal; private int _connectTimeout = DbConnectionStringDefaults.ConnectTimeout; private int _loadBalanceTimeout = DbConnectionStringDefaults.LoadBalanceTimeout; @@ -183,6 +186,7 @@ static SqlConnectionStringBuilder() validKeywords[(int)Keywords.ColumnEncryptionSetting] = DbConnectionStringKeywords.ColumnEncryptionSetting; validKeywords[(int)Keywords.EnclaveAttestationUrl] = DbConnectionStringKeywords.EnclaveAttestationUrl; validKeywords[(int)Keywords.AttestationProtocol] = DbConnectionStringKeywords.AttestationProtocol; + validKeywords[(int)Keywords.TruncateScaledDecimal] = DbConnectionStringKeywords.TruncateScaledDecimal; #if ADONET_CERT_AUTH validKeywords[(int)Keywords.Certificate] = DbConnectionStringKeywords.Certificate; #endif @@ -229,7 +233,8 @@ static SqlConnectionStringBuilder() hash.Add(DbConnectionStringKeywords.ColumnEncryptionSetting, Keywords.ColumnEncryptionSetting); hash.Add(DbConnectionStringKeywords.EnclaveAttestationUrl, Keywords.EnclaveAttestationUrl); hash.Add(DbConnectionStringKeywords.AttestationProtocol, Keywords.AttestationProtocol); -#if ADONET_CERT_AUTH + hash.Add(DbConnectionStringKeywords.TruncateScaledDecimal, Keywords.TruncateScaledDecimal); +#if ADONET_CERT_AUTH hash.Add(DbConnectionStringKeywords.Certificate, Keywords.Certificate); #endif hash.Add(DbConnectionStringSynonyms.APP, Keywords.ApplicationName); @@ -258,12 +263,12 @@ static SqlConnectionStringBuilder() } - /// + /// public SqlConnectionStringBuilder() : this((string)null) { } - /// + /// public SqlConnectionStringBuilder(string connectionString) : base() { if (!ADP.IsEmpty(connectionString)) @@ -272,7 +277,7 @@ public SqlConnectionStringBuilder(string connectionString) : base() } } - /// + /// public override object this[string keyword] { get @@ -413,6 +418,9 @@ public override object this[string keyword] case Keywords.ConnectRetryInterval: ConnectRetryInterval = ConvertToInt32(value); break; + case Keywords.TruncateScaledDecimal: + TruncateScaledDecimal = ConvertToBoolean(value); + break; default: Debug.Fail("unexpected keyword"); @@ -426,7 +434,7 @@ public override object this[string keyword] } } - /// + /// [DisplayName(DbConnectionStringKeywords.ApplicationIntent)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Initialization)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_ApplicationIntent)] @@ -446,7 +454,7 @@ public ApplicationIntent ApplicationIntent } } - /// + /// [DisplayName(DbConnectionStringKeywords.ApplicationName)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Context)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_ApplicationName)] @@ -461,7 +469,7 @@ public string ApplicationName } } - /// + /// [DisplayName(DbConnectionStringKeywords.AsynchronousProcessing)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Initialization)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_AsynchronousProcessing)] @@ -476,7 +484,7 @@ public bool AsynchronousProcessing } } - /// + /// [DisplayName(DbConnectionStringKeywords.AttachDBFilename)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Source)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_AttachDBFilename)] @@ -493,7 +501,7 @@ public string AttachDBFilename } } - /// + /// [DisplayName(DbConnectionStringKeywords.PoolBlockingPeriod)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Pooling)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_PoolBlockingPeriod)] @@ -513,7 +521,7 @@ public PoolBlockingPeriod PoolBlockingPeriod } } - /// + /// [Browsable(false)] [DisplayName(DbConnectionStringKeywords.ConnectionReset)] [Obsolete("ConnectionReset has been deprecated. SqlConnection will ignore the 'connection reset' keyword and always reset the connection")] // SQLPT 41700 @@ -530,7 +538,7 @@ public bool ConnectionReset } } - /// + /// [DisplayName(DbConnectionStringKeywords.ContextConnection)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Source)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_ContextConnection)] @@ -545,7 +553,7 @@ public bool ContextConnection } } - /// + /// [DisplayName(DbConnectionStringKeywords.ConnectTimeout)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Initialization)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_ConnectTimeout)] @@ -564,7 +572,7 @@ public int ConnectTimeout } } - /// + /// [DisplayName(DbConnectionStringKeywords.CurrentLanguage)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Initialization)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_CurrentLanguage)] @@ -579,7 +587,7 @@ public string CurrentLanguage } } - /// + /// [DisplayName(DbConnectionStringKeywords.DataSource)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Source)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_DataSource)] @@ -595,7 +603,7 @@ public string DataSource } } - /// + /// [DisplayName(DbConnectionStringKeywords.Encrypt)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_Encrypt)] @@ -610,7 +618,7 @@ public bool Encrypt } } - /// + /// [DisplayName(DbConnectionStringKeywords.ColumnEncryptionSetting)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] [ResDescriptionAttribute(StringsHelper.ResourceNames.TCE_DbConnectionString_ColumnEncryptionSetting)] @@ -630,7 +638,7 @@ public SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting } } - /// + /// [DisplayName(DbConnectionStringKeywords.EnclaveAttestationUrl)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] [ResDescriptionAttribute(StringsHelper.ResourceNames.TCE_DbConnectionString_EnclaveAttestationUrl)] @@ -645,7 +653,7 @@ public string EnclaveAttestationUrl } } - /// + /// [DisplayName(DbConnectionStringKeywords.AttestationProtocol)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] [ResDescriptionAttribute(StringsHelper.ResourceNames.TCE_DbConnectionString_AttestationProtocol)] @@ -665,7 +673,7 @@ public SqlConnectionAttestationProtocol AttestationProtocol } } - /// + /// [DisplayName(DbConnectionStringKeywords.TrustServerCertificate)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_TrustServerCertificate)] @@ -680,7 +688,7 @@ public bool TrustServerCertificate } } - /// + /// [DisplayName(DbConnectionStringKeywords.Enlist)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Pooling)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_Enlist)] @@ -695,7 +703,7 @@ public bool Enlist } } - /// + /// [DisplayName(DbConnectionStringKeywords.FailoverPartner)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Source)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_FailoverPartner)] @@ -711,7 +719,7 @@ public string FailoverPartner } } - /// + /// [DisplayName(DbConnectionStringKeywords.InitialCatalog)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Source)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_InitialCatalog)] @@ -727,7 +735,7 @@ public string InitialCatalog } } - /// + /// [DisplayName(DbConnectionStringKeywords.IntegratedSecurity)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_IntegratedSecurity)] @@ -742,7 +750,7 @@ public bool IntegratedSecurity } } - /// + /// [DisplayName(DbConnectionStringKeywords.Authentication)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_Authentication)] @@ -785,7 +793,8 @@ internal string Certificate } #endif - /// + + /// [DisplayName(DbConnectionStringKeywords.LoadBalanceTimeout)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Pooling)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_LoadBalanceTimeout)] @@ -804,7 +813,7 @@ public int LoadBalanceTimeout } } - /// + /// [DisplayName(DbConnectionStringKeywords.MaxPoolSize)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Pooling)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_MaxPoolSize)] @@ -823,7 +832,7 @@ public int MaxPoolSize } } - /// + /// [DisplayName(DbConnectionStringKeywords.ConnectRetryCount)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_ConnectionResilency)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_ConnectRetryCount)] @@ -842,7 +851,7 @@ public int ConnectRetryCount } } - /// + /// [DisplayName(DbConnectionStringKeywords.ConnectRetryInterval)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_ConnectionResilency)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_ConnectRetryInterval)] @@ -862,7 +871,7 @@ public int ConnectRetryInterval } - /// + /// [DisplayName(DbConnectionStringKeywords.MinPoolSize)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Pooling)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_MinPoolSize)] @@ -881,7 +890,7 @@ public int MinPoolSize } } - /// + /// [DisplayName(DbConnectionStringKeywords.MultipleActiveResultSets)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Advanced)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_MultipleActiveResultSets)] @@ -896,7 +905,7 @@ public bool MultipleActiveResultSets } } - /// + /// [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "Reviewed and Approved by UE")] [DisplayName(DbConnectionStringKeywords.MultiSubnetFailover)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Source)] @@ -912,7 +921,7 @@ public bool MultiSubnetFailover } } - /// + /// [DisplayName(DbConnectionStringKeywords.TransparentNetworkIPResolution)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Source)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_TransparentNetworkIPResolution)] @@ -940,7 +949,7 @@ public string NamedConnection { } } */ - /// + /// [DisplayName(DbConnectionStringKeywords.NetworkLibrary)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Advanced)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_NetworkLibrary)] @@ -988,7 +997,7 @@ public string NetworkLibrary } } - /// + /// [DisplayName(DbConnectionStringKeywords.PacketSize)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Advanced)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_PacketSize)] @@ -1007,7 +1016,7 @@ public int PacketSize } } - /// + /// [DisplayName(DbConnectionStringKeywords.Password)] [PasswordPropertyTextAttribute(true)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] @@ -1023,7 +1032,7 @@ public string Password } } - /// + /// [DisplayName(DbConnectionStringKeywords.PersistSecurityInfo)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_PersistSecurityInfo)] @@ -1038,7 +1047,7 @@ public bool PersistSecurityInfo } } - /// + /// [DisplayName(DbConnectionStringKeywords.Pooling)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Pooling)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_Pooling)] @@ -1053,7 +1062,7 @@ public bool Pooling } } - /// + /// [DisplayName(DbConnectionStringKeywords.Replication)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Replication)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_Replication)] @@ -1068,7 +1077,7 @@ public bool Replication } } - /// + /// [DisplayName(DbConnectionStringKeywords.TransactionBinding)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Advanced)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_TransactionBinding)] @@ -1083,7 +1092,7 @@ public string TransactionBinding } } - /// + /// [DisplayName(DbConnectionStringKeywords.TypeSystemVersion)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Advanced)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_TypeSystemVersion)] @@ -1098,7 +1107,7 @@ public string TypeSystemVersion } } - /// + /// [DisplayName(DbConnectionStringKeywords.UserID)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Security)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_UserID)] @@ -1113,7 +1122,7 @@ public string UserID } } - /// + /// [DisplayName(DbConnectionStringKeywords.UserInstance)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Source)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_UserInstance)] @@ -1128,7 +1137,7 @@ public bool UserInstance } } - /// + /// [DisplayName(DbConnectionStringKeywords.WorkstationID)] [ResCategoryAttribute(StringsHelper.ResourceNames.DataCategory_Context)] [ResDescriptionAttribute(StringsHelper.ResourceNames.DbConnectionString_WorkstationID)] @@ -1143,7 +1152,7 @@ public string WorkstationID } } - /// + /// public override bool IsFixedSize { get @@ -1152,7 +1161,7 @@ public override bool IsFixedSize } } - /// + /// public override ICollection Keys { get @@ -1161,7 +1170,7 @@ public override ICollection Keys } } - /// + /// public override ICollection Values { get @@ -1177,7 +1186,21 @@ public override ICollection Values } } - /// + /// + public bool TruncateScaledDecimal + { + get + { + return _truncateScaledDecimal; + } + set + { + SetValue(DbConnectionStringKeywords.TruncateScaledDecimal, value); + _truncateScaledDecimal = value; + } + } + + /// public override void Clear() { base.Clear(); @@ -1187,7 +1210,7 @@ public override void Clear() } } - /// + /// public override bool ContainsKey(string keyword) { ADP.CheckArgumentNull(keyword, "keyword"); @@ -1329,6 +1352,8 @@ private object GetAt(Keywords index) return EnclaveAttestationUrl; case Keywords.AttestationProtocol: return AttestationProtocol; + case Keywords.TruncateScaledDecimal: + return TruncateScaledDecimal; #if ADONET_CERT_AUTH case Keywords.Certificate: return Certificate; #endif @@ -1376,7 +1401,7 @@ protected override void GetProperties(Hashtable propertyDescriptors) { base.GetProperties(propertyDescriptors); } */ - /// + /// public override bool Remove(string keyword) { ADP.CheckArgumentNull(keyword, "keyword"); @@ -1521,6 +1546,9 @@ private void Reset(Keywords index) case Keywords.AttestationProtocol: _attestationProtocol = DbConnectionStringDefaults.AttestationProtocol; break; + case Keywords.TruncateScaledDecimal: + _truncateScaledDecimal = DbConnectionStringDefaults.TruncateScaledDecimal; + break; default: Debug.Fail("unexpected keyword"); throw ADP.KeywordNotSupported(_validKeywords[(int)index]); @@ -1568,7 +1596,7 @@ private void SetAttestationProtocolValue(SqlConnectionAttestationProtocol value) } - /// + /// public override bool ShouldSerialize(string keyword) { ADP.CheckArgumentNull(keyword, "keyword"); @@ -1576,7 +1604,7 @@ public override bool ShouldSerialize(string keyword) return _keywords.TryGetValue(keyword, out index) && base.ShouldSerialize(_validKeywords[(int)index]); } - /// + /// public override bool TryGetValue(string keyword, out object value) { Keywords index; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 54e707380b..7014b0f09b 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -309,6 +309,14 @@ internal SqlInternalConnectionTds Connection } } + internal bool TruncateScaledDecimal + { + get + { + return _connHandler.ConnectionOptions.TruncateScaledDecimal; + } + } + internal SqlInternalTransaction CurrentTransaction { get @@ -2045,7 +2053,7 @@ internal bool RunReliably(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDat { tdsReliabilitySection.Start(); #endif //DEBUG - return Run(runBehavior, cmdHandler, dataStream, bulkCopyHandler, stateObj); + return Run(runBehavior, cmdHandler, dataStream, bulkCopyHandler, stateObj); #if DEBUG } finally @@ -7721,17 +7729,17 @@ private bool TryReadDecimalBits(int length, TdsParserStateObject stateObj, out i return true; } - static internal SqlDecimal AdjustSqlDecimalScale(SqlDecimal d, int newScale) + static internal SqlDecimal AdjustSqlDecimalScale(SqlDecimal d, int newScale, bool round) { if (d.Scale != newScale) { - return SqlDecimal.AdjustScale(d, newScale - d.Scale, false /* Don't round, truncate. MDAC 69229 */); + return SqlDecimal.AdjustScale(d, newScale - d.Scale, round); } return d; } - static internal decimal AdjustDecimalScale(decimal value, int newScale) + static internal decimal AdjustDecimalScale(decimal value, int newScale, bool round) { int oldScale = (Decimal.GetBits(value)[3] & 0x00ff0000) >> 0x10; @@ -7739,7 +7747,7 @@ static internal decimal AdjustDecimalScale(decimal value, int newScale) { SqlDecimal num = new SqlDecimal(value); - num = SqlDecimal.AdjustScale(num, newScale - oldScale, false /* Don't round, truncate. MDAC 69229 */); + num = SqlDecimal.AdjustScale(num, newScale - oldScale, round); return num.Value; } @@ -9777,9 +9785,10 @@ internal Task TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, int timeout, boo // bug 49512, make sure the value matches the scale the user enters if (!isNull) { + bool roundDecimal = !TruncateScaledDecimal; if (isSqlVal) { - value = AdjustSqlDecimalScale((SqlDecimal)value, scale); + value = AdjustSqlDecimalScale((SqlDecimal)value, scale, roundDecimal); // If Precision is specified, verify value precision vs param precision if (precision != 0) @@ -9792,7 +9801,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, int timeout, boo } else { - value = AdjustDecimalScale((Decimal)value, scale); + value = AdjustDecimalScale((Decimal)value, scale, roundDecimal); SqlDecimal sqlValue = new SqlDecimal((Decimal)value); diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs index 553727b03a..716db64b50 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs @@ -17,6 +17,10 @@ public class SqlConnectionStringBuilderTest [InlineData("WSID = myworkstation")] [InlineData("Application Name = .Net Tests")] [InlineData("Pooling = false")] + [InlineData("Truncate Scaled Decimal = false")] + [InlineData("Truncate Scaled Decimal = no")] + [InlineData("Truncate Scaled Decimal = true")] + [InlineData("Truncate Scaled Decimal = yes")] public void ConnectionStringTests(string connectionString) { ExecuteConnectionStringTests(connectionString); diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionTest.cs index 05035da6ba..8809a79617 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionTest.cs @@ -1082,6 +1082,17 @@ public void ConnectionString_UserInstance_Invalid() } } + [Fact] + public void ConnectionString_TruncateScaledDecimal() + { + SqlConnection cn = new SqlConnection(); + Assert.False(new SqlConnectionStringBuilder(cn.ConnectionString).TruncateScaledDecimal, "The default 'Truncate Scaled Decimal' property expects to be false!"); + cn.ConnectionString = "Truncate Scaled Decimal=false"; + cn.ConnectionString = "Truncate Scaled Decimal=true"; + cn.ConnectionString = "Truncate Scaled Decimal=no"; + cn.ConnectionString = "Truncate Scaled Decimal=yes"; + } + [Fact] public void ConnectionString_OtherKeywords() { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index ea3def41a0..d9f7850f14 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -297,6 +297,30 @@ public static string GetUniqueNameForSqlServer(string prefix) return name; } + public static void DropTable(SqlConnection sqlConnection, string tableName) + { + using (SqlCommand cmd = new SqlCommand(string.Format("IF (OBJECT_ID('{0}') IS NOT NULL) \n DROP TABLE {0}", tableName), sqlConnection)) + { + cmd.ExecuteNonQuery(); + } + } + + public static void DropUserDefinedType(SqlConnection sqlConnection, string typeName) + { + using (SqlCommand cmd = new SqlCommand(string.Format("IF (TYPE_ID('{0}') IS NOT NULL) \n DROP TYPE {0}", typeName), sqlConnection)) + { + cmd.ExecuteNonQuery(); + } + } + + public static void DropStoredProcedure(SqlConnection sqlConnection, string spName) + { + using (SqlCommand cmd = new SqlCommand(string.Format("IF (OBJECT_ID('{0}') IS NOT NULL) \n DROP PROCEDURE {0}", spName), sqlConnection)) + { + cmd.ExecuteNonQuery(); + } + } + public static bool IsLocalDBInstalled() => SupportsLocalDb; public static bool IsIntegratedSecuritySetup() => SupportsIntegratedSecurity; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs index 4125c8578e..447acbd095 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs @@ -4,6 +4,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Data; using System.Data.SqlTypes; using Xunit; @@ -314,6 +315,220 @@ public static void TestParametersWithDatatablesTVPInsert() } } + #region Scaled Decimal Parameter & TVP Test + [Theory] + [ClassData(typeof(ConnectionStringsProvider))] + public static void TestScaledDecimalParameter_CommandInsert(string connectionString, bool truncateScaledDecimal) + { + string tableName = DataTestUtility.GetUniqueNameForSqlServer("TestDecimalParameterCMD"); + using (SqlConnection connection = InitialDatabaseTable(connectionString, tableName)) + { + try + { + using (SqlCommand cmd = connection.CreateCommand()) + { + var p = new SqlParameter("@Value", null); + p.Precision = 18; + p.Scale = 2; + cmd.Parameters.Add(p); + for (int i = 0; i < _testValues.Length; i++) + { + p.Value = _testValues[i]; + cmd.CommandText = $"INSERT INTO {tableName} (Id, [Value]) VALUES({i}, @Value)"; + cmd.ExecuteNonQuery(); + } + } + Assert.True(ValidateInsertedValues(connection, tableName, truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]"); + } + finally + { + DataTestUtility.DropTable(connection, tableName); + } + } + } + + [Theory] + [ClassData(typeof(ConnectionStringsProvider))] + public static void TestScaledDecimalParameter_BulkCopy(string connectionString, bool truncateScaledDecimal) + { + string tableName = DataTestUtility.GetUniqueNameForSqlServer("TestDecimalParameterBC"); + using (SqlConnection connection = InitialDatabaseTable(connectionString, tableName)) + { + try + { + using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection)) + { + DataTable table = new DataTable(tableName); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("Value", typeof(decimal)); + for (int i = 0; i < _testValues.Length; i++) + { + var newRow = table.NewRow(); + newRow["Id"] = i; + newRow["Value"] = _testValues[i]; + table.Rows.Add(newRow); + } + + bulkCopy.DestinationTableName = tableName; + bulkCopy.WriteToServer(table); + } + Assert.True(ValidateInsertedValues(connection, tableName, truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]"); + } + finally + { + DataTestUtility.DropTable(connection, tableName); + } + } + } + + [Theory] + [ClassData(typeof(ConnectionStringsProvider))] + public static void TestScaledDecimalTVP_CommandSP(string connectionString, bool truncateScaledDecimal) + { + string tableName = DataTestUtility.GetUniqueNameForSqlServer("TestDecimalParameterBC"); + string tableTypeName = DataTestUtility.GetUniqueNameForSqlServer("UDTTTestDecimalParameterBC"); + string spName = DataTestUtility.GetUniqueNameForSqlServer("spTestDecimalParameterBC"); + using (SqlConnection connection = InitialDatabaseUDTT(connectionString, tableName, tableTypeName, spName)) + { + try + { + using (SqlCommand cmd = connection.CreateCommand()) + { + var p = new SqlParameter("@tvp", SqlDbType.Structured); + p.TypeName = $"dbo.{tableTypeName}"; + cmd.CommandText = spName; + cmd.CommandType = CommandType.StoredProcedure; + cmd.Parameters.Add(p); + + DataTable table = new DataTable(tableName); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("Value", typeof(decimal)); + for (int i = 0; i < _testValues.Length; i++) + { + var newRow = table.NewRow(); + newRow["Id"] = i; + newRow["Value"] = _testValues[i]; + table.Rows.Add(newRow); + } + p.Value = table; + cmd.ExecuteNonQuery(); + } + // TVP always rounds data without attention to the configuration. + Assert.True(ValidateInsertedValues(connection, tableName, false && truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]"); + } + finally + { + DataTestUtility.DropTable(connection, tableName); + DataTestUtility.DropStoredProcedure(connection, spName); + DataTestUtility.DropUserDefinedType(connection, tableTypeName); + } + } + } + + #region Decimal parameter test setup + private static readonly decimal[] _testValues = new[] { 4210862852.8600000000_0000000000m, 19.1560m, 19.1550m, 19.1549m }; + private static readonly decimal[] _expectedRoundedValues = new[] { 4210862852.86m, 19.16m, 19.16m, 19.15m }; + private static readonly decimal[] _expectedTruncatedValues = new[] { 4210862852.86m, 19.15m, 19.15m, 19.15m }; + + private static SqlConnection InitialDatabaseUDTT(string cnnString, string tableName, string tableTypeName, string spName) + { + SqlConnection connection = new SqlConnection(cnnString); + connection.Open(); + using (SqlCommand cmd = connection.CreateCommand()) + { + cmd.CommandType = CommandType.Text; + cmd.CommandText = $"CREATE TABLE {tableName} (Id INT, Value Decimal(38, 2)) \n"; + cmd.CommandText += $"CREATE TYPE {tableTypeName} AS TABLE (Id INT, Value Decimal(38, 2)) "; + cmd.ExecuteNonQuery(); + cmd.CommandText = $"CREATE PROCEDURE {spName} (@tvp {tableTypeName} READONLY) AS \n INSERT INTO {tableName} (Id, Value) SELECT * FROM @tvp ORDER BY Id"; + cmd.ExecuteNonQuery(); + } + return connection; + } + + private static SqlConnection InitialDatabaseTable(string cnnString, string tableName) + { + SqlConnection connection = new SqlConnection(cnnString); + connection.Open(); + using (SqlCommand cmd = connection.CreateCommand()) + { + cmd.CommandType = CommandType.Text; + cmd.CommandText = $"CREATE TABLE {tableName} (Id INT, Value Decimal(38, 2))"; + cmd.ExecuteNonQuery(); + } + return connection; + } + + private static bool ValidateInsertedValues(SqlConnection connection, string tableName, bool truncateScaledDecimal) + { + bool exceptionHit; + decimal[] expectedValues = truncateScaledDecimal ? _expectedTruncatedValues : _expectedRoundedValues; + + try + { + using (SqlCommand cmd = connection.CreateCommand()) + { + // Verify if the data was as same as our expectation. + cmd.CommandText = $"SELECT [Value] FROM {tableName} ORDER BY Id ASC"; + cmd.CommandType = CommandType.Text; + using (SqlDataReader reader = cmd.ExecuteReader()) + { + DataTable dbData = new DataTable(); + dbData.Load(reader); + Assert.Equal(expectedValues.Length, dbData.Rows.Count); + for (int i = 0; i < expectedValues.Length; i++) + { + Assert.Equal(expectedValues[i], dbData.Rows[i][0]); + } + } + } + exceptionHit = false; + } + catch + { + exceptionHit = true; + } + return !exceptionHit; + } + + public class ConnectionStringsProvider : IEnumerable + { + public IEnumerator GetEnumerator() + { + var cnnStringBuilder = new SqlConnectionStringBuilder(); + + if (!string.IsNullOrEmpty(DataTestUtility.TCPConnectionString)) + { + cnnStringBuilder.ConnectionString = DataTestUtility.TCPConnectionString; + cnnStringBuilder.TruncateScaledDecimal = false; + yield return new object[] { cnnStringBuilder.ConnectionString, false }; + cnnStringBuilder.TruncateScaledDecimal = true; + yield return new object[] { cnnStringBuilder.ConnectionString, true }; + } + else if (!string.IsNullOrEmpty(DataTestUtility.NPConnectionString)) + { + cnnStringBuilder.ConnectionString = DataTestUtility.NPConnectionString; + cnnStringBuilder.TruncateScaledDecimal = false; + yield return new object[] { cnnStringBuilder.ConnectionString, false }; + cnnStringBuilder.TruncateScaledDecimal = true; + yield return new object[] { cnnStringBuilder.ConnectionString, true }; + } + + foreach (string connStrAE in DataTestUtility.AEConnStrings) + { + cnnStringBuilder.ConnectionString = connStrAE; + cnnStringBuilder.TruncateScaledDecimal = false; + yield return new object[] { cnnStringBuilder.ConnectionString, false }; + cnnStringBuilder.TruncateScaledDecimal = true; + yield return new object[] { cnnStringBuilder.ConnectionString, true }; + } + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + #endregion + #endregion + private enum MyEnum { A = 1, 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 a982cfc20b..882aa2bc0f 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 @@ -483,14 +483,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 1 ++++++++ ------IEnumerable--------- @@ -499,14 +499,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 2 ++++++++ ------IEnumerable--------- @@ -515,14 +515,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 3 ++++++++ ------IEnumerable--------- @@ -531,14 +531,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 4 ++++++++ ------IEnumerable--------- @@ -547,14 +547,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 5 ++++++++ ------IEnumerable--------- @@ -563,14 +563,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 6 ++++++++ SqlException creating objects: 1701 @@ -582,14 +582,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 8 ++++++++ ------IEnumerable--------- @@ -598,14 +598,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 9 ++++++++ ------IEnumerable--------- @@ -614,14 +614,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 10 ++++++++ ------IEnumerable--------- @@ -630,14 +630,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 11 ++++++++ ------IEnumerable--------- @@ -646,14 +646,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 12 ++++++++ ------IEnumerable--------- @@ -662,14 +662,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 13 ++++++++ ------IEnumerable--------- @@ -678,14 +678,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 14 ++++++++ SqlException creating objects: 1701 @@ -700,14 +700,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 17 ++++++++ ------IEnumerable--------- @@ -716,14 +716,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 18 ++++++++ ------IEnumerable--------- @@ -732,14 +732,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 19 ++++++++ ------IEnumerable--------- @@ -748,14 +748,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 20 ++++++++ ------IEnumerable--------- @@ -765,13 +765,13 @@ Matches = 168 ------DataTables--------- Matches = 14 Matches = 14 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 Matches = 28 Matches = 14 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 Matches = 14 Matches = 14 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 21 ++++++++ ------IEnumerable--------- @@ -781,13 +781,13 @@ Matches = 168 ------DataTables--------- Matches = 14 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 22 ++++++++ SqlException creating objects: 1701 @@ -841,14 +841,14 @@ Mismatch: Source = 1/1/1753 12:00:00 AM, result = , metadata=SteAttributeKey=Sma Matches = 162 ------DataTables--------- SqlException. Error Code: 242 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 26 ++++++++ ------IEnumerable--------- @@ -857,14 +857,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 27 ++++++++ ------IEnumerable--------- @@ -933,14 +933,14 @@ Mismatch: Source = 922337203685477.5807, result = , metadata=SteAttributeKey=Sma Matches = 158 ------DataTables--------- SqlException. Error Code: 242 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 SqlException. Error Code: 8115 ------- Sort order + uniqueness #1: simple ------- ------------- 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 533901f356..b080cee9fb 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 @@ -22,14 +22,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 1 ++++++++ ------IEnumerable--------- @@ -38,14 +38,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 2 ++++++++ ------IEnumerable--------- @@ -54,14 +54,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 3 ++++++++ ------IEnumerable--------- @@ -70,14 +70,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 4 ++++++++ ------IEnumerable--------- @@ -86,14 +86,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 5 ++++++++ ------IEnumerable--------- @@ -102,14 +102,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 6 ++++++++ SqlException creating objects: 1701 @@ -121,14 +121,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 8 ++++++++ ------IEnumerable--------- @@ -137,14 +137,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 9 ++++++++ ------IEnumerable--------- @@ -153,14 +153,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 10 ++++++++ ------IEnumerable--------- @@ -169,14 +169,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 11 ++++++++ ------IEnumerable--------- @@ -185,14 +185,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 12 ++++++++ ------IEnumerable--------- @@ -201,14 +201,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 13 ++++++++ ------IEnumerable--------- @@ -217,14 +217,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 14 ++++++++ SqlException creating objects: 1701 @@ -239,14 +239,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 17 ++++++++ ------IEnumerable--------- @@ -255,14 +255,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 18 ++++++++ ------IEnumerable--------- @@ -271,14 +271,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 19 ++++++++ ------IEnumerable--------- @@ -287,14 +287,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 20 ++++++++ ------IEnumerable--------- @@ -304,13 +304,13 @@ Matches = 168 ------DataTables--------- Matches = 14 Matches = 14 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 Matches = 28 Matches = 14 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 Matches = 14 Matches = 14 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 21 ++++++++ ------IEnumerable--------- @@ -320,13 +320,13 @@ Matches = 168 ------DataTables--------- Matches = 14 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 22 ++++++++ SqlException creating objects: 1701 @@ -380,14 +380,14 @@ Mismatch: Source = 1/1/1753 12:00:00 AM, result = , metadata=SteAttributeKey=Sma Matches = 162 ------DataTables--------- SqlException. Error Code: 242 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 26 ++++++++ ------IEnumerable--------- @@ -396,14 +396,14 @@ Matches = 168 Matches = 168 ------DataTables--------- Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 28 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 Matches = 14 +++++++ Iteration 27 ++++++++ ------IEnumerable--------- @@ -472,14 +472,14 @@ Mismatch: Source = 922337203685477.5807, result = , metadata=SteAttributeKey=Sma Matches = 158 ------DataTables--------- SqlException. Error Code: 242 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 -SqlException. Error Code: 8152 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 +SqlException. Error Code: 2628 SqlException. Error Code: 8115 ------- Sort order + uniqueness #1: simple ------- ------------- 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..95d8ea8264 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs @@ -254,7 +254,6 @@ private void ColumnBoundariesTest() { IEnumerator boundsMD = SteStructuredTypeBoundaries.AllColumnTypesExceptUdts.GetEnumerator( BoundariesTestKeys); - TestTVPPermutations(SteStructuredTypeBoundaries.AllColumnTypesExceptUdts, false); //Console.WriteLine("+++++++++++ UDT TVP tests ++++++++++++++"); //TestTVPPermutations(SteStructuredTypeBoundaries.UdtsOnly, true); @@ -1163,9 +1162,15 @@ private void ExecuteAndVerify(SqlCommand cmd, StePermutation tvpPerm, object[][] { conn.Open(); cmd.Connection = conn; - // cmd.Transaction = conn.BeginTransaction(); + if (DataTestUtility.IsNotAzureServer()) + { + // Chose the 2628 error message instead of 8152 in SQL Server 2016 & 2017 + using (SqlCommand cmdFix = new SqlCommand("DBCC TRACEON(460)", conn)) + { + cmdFix.ExecuteNonQuery(); + } + } - // and run the command try { using (SqlDataReader rdr = cmd.ExecuteReader()) @@ -1185,13 +1190,6 @@ private void ExecuteAndVerify(SqlCommand cmd, StePermutation tvpPerm, object[][] { Console.WriteLine("ArgumentException: {0}", ae.Message); } - - // And clean up. If an error is thrown, the connection being recycled - // will roll back the transaction - if (null != cmd.Transaction) - { - // cmd.Transaction.Rollback(); - } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/AdjustPrecScaleForBulkCopy.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/AdjustPrecScaleForBulkCopy.cs index a1eb2f2fb1..27f4ebb79b 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/AdjustPrecScaleForBulkCopy.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/AdjustPrecScaleForBulkCopy.cs @@ -27,7 +27,7 @@ public static void RunTest() Assert.Equal("12.3", value.ToString()); value = BulkCopySqlDecimalToTable(new SqlDecimal(123.45), 10, 2, 4, 1); - Assert.Equal("123.4", value.ToString()); + Assert.Equal("123.5", value.ToString()); Assert.Throws(() => BulkCopySqlDecimalToTable(new SqlDecimal(111.00), 7, 2, 2, 0)); }