npgsql: Overflow exception with seemingly fine numeric value

Please clarify what I am doing wrong here.

Steps to reproduce

// connection init
// ...

using (var cmd = new NpgsqlCommand("select 794866.99999999999999999999999", conn))
{
    using (var reader = await cmd.ExecuteReaderAsync())
    {
        while (await reader.ReadAsync())
            Console.WriteLine(reader.GetDecimal(0));
    }
}

The issue

I’m getting an overflow exception at GetDecimal.

 System.OverflowException: Numeric value does not fit in a System.Decimal
   at void Npgsql.Internal.TypeHandlers.NumericHandlers.DecimalRaw.Multiply(ref DecimalRaw value, uint multiplier) in /_/src/Npgsql/Internal/TypeHandlers/NumericHandlers/DecimalRaw.cs:line 119
   at async ValueTask<decimal> Npgsql.Internal.TypeHandlers.NumericHandlers.NumericHandler.Read(NpgsqlReadBuffer buf, int len, bool async, FieldDescription fieldDescription) in /_/src/Npgsql/Internal/TypeHandlers/NumericHandlers/NumericHandler.cs:line 99
   at T Npgsql.NpgsqlDataReader.GetFieldValue<T>(int ordinal) in /_/src/Npgsql/NpgsqlDataReader.cs:line 1640

I’ve read #3627.

The value 99999999999.0000000000000000000 has 30 digits, but the .NET decimal type only supports up to 29 digits, so Npgsql cannot read that value correctly

My value has 29 digits and still causes an exception.

Further technical details

Npgsql version: 6.0.3 PostgreSQL version: PostgreSQL 10.5 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28), 64-bit Server operating system: Red Hat Enterprise Linux Server release 7.5 (Maipo) Client operating system:: Microsoft Windows Server 2012 R2 Standard TargetFramework: netcoreapp2.0

Thanks.

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 18 (18 by maintainers)

Most upvoted comments

Not only because of that, but also to avoid creation of a secondary decimal from an integer. Internally decimal has DecCalc which serves the same purpose, and which is the same type we have, I just copy pasted some pieces of code we needed for quick math on integers. In addition to that, doing parsing this way keeps the scale as is and allows the driver to avoid rounding.

There is also a problem with division…

var dr = new DecimalRaw(794866.99999999999999999999m);
var expected = 794.86699999999999999999999m;
DecimalRaw.Divide(ref dr, 1000);
Assert.AreEqual(dr.Value, expected);
Expected: 794.86699999999999999999m
But was:  794.86699999999999999999999m

@roji I can try, it’s definitely not a trivial thing)