Skip to content

NpgsqlDataReader.GetFieldValueAsync intermittently does not return #6190

@bill-poole

Description

@bill-poole

When reading a large dataset from a PostgreSQL database, the NpgsqlDataReader.GetFieldValueAsync method will sometimes intermittently not return. My PostgreSQL query selects five columns, the first of which is a composite type, and the last four of which are arrays of composite types. I am using CommandBehavior.SequentialAccess and the GetFieldValueAsync method because the returned array values are sometimes quite large (sometimes up to about 100 kB in my test dataset, but could be several MBs).

The following line of code is where the problem occurs.

yield return (
    await reader.GetFieldValueAsync<T1>(ordinal: 0, cancellationToken),
    await reader.IsDBNullAsync(ordinal: 1, cancellationToken) ? [] : await reader.GetFieldValueAsync<T2[]>(ordinal: 1, cancellationToken),
    await reader.IsDBNullAsync(ordinal: 2, cancellationToken) ? [] : await reader.GetFieldValueAsync<T3[]>(ordinal: 2, cancellationToken),
    await reader.IsDBNullAsync(ordinal: 3, cancellationToken) ? [] : await reader.GetFieldValueAsync<T4[]>(ordinal: 3, cancellationToken),
    await reader.IsDBNullAsync(ordinal: 4, cancellationToken) ? [] : await reader.GetFieldValueAsync<T5[]>(ordinal: 4, cancellationToken)
);

Closer inspection reveals that the specific method call that does not return is await reader.GetFieldValueAsync<T2[]>.

Note that I must use IsDBNullAsync because otherwise the GetFieldValueAsync method with an array type throws an InvalidCastException if the column is null. It would be nice if await reader.GetFieldValueAsync<T2[]?> were to just return null if the column is null.

System.InvalidCastException: Column 'xxxxx' is null.
         at Npgsql.ThrowHelper.ThrowInvalidCastException_NoValue(FieldDescription field)
         at Npgsql.NpgsqlDataReader.DbNullValueOrThrow[T](Int32 ordinal)
         at Npgsql.NpgsqlDataReader.GetFieldValueCore[T](Int32 ordinal)
         at Npgsql.NpgsqlDataReader.GetFieldValue[T](Int32 ordinal)

If I change the above code to not use the async calls as shown below, then there is no problem. However, I'd like to use the async calls so the call does not block the thread when reading a large array value.

yield return (
    reader.GetFieldValue<T1>(ordinal: 0),
    reader.IsDBNull(ordinal: 1) ? [] : reader.GetFieldValue<T2[]>(ordinal: 1),
    reader.IsDBNull(ordinal: 2) ? [] : reader.GetFieldValue<T3[]>(ordinal: 2),
    reader.IsDBNull(ordinal: 3) ? [] : reader.GetFieldValue<T4[]>(ordinal: 3),
    reader.IsDBNull(ordinal: 4) ? [] : reader.GetFieldValue<T5[]>(ordinal: 4)
);

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions