-
Notifications
You must be signed in to change notification settings - Fork 874
Description
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)
);