From 4fbfdc4d24c9608cd536568b41538741a26f18cd Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 11:33:01 -0700 Subject: [PATCH 01/23] Make `TruncateToNetDecimal()` be `safe` --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 354 ++++++++---------- 1 file changed, 161 insertions(+), 193 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index 6f9d8f0b4d..c75431524d 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -4,219 +4,187 @@ // Created by: Alexey Kulakov // Created: 2020.04.10 -using System; -using System.Collections.Generic; using Microsoft.Data.SqlClient; using System.Data.SqlTypes; -using System.Diagnostics.Metrics; using Xtensive.Diagnostics; -namespace Xtensive.Sql.Drivers.SqlServer +namespace Xtensive.Sql.Drivers.SqlServer; + +internal static class InternalHelpers { - internal static class InternalHelpers + private static readonly UInt128[] PowersOf10 = [ + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000 + ]; + + private static readonly UInt128 Max96bitValue = new(0xFFFFFFFFUL, ulong.MaxValue); + + /// + /// This API supports the Entity Framework Core infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + public static bool ShouldRetryOn(Exception ex) { - private static readonly uint[] PowersOf10 = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000 - }; - - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - public static bool ShouldRetryOn(Exception ex) - { - ArgumentNullException.ThrowIfNull(ex); - if (ex is SqlException sqlException) { - foreach (SqlError err in sqlException.Errors) { - Metrics.SqlErrorCounter.Add(1, KeyValuePair.Create("Code", (object)err.Number)); - } + ArgumentNullException.ThrowIfNull(ex); + if (ex is SqlException sqlException) { + foreach (SqlError err in sqlException.Errors) { + Metrics.SqlErrorCounter.Add(1, KeyValuePair.Create("Code", (object)err.Number)); + } - foreach (SqlError err in sqlException.Errors) { - switch (err.Number) { - // SQL Error Code: 49920 - // Cannot process request. Too many operations in progress for subscription "%ld". - // The service is busy processing multiple requests for this subscription. - // Requests are currently blocked for resource optimization. Query sys.dm_operation_status for operation status. - // Wait until pending requests are complete or delete one of your pending requests and retry your request later. - case 49920: - // SQL Error Code: 49919 - // Cannot process create or update request. Too many create or update operations in progress for subscription "%ld". - // The service is busy processing multiple create or update requests for your subscription or server. - // Requests are currently blocked for resource optimization. Query sys.dm_operation_status for pending operations. - // Wait till pending create or update requests are complete or delete one of your pending requests and - // retry your request later. - case 49919: - // SQL Error Code: 49918 - // Cannot process request. Not enough resources to process request. - // The service is currently busy.Please retry the request later. - case 49918: - // SQL Error Code: 41839 - // Transaction exceeded the maximum number of commit dependencies. - case 41839: - // SQL Error Code: 41325 - // The current transaction failed to commit due to a serializable validation failure. - case 41325: - // SQL Error Code: 41305 - // The current transaction failed to commit due to a repeatable read validation failure. - case 41305: - // SQL Error Code: 41302 - // The current transaction attempted to update a record that has been updated since the transaction started. - case 41302: - // SQL Error Code: 41301 - // Dependency failure: a dependency was taken on another transaction that later failed to commit. - case 41301: - // SQL Error Code: 40613 - // Database XXXX on server YYYY is not currently available. Please retry the connection later. - // If the problem persists, contact customer support, and provide them the session tracing ID of ZZZZZ. - case 40613: - // SQL Error Code: 40501 - // The service is currently busy. Retry the request after 10 seconds. Code: (reason code to be decoded). - case 40501: - // SQL Error Code: 40197 - // The service has encountered an error processing your request. Please try again. - case 40197: - // SQL Error Code: 10929 - // Resource ID: %d. The %s minimum guarantee is %d, maximum limit is %d and the current usage for the database is %d. - // However, the server is currently too busy to support requests greater than %d for this database. - // For more information, see http://go.microsoft.com/fwlink/?LinkId=267637. Otherwise, please try again. - case 10929: - // SQL Error Code: 10928 - // Resource ID: %d. The %s limit for the database is %d and has been reached. For more information, - // see http://go.microsoft.com/fwlink/?LinkId=267637. - case 10928: - // SQL Error Code: 10060 - // A network-related or instance-specific error occurred while establishing a connection to SQL Server. - // The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server - // is configured to allow remote connections. (provider: TCP Provider, error: 0 - A connection attempt failed - // because the connected party did not properly respond after a period of time, or established connection failed - // because connected host has failed to respond.)"} - case 10060: - // SQL Error Code: 10054 - // A transport-level error has occurred when sending the request to the server. - // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) - case 10054: - // SQL Error Code: 10053 - // A transport-level error has occurred when receiving results from the server. - // An established connection was aborted by the software in your host machine. - case 10053: - // SQL Error Code: 1205 - // Deadlock - case 1205: - // SQL Error Code: 233 - // The client was unable to establish a connection because of an error during connection initialization process before login. - // Possible causes include the following: the client tried to connect to an unsupported version of SQL Server; - // the server was too busy to accept new connections; or there was a resource limitation (insufficient memory or maximum - // allowed connections) on the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by - // the remote host.) - case 233: - // SQL Error Code: 121 - // The semaphore timeout period has expired - case 121: - // SQL Error Code: 64 - // A connection was successfully established with the server, but then an error occurred during the login process. - // (provider: TCP Provider, error: 0 - The specified network name is no longer available.) - case 64: - // DBNETLIB Error Code: 20 - // The instance of SQL Server you attempted to connect to does not support encryption. - case 20: - return true; - // This exception can be thrown even if the operation completed successfully, so it's safer to let the application fail. - // DBNETLIB Error Code: -2 - // Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. The statement has been terminated. - //case -2: - } + foreach (SqlError err in sqlException.Errors) { + switch (err.Number) { + // SQL Error Code: 49920 + // Cannot process request. Too many operations in progress for subscription "%ld". + // The service is busy processing multiple requests for this subscription. + // Requests are currently blocked for resource optimization. Query sys.dm_operation_status for operation status. + // Wait until pending requests are complete or delete one of your pending requests and retry your request later. + case 49920: + // SQL Error Code: 49919 + // Cannot process create or update request. Too many create or update operations in progress for subscription "%ld". + // The service is busy processing multiple create or update requests for your subscription or server. + // Requests are currently blocked for resource optimization. Query sys.dm_operation_status for pending operations. + // Wait till pending create or update requests are complete or delete one of your pending requests and + // retry your request later. + case 49919: + // SQL Error Code: 49918 + // Cannot process request. Not enough resources to process request. + // The service is currently busy.Please retry the request later. + case 49918: + // SQL Error Code: 41839 + // Transaction exceeded the maximum number of commit dependencies. + case 41839: + // SQL Error Code: 41325 + // The current transaction failed to commit due to a serializable validation failure. + case 41325: + // SQL Error Code: 41305 + // The current transaction failed to commit due to a repeatable read validation failure. + case 41305: + // SQL Error Code: 41302 + // The current transaction attempted to update a record that has been updated since the transaction started. + case 41302: + // SQL Error Code: 41301 + // Dependency failure: a dependency was taken on another transaction that later failed to commit. + case 41301: + // SQL Error Code: 40613 + // Database XXXX on server YYYY is not currently available. Please retry the connection later. + // If the problem persists, contact customer support, and provide them the session tracing ID of ZZZZZ. + case 40613: + // SQL Error Code: 40501 + // The service is currently busy. Retry the request after 10 seconds. Code: (reason code to be decoded). + case 40501: + // SQL Error Code: 40197 + // The service has encountered an error processing your request. Please try again. + case 40197: + // SQL Error Code: 10929 + // Resource ID: %d. The %s minimum guarantee is %d, maximum limit is %d and the current usage for the database is %d. + // However, the server is currently too busy to support requests greater than %d for this database. + // For more information, see http://go.microsoft.com/fwlink/?LinkId=267637. Otherwise, please try again. + case 10929: + // SQL Error Code: 10928 + // Resource ID: %d. The %s limit for the database is %d and has been reached. For more information, + // see http://go.microsoft.com/fwlink/?LinkId=267637. + case 10928: + // SQL Error Code: 10060 + // A network-related or instance-specific error occurred while establishing a connection to SQL Server. + // The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server + // is configured to allow remote connections. (provider: TCP Provider, error: 0 - A connection attempt failed + // because the connected party did not properly respond after a period of time, or established connection failed + // because connected host has failed to respond.)"} + case 10060: + // SQL Error Code: 10054 + // A transport-level error has occurred when sending the request to the server. + // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) + case 10054: + // SQL Error Code: 10053 + // A transport-level error has occurred when receiving results from the server. + // An established connection was aborted by the software in your host machine. + case 10053: + // SQL Error Code: 1205 + // Deadlock + case 1205: + // SQL Error Code: 233 + // The client was unable to establish a connection because of an error during connection initialization process before login. + // Possible causes include the following: the client tried to connect to an unsupported version of SQL Server; + // the server was too busy to accept new connections; or there was a resource limitation (insufficient memory or maximum + // allowed connections) on the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by + // the remote host.) + case 233: + // SQL Error Code: 121 + // The semaphore timeout period has expired + case 121: + // SQL Error Code: 64 + // A connection was successfully established with the server, but then an error occurred during the login process. + // (provider: TCP Provider, error: 0 - The specified network name is no longer available.) + case 64: + // DBNETLIB Error Code: 20 + // The instance of SQL Server you attempted to connect to does not support encryption. + case 20: + return true; + // This exception can be thrown even if the operation completed successfully, so it's safer to let the application fail. + // DBNETLIB Error Code: -2 + // Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. The statement has been terminated. + //case -2: } - - return false; } - Metrics.SqlErrorCounter.Add(1, KeyValuePair.Create("Code", (object)ex.GetType().Name)); - return ex is TimeoutException; + return false; } - internal static unsafe decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) - { - var inputData = sqlDecimal.Data; - var scale = sqlDecimal.Scale; + Metrics.SqlErrorCounter.Add(1, KeyValuePair.Create("Code", (object)ex.GetType().Name)); + return ex is TimeoutException; + } + + internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) + { + var inputData = sqlDecimal.Data; + var scale = sqlDecimal.Scale; - if (inputData[3] == 0) { - if (scale <= 28) { - return sqlDecimal.Value; - } - } - else if (scale == 0) { - return sqlDecimal.Value; // throws OverflowException. + if (inputData[3] == 0) { + if (scale <= 28) { + return sqlDecimal.Value; } + } + else if (scale == 0) { + return sqlDecimal.Value; // throws OverflowException. + } - fixed (int* inputS = inputData) { - var input = (uint*) inputS; - byte maxZeroCount = 0; - while (maxZeroCount < scale && (input[maxZeroCount >> 6] & (1 << maxZeroCount)) == 0) { - maxZeroCount++; - } + byte maxZeroCount = 0; + while (maxZeroCount < scale && (inputData[maxZeroCount >> 6] & (1 << maxZeroCount)) == 0) { + maxZeroCount++; + } + + var realScale = scale; + var dividerPow = maxZeroCount > 9 ? (byte) 9 : maxZeroCount; + + UInt128 data = new((ulong)inputData[2] | ((ulong)inputData[3] << 32), + (ulong)inputData[0] | ((ulong)inputData[1] << 32)); - var realScale = scale; - var outputData = sqlDecimal.Data; - fixed (int* outputS = outputData) { - var output = (uint*) outputS; - var dividerPow = maxZeroCount > 9 ? (byte) 9 : maxZeroCount; - if (dividerPow > 5) { - var divider = PowersOf10[dividerPow]; - for (byte length = 4; realScale >= dividerPow; realScale -= dividerPow) { - if (DivHasRem(input, ref length, divider)) { - break; - } - - output[0] = input[0]; - output[1] = input[1]; - output[2] = input[2]; - output[3] = input[3]; - } - } - - for (byte length = 4; realScale > 0 && output[3] != 0; realScale--) { - _ = DivHasRem(output, ref length, 10); - } - - if (output[3] != 0) { - return sqlDecimal.Value; // throws OverflowException. - } - - return new decimal(outputS[0], outputS[1], outputS[2], !sqlDecimal.IsPositive, realScale); + if (dividerPow > 5) { + var divider = PowersOf10[dividerPow]; + for (; realScale >= dividerPow; realScale -= dividerPow) { + (data, var rem) = UInt128.DivRem(data, divider); + if (rem != 0) { + break; } } } - private static unsafe bool DivHasRem(uint* bits, ref byte length, uint divider) - { - unchecked { - ulong rem = 0; - var tempBits = bits + length; - for (byte i = 0; i < length; i++) { - var bit = *(--tempBits); - if (bit == 0 && i == 0) { - length--; - i--; - continue; - } - - var num = (rem << 32) + bit; - bit = (uint) (num / divider); - rem = (uint) (num - (ulong) bit * divider); - *tempBits = bit; - } + for (; realScale > 0 && data > Max96bitValue; realScale--) { + (data, _) = UInt128.DivRem(data, 10); + } - return rem > 0; - } + if (data > Max96bitValue) { + return sqlDecimal.Value; // throws OverflowException. } + + return new((int) data, (int) (data >> 32), (int) (data >> 64), !sqlDecimal.IsPositive, realScale); } -} \ No newline at end of file +} From 8ddfbf4695c4ea4870fe4302981de613f5e8049e Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 11:44:00 -0700 Subject: [PATCH 02/23] Ten value --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index c75431524d..b96c416bca 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -27,6 +27,8 @@ internal static class InternalHelpers private static readonly UInt128 Max96bitValue = new(0xFFFFFFFFUL, ulong.MaxValue); + private static readonly UInt128 Ten = 10; + /// /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. @@ -178,7 +180,7 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) } for (; realScale > 0 && data > Max96bitValue; realScale--) { - (data, _) = UInt128.DivRem(data, 10); + (data, _) = UInt128.DivRem(data, Ten); } if (data > Max96bitValue) { From e8695d19c3f599914da7036e14faaba0dc2c1a22 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 13:28:10 -0700 Subject: [PATCH 03/23] Update Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index b96c416bca..ac92bc0bc5 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -166,8 +166,7 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) var realScale = scale; var dividerPow = maxZeroCount > 9 ? (byte) 9 : maxZeroCount; - UInt128 data = new((ulong)inputData[2] | ((ulong)inputData[3] << 32), - (ulong)inputData[0] | ((ulong)inputData[1] << 32)); + UInt128 data = FromSqlDecimalData(inputData); if (dividerPow > 5) { var divider = PowersOf10[dividerPow]; From 68b5084a855651f32f10928d5d39602f4823134f Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 13:31:41 -0700 Subject: [PATCH 04/23] FromSqlDecimalData() --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index ac92bc0bc5..a9ce70121e 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -144,6 +144,10 @@ public static bool ShouldRetryOn(Exception ex) return ex is TimeoutException; } + private static UInt128 FromSqlDecimalData(int[] a) => + new((uint) a[0] | ((ulong) (uint) a[1] << 32), + (uint) a[2] | ((ulong) (uint) a[3] << 32)); + internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) { var inputData = sqlDecimal.Data; @@ -166,7 +170,7 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) var realScale = scale; var dividerPow = maxZeroCount > 9 ? (byte) 9 : maxZeroCount; - UInt128 data = FromSqlDecimalData(inputData); + var data = FromSqlDecimalData(inputData); if (dividerPow > 5) { var divider = PowersOf10[dividerPow]; From ba33915f1e24335b7fe9dc0d1094c14cfa5ffe53 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 14:49:27 -0700 Subject: [PATCH 05/23] Update Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs Co-authored-by: Sergey Naumenko <152863015+snaumenko-st@users.noreply.github.com> --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index a9ce70121e..a43531ea0d 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -162,10 +162,9 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) return sqlDecimal.Value; // throws OverflowException. } - byte maxZeroCount = 0; - while (maxZeroCount < scale && (inputData[maxZeroCount >> 6] & (1 << maxZeroCount)) == 0) { - maxZeroCount++; - } + byte maxZeroCount = (byte)BitOperations.TrailingZeroCount(inputData[0]); + if (maxZeroCount > scale) + maxZeroCount = scale; var realScale = scale; var dividerPow = maxZeroCount > 9 ? (byte) 9 : maxZeroCount; From 8d460355c669107d2255aded3b58c30be296c905 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 14:49:34 -0700 Subject: [PATCH 06/23] Update Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs Co-authored-by: Sergey Naumenko <152863015+snaumenko-st@users.noreply.github.com> --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index a43531ea0d..d207380368 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -6,6 +6,7 @@ using Microsoft.Data.SqlClient; using System.Data.SqlTypes; +using System.Numerics; using Xtensive.Diagnostics; namespace Xtensive.Sql.Drivers.SqlServer; From ed2eef4b99b6465a46efd28d9ecf4dfcc30810d8 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 14:54:05 -0700 Subject: [PATCH 07/23] Simplify --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index d207380368..9ad22c09dd 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -152,7 +152,7 @@ private static UInt128 FromSqlDecimalData(int[] a) => internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) { var inputData = sqlDecimal.Data; - var scale = sqlDecimal.Scale; + int scale = sqlDecimal.Scale; if (inputData[3] == 0) { if (scale <= 28) { @@ -163,13 +163,9 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) return sqlDecimal.Value; // throws OverflowException. } - byte maxZeroCount = (byte)BitOperations.TrailingZeroCount(inputData[0]); - if (maxZeroCount > scale) - maxZeroCount = scale; - + var maxZeroCount = Math.Min(scale, BitOperations.TrailingZeroCount(inputData[0])); + var dividerPow = Math.Min(maxZeroCount, 9); var realScale = scale; - var dividerPow = maxZeroCount > 9 ? (byte) 9 : maxZeroCount; - var data = FromSqlDecimalData(inputData); if (dividerPow > 5) { From 7b4db8e8a6922126204d1e234a8423685e885fd6 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 14:56:15 -0700 Subject: [PATCH 08/23] Pattern --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index 9ad22c09dd..785f0a4eb6 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -164,11 +164,10 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) } var maxZeroCount = Math.Min(scale, BitOperations.TrailingZeroCount(inputData[0])); - var dividerPow = Math.Min(maxZeroCount, 9); var realScale = scale; var data = FromSqlDecimalData(inputData); - if (dividerPow > 5) { + if (Math.Min(maxZeroCount, 9) is > 5 and var dividerPow) { var divider = PowersOf10[dividerPow]; for (; realScale >= dividerPow; realScale -= dividerPow) { (data, var rem) = UInt128.DivRem(data, divider); From 5c46d9d595445e0ab1a4ba876cf82bb9efd9e143 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 14:59:59 -0700 Subject: [PATCH 09/23] Fix casting --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index 785f0a4eb6..4cf0e41f67 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -185,6 +185,6 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) return sqlDecimal.Value; // throws OverflowException. } - return new((int) data, (int) (data >> 32), (int) (data >> 64), !sqlDecimal.IsPositive, realScale); + return new((int) data, (int) (data >> 32), (int) (data >> 64), !sqlDecimal.IsPositive, (byte) realScale); } } From efec23960e44401a5ff2484177811d8abc78a343 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:01:01 -0700 Subject: [PATCH 10/23] Fix order of UInt128 parts --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index 4cf0e41f67..d6c58045bf 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -146,8 +146,7 @@ public static bool ShouldRetryOn(Exception ex) } private static UInt128 FromSqlDecimalData(int[] a) => - new((uint) a[0] | ((ulong) (uint) a[1] << 32), - (uint) a[2] | ((ulong) (uint) a[3] << 32)); + new((uint) a[2] | ((ulong) (uint) a[3] << 32), (uint) a[0] | ((ulong) (uint) a[1] << 32)); internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) { From c8dbd00f3efd3cdbe4ad3d88120e0d2dd1355f90 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:03:57 -0700 Subject: [PATCH 11/23] Simplify --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 32 ++----------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index d6c58045bf..d22a5fb494 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -6,26 +6,12 @@ using Microsoft.Data.SqlClient; using System.Data.SqlTypes; -using System.Numerics; using Xtensive.Diagnostics; namespace Xtensive.Sql.Drivers.SqlServer; internal static class InternalHelpers { - private static readonly UInt128[] PowersOf10 = [ - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000 - ]; - private static readonly UInt128 Max96bitValue = new(0xFFFFFFFFUL, ulong.MaxValue); private static readonly UInt128 Ten = 10; @@ -151,7 +137,7 @@ private static UInt128 FromSqlDecimalData(int[] a) => internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) { var inputData = sqlDecimal.Data; - int scale = sqlDecimal.Scale; + var scale = sqlDecimal.Scale; if (inputData[3] == 0) { if (scale <= 28) { @@ -162,21 +148,9 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) return sqlDecimal.Value; // throws OverflowException. } - var maxZeroCount = Math.Min(scale, BitOperations.TrailingZeroCount(inputData[0])); - var realScale = scale; var data = FromSqlDecimalData(inputData); - if (Math.Min(maxZeroCount, 9) is > 5 and var dividerPow) { - var divider = PowersOf10[dividerPow]; - for (; realScale >= dividerPow; realScale -= dividerPow) { - (data, var rem) = UInt128.DivRem(data, divider); - if (rem != 0) { - break; - } - } - } - - for (; realScale > 0 && data > Max96bitValue; realScale--) { + for (; scale > 0 && data > Max96bitValue; --scale) { (data, _) = UInt128.DivRem(data, Ten); } @@ -184,6 +158,6 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) return sqlDecimal.Value; // throws OverflowException. } - return new((int) data, (int) (data >> 32), (int) (data >> 64), !sqlDecimal.IsPositive, (byte) realScale); + return new((int) data, (int) (data >> 32), (int) (data >> 64), !sqlDecimal.IsPositive, scale); } } From 81456c9de5a9bc535db689fc2a37c36ea01dc0db Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:12:54 -0700 Subject: [PATCH 12/23] Simplify --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index d22a5fb494..ec64912b32 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -139,25 +139,17 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) var inputData = sqlDecimal.Data; var scale = sqlDecimal.Scale; - if (inputData[3] == 0) { - if (scale <= 28) { - return sqlDecimal.Value; - } - } - else if (scale == 0) { - return sqlDecimal.Value; // throws OverflowException. - } - - var data = FromSqlDecimalData(inputData); + if (scale > 28 || scale > 0 && inputData[3] != 0) { + var data = FromSqlDecimalData(inputData); - for (; scale > 0 && data > Max96bitValue; --scale) { - (data, _) = UInt128.DivRem(data, Ten); - } + for (; scale > 0 && data > Max96bitValue; --scale) { + (data, _) = UInt128.DivRem(data, Ten); + } - if (data > Max96bitValue) { - return sqlDecimal.Value; // throws OverflowException. + if (data <= Max96bitValue) { + return new((int) data, (int) (data >> 32), (int) (data >> 64), !sqlDecimal.IsPositive, scale); + } } - - return new((int) data, (int) (data >> 32), (int) (data >> 64), !sqlDecimal.IsPositive, scale); + return sqlDecimal.Value; // throws OverflowException is the value is out of decimal range. } } From a87ca734fc66197a90ced89f08dca767135b03fb Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:15:16 -0700 Subject: [PATCH 13/23] u128 --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index ec64912b32..0e8232655c 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -140,14 +140,14 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) var scale = sqlDecimal.Scale; if (scale > 28 || scale > 0 && inputData[3] != 0) { - var data = FromSqlDecimalData(inputData); + var u128 = FromSqlDecimalData(inputData); - for (; scale > 0 && data > Max96bitValue; --scale) { - (data, _) = UInt128.DivRem(data, Ten); + for (; scale > 0 && u128 > Max96bitValue; --scale) { + (u128, _) = UInt128.DivRem(u128, Ten); } - if (data <= Max96bitValue) { - return new((int) data, (int) (data >> 32), (int) (data >> 64), !sqlDecimal.IsPositive, scale); + if (u128 <= Max96bitValue) { + return new((int) u128, (int) (u128 >> 32), (int) (u128 >> 64), !sqlDecimal.IsPositive, scale); } } return sqlDecimal.Value; // throws OverflowException is the value is out of decimal range. From 58b3eedde2b3c84aa8abef0edfd265ba8bf21b8f Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:16:21 -0700 Subject: [PATCH 14/23] Simplify --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index 0e8232655c..dc7f6cf922 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -137,9 +137,7 @@ private static UInt128 FromSqlDecimalData(int[] a) => internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) { var inputData = sqlDecimal.Data; - var scale = sqlDecimal.Scale; - - if (scale > 28 || scale > 0 && inputData[3] != 0) { + if (sqlDecimal.Scale is var scale && (scale > 28 || scale > 0 && inputData[3] != 0)) { var u128 = FromSqlDecimalData(inputData); for (; scale > 0 && u128 > Max96bitValue; --scale) { @@ -148,7 +146,7 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) if (u128 <= Max96bitValue) { return new((int) u128, (int) (u128 >> 32), (int) (u128 >> 64), !sqlDecimal.IsPositive, scale); - } + } } return sqlDecimal.Value; // throws OverflowException is the value is out of decimal range. } From 8e121a6b5f5bff2ff7ed3f0c9e815c6ddbc57e60 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:17:37 -0700 Subject: [PATCH 15/23] Simplify --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index dc7f6cf922..5ae5cf50ba 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -137,7 +137,7 @@ private static UInt128 FromSqlDecimalData(int[] a) => internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) { var inputData = sqlDecimal.Data; - if (sqlDecimal.Scale is var scale && (scale > 28 || scale > 0 && inputData[3] != 0)) { + if (sqlDecimal.Scale is var scale && (scale > 28 || inputData[3] != 0)) { var u128 = FromSqlDecimalData(inputData); for (; scale > 0 && u128 > Max96bitValue; --scale) { From 7a05b387183c3e8e6e70e3f38de9b1fde05298a3 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:30:41 -0700 Subject: [PATCH 16/23] Try Catch --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index 5ae5cf50ba..dca8fe7a0e 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -136,18 +136,21 @@ private static UInt128 FromSqlDecimalData(int[] a) => internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) { - var inputData = sqlDecimal.Data; - if (sqlDecimal.Scale is var scale && (scale > 28 || inputData[3] != 0)) { + try { + return sqlDecimal.Value; // throws OverflowException is the value is out of decimal range. + } + catch (OverflowException) { + var inputData = sqlDecimal.Data; + var scale = sqlDecimal.Scale; var u128 = FromSqlDecimalData(inputData); for (; scale > 0 && u128 > Max96bitValue; --scale) { (u128, _) = UInt128.DivRem(u128, Ten); } - if (u128 <= Max96bitValue) { - return new((int) u128, (int) (u128 >> 32), (int) (u128 >> 64), !sqlDecimal.IsPositive, scale); - } + return u128 <= Max96bitValue + ? new((int) u128, (int) (u128 >> 32), (int) (u128 >> 64), !sqlDecimal.IsPositive, scale) + : throw; } - return sqlDecimal.Value; // throws OverflowException is the value is out of decimal range. } } From c8212d4cb4241a10ee4d7c0acf207b43a1db6b16 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:32:48 -0700 Subject: [PATCH 17/23] Typo --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index dca8fe7a0e..3d8cab74f9 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -137,7 +137,7 @@ private static UInt128 FromSqlDecimalData(int[] a) => internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) { try { - return sqlDecimal.Value; // throws OverflowException is the value is out of decimal range. + return sqlDecimal.Value; // throws OverflowException if the value is out of decimal range. } catch (OverflowException) { var inputData = sqlDecimal.Data; From 734769a3d9d89a53b3fa7b189eddd44ab967ad0b Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:34:19 -0700 Subject: [PATCH 18/23] add comment --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index 3d8cab74f9..eb74acd6a5 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -140,7 +140,7 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) return sqlDecimal.Value; // throws OverflowException if the value is out of decimal range. } catch (OverflowException) { - var inputData = sqlDecimal.Data; + var inputData = sqlDecimal.Data; // Allocates a new array var scale = sqlDecimal.Scale; var u128 = FromSqlDecimalData(inputData); From 5417af40d563c58ecdf86d5ae7e2c80bef363b14 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:35:24 -0700 Subject: [PATCH 19/23] Simplify --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index eb74acd6a5..8d56acf187 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -140,9 +140,8 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) return sqlDecimal.Value; // throws OverflowException if the value is out of decimal range. } catch (OverflowException) { - var inputData = sqlDecimal.Data; // Allocates a new array var scale = sqlDecimal.Scale; - var u128 = FromSqlDecimalData(inputData); + var u128 = FromSqlDecimalData(sqlDecimal.Data); // sqlDecimal.Data allocates a new array for (; scale > 0 && u128 > Max96bitValue; --scale) { (u128, _) = UInt128.DivRem(u128, Ten); From e329140cc97f046454f3f8f98315f5a3d03b2d9a Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:36:54 -0700 Subject: [PATCH 20/23] correct comment --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index 8d56acf187..d7a8467c8b 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -137,7 +137,7 @@ private static UInt128 FromSqlDecimalData(int[] a) => internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) { try { - return sqlDecimal.Value; // throws OverflowException if the value is out of decimal range. + return sqlDecimal.Value; // throws an OverflowException if the value is out of the decimal range. } catch (OverflowException) { var scale = sqlDecimal.Scale; From 8d5eeded6c88e137e07cce3c6744c5660bb8c47c Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:39:27 -0700 Subject: [PATCH 21/23] fix build --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index d7a8467c8b..f8a3c60ed1 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -147,9 +147,10 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) (u128, _) = UInt128.DivRem(u128, Ten); } - return u128 <= Max96bitValue - ? new((int) u128, (int) (u128 >> 32), (int) (u128 >> 64), !sqlDecimal.IsPositive, scale) - : throw; + if (u128 > Max96bitValue) { + throw; + } + return new((int) u128, (int) (u128 >> 32), (int) (u128 >> 64), !sqlDecimal.IsPositive, scale); } } } From 05efcaeeabc69459120ee37851eff8c5193512e2 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:47:01 -0700 Subject: [PATCH 22/23] Simplify --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index f8a3c60ed1..80adf36d5b 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -144,7 +144,7 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) var u128 = FromSqlDecimalData(sqlDecimal.Data); // sqlDecimal.Data allocates a new array for (; scale > 0 && u128 > Max96bitValue; --scale) { - (u128, _) = UInt128.DivRem(u128, Ten); + u128 = UInt128.DivRem(u128, Ten).Quotient; } if (u128 > Max96bitValue) { From 276105eecf66b3f1acddc29ab7f69b9ac75695e8 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 24 Jun 2025 16:47:46 -0700 Subject: [PATCH 23/23] Simplify --- .../Sql.Drivers.SqlServer/InternalHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs index 80adf36d5b..6e2e5770e2 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/InternalHelpers.cs @@ -144,7 +144,7 @@ internal static decimal TruncateToNetDecimal(SqlDecimal sqlDecimal) var u128 = FromSqlDecimalData(sqlDecimal.Data); // sqlDecimal.Data allocates a new array for (; scale > 0 && u128 > Max96bitValue; --scale) { - u128 = UInt128.DivRem(u128, Ten).Quotient; + u128 /= Ten; } if (u128 > Max96bitValue) {