question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SqlClient fails to convert decimal(38,20) to .Net decimal for values within the range of .Net's decimal type

See original GitHub issue

This program

        static void Main(string[] args)
        {
            using (var con = new SqlConnection("server=.;database=tempdb;Integrated Security=true"))
            {
                con.Open();
                var cmd = new SqlCommand("select cast(4210862852.86 as decimal(38,20))  val", con);
                using (SqlDataReader rdr = cmd.ExecuteReader())
                {
                    rdr.Read();

                    var val = rdr.GetDecimal(0);
                    Console.WriteLine(val);
                }
            }
        }

fails with

System.OverflowException: ‘Conversion overflows.’

at SqlBuffer.cs line 254:

                if (StorageType.Decimal == _type)
                {
                    if (_value._numericInfo.data4 != 0 || _value._numericInfo.scale > 28)
                    {
                        throw new OverflowException(SQLResource.ConversionOverflowMessage);
                    }

This value is well within the range of a .NET decimal, and it’s a value that the SqlClient can write using a SqlParameter. So it should be converted to .NET decimal.

The byte pattern in SQL and TDS for this value is:

0x261400010000D877FB4DEE8B51699A5005000000

And it looks like SqlBuffer refuses to convert any value with a non-zero value in the last 4 bytes. But a .NET Decimal is stored as a 12-byte integer, along with a sign and a scaling factor.

So the apparent intent is to determine if the SqlDecimal uses a larger-than-12 byte integer and trigger the overflow.

So this conversion has a bug. It looks like the SqlClient is confused on the byte ordering SQL Server is using, and the last 4 bytes of this buffer are not the 4 least-significant bytes of the 16-byte integer embedded in the decimal.

This number requires uses 12 (base-10) decimal digits to store, so it requires fewer than 12 (base-256) bytes to store.

https://docs.microsoft.com/en-us/dotnet/api/system.decimal?redirectedfrom=MSDN&view=netframework-4.8

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:5
  • Comments:15 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
DavoudEshteharicommented, Jul 9, 2021

It is on the to-do list this semester.

0reactions
klemmchrcommented, Jul 6, 2021

Any updates on this? This issue is present since 3 years.

Read more comments on GitHub >

github_iconTop Results From Across the Web

SQL Server to .Net Decimals with EF6 dDatabase first issue
The OP's problem is that the database field's precision 38. Decimal can handle up to 28. HasColumnType("decimal(28,20)") won't change the ...
Read more >
System.OverflowException is thrown when reading decimal ...
SqlDecimal types have different representable value ranges (SqlDecimal can have up to 38 decimal digits in its integer part while System.Decimal ...
Read more >
DB decimal to System.Decimal type conversion overflow
As I think LLBLGen tries to convert decimal DB type to System.Decimal type automatically. This works good on decimals with small scale.
Read more >
decimal and numeric (Transact-SQL) - SQL Server
In Transact-SQL statements, a constant with a decimal point is automatically converted into a numeric data value, using the minimum precision ...
Read more >
Understanding the SQL Decimal data type
This article explains one of the important data types in SQL Server – SQL Decimal with several examples and for different scenarios.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found