Skip to content

BigIntegerNumericConverter fails with There is not enough data left in the buffer. and more #6107

@Groxan

Description

@Groxan

Hi! I've faced an issue with Npgsql (v9.0.3) + Dapper (dynamic binding) when converting numeric to BigInteger (I'm using a custom TypeInfoResolverFactory, just like here: #448 (comment)).

It randomly fails on different queries with one the following errors:

There is not enough data left in the buffer.
System.InvalidCastException: Numeric value with non-zero fractional digits not supported by BigInteger
   at Tzkt.Api.PgNumeric.Builder.ToBigInteger(Int16 weight, UInt16 sign, Span`1 digits)
   at Tzkt.Api.BigIntegerNumericConverter.Read(PgReader reader)
System.ArgumentOutOfRangeException: Buffer requirement is larger than the remaining length of the value, make sure the value is always at least this size or use an upper bound requirement instead. (Parameter 'byteCount')
   at Npgsql.ThrowHelper.ThrowArgumentOutOfRangeException(String paramName, String message)
   at Npgsql.Internal.PgReader.<ShouldBuffer>g__ShouldBufferSlow|115_0(<>c__DisplayClass115_0&)
   at Tzkt.Api.BigIntegerNumericConverter.Read(PgReader reader)
System.ArgumentOutOfRangeException: length ('-1') must be a non-negative value. (Parameter 'length')
Actual value was -1.
   at System.ArgumentOutOfRangeException.ThrowNegative[T](T value, String paramName)
   at System.Array.CopyImpl(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
   at Npgsql.Internal.NpgsqlReadBuffer.<Ensure>g__EnsureLong|55_0(NpgsqlReadBuffer buffer, Int32 count, Boolean async, Boolean readingNotifications)
   at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
   at Npgsql.Internal.NpgsqlReadBuffer.Ensure(Int32 count)
   at Tzkt.Api.BigIntegerNumericConverter.Read(PgReader reader)
System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Tzkt.Api.BigIntegerNumericConverter.Read(PgReader reader) // in var digitCount = reader.ReadInt16();

Not sure if this is the reason, but I think the issue is caused by BigIntegerNumericConverter inheriting bufferRequirements = BufferRequirements.None; from PgStreamingConverter, that makes PgReader.GetBufferRequirementByteCount return 0, that makes PgReader.ShouldBuffer return false, that causes NpgsqlDataReader.GetValue to read from a possibly empty buffer.

As a quick workaround I've tried to patch the converter:

class PatchedBigIntegerNumericConverter : BigIntegerNumericConverter
{
    public override bool CanConvert(DataFormat format, out BufferRequirements bufferRequirements)
    {
        bufferRequirements = BufferRequirements.Create(Size.CreateUpperBound(8192));
        return format is DataFormat.Binary;
    }
}

and it seems to be working fine now.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions