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