Skip to content

Commit c84ab6a

Browse files
authored
Made everything to dispose asynchronously if possible (#3703)
Closes #3694
1 parent 35660c8 commit c84ab6a

File tree

6 files changed

+175
-93
lines changed

6 files changed

+175
-93
lines changed

src/Npgsql/Internal/NpgsqlConnector.cs

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -579,19 +579,42 @@ internal async ValueTask<ClusterState> QueryClusterState(
579579
// 'old' state. Otherwise, execution of the query shouldn't make notable difference.
580580
var timeStamp = DateTime.UtcNow;
581581

582-
using var reader = async ? await cmd.ExecuteReaderAsync(cancellationToken) : cmd.ExecuteReader();
583-
reader.Read();
584-
var isInRecovery = reader.GetBoolean(0);
585-
reader.NextResult();
586-
reader.Read();
587-
var transactionReadOnly = reader.GetString(0) != "off";
588-
589-
var state = isInRecovery ? ClusterState.Standby :
590-
transactionReadOnly
591-
? ClusterState.PrimaryReadOnly
592-
: ClusterState.PrimaryReadWrite;
593-
return ClusterStateCache.UpdateClusterState(Settings.Host!, Settings.Port, state, timeStamp,
594-
Settings.HostRecheckSecondsTranslated);
582+
var reader = async ? await cmd.ExecuteReaderAsync(cancellationToken) : cmd.ExecuteReader();
583+
try
584+
{
585+
bool isInRecovery;
586+
587+
if (async)
588+
{
589+
await reader.ReadAsync(cancellationToken);
590+
isInRecovery = reader.GetBoolean(0);
591+
await reader.NextResultAsync(cancellationToken);
592+
await reader.ReadAsync(cancellationToken);
593+
}
594+
else
595+
{
596+
reader.Read();
597+
isInRecovery = reader.GetBoolean(0);
598+
reader.NextResult();
599+
reader.Read();
600+
}
601+
602+
var transactionReadOnly = reader.GetString(0) != "off";
603+
604+
var state = isInRecovery ? ClusterState.Standby :
605+
transactionReadOnly
606+
? ClusterState.PrimaryReadOnly
607+
: ClusterState.PrimaryReadWrite;
608+
return ClusterStateCache.UpdateClusterState(Settings.Host!, Settings.Port, state, timeStamp,
609+
Settings.HostRecheckSecondsTranslated);
610+
}
611+
finally
612+
{
613+
if (async)
614+
await reader.DisposeAsync();
615+
else
616+
reader.Dispose();
617+
}
595618
}
596619

597620
void WriteStartupMessage(string username)

src/Npgsql/NpgsqlCommand.cs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,10 +1050,20 @@ public override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationTok
10501050
[MethodImpl(MethodImplOptions.AggressiveInlining)]
10511051
async Task<int> ExecuteNonQuery(bool async, CancellationToken cancellationToken)
10521052
{
1053-
using var reader = await ExecuteReader(CommandBehavior.Default, async, cancellationToken);
1054-
while (async ? await reader.NextResultAsync(cancellationToken) : reader.NextResult()) ;
1053+
var reader = await ExecuteReader(CommandBehavior.Default, async, cancellationToken);
1054+
try
1055+
{
1056+
while (async ? await reader.NextResultAsync(cancellationToken) : reader.NextResult()) ;
10551057

1056-
return reader.RecordsAffected;
1058+
return reader.RecordsAffected;
1059+
}
1060+
finally
1061+
{
1062+
if (async)
1063+
await reader.DisposeAsync();
1064+
else
1065+
reader.Dispose();
1066+
}
10571067
}
10581068

10591069
#endregion Execute Non Query
@@ -1089,8 +1099,19 @@ async Task<int> ExecuteNonQuery(bool async, CancellationToken cancellationToken)
10891099
if (!Parameters.HasOutputParameters)
10901100
behavior |= CommandBehavior.SequentialAccess;
10911101

1092-
using var reader = await ExecuteReader(behavior, async, cancellationToken);
1093-
return reader.Read() && reader.FieldCount != 0 ? reader.GetValue(0) : null;
1102+
var reader = await ExecuteReader(behavior, async, cancellationToken);
1103+
try
1104+
{
1105+
var read = async ? await reader.ReadAsync(cancellationToken) : reader.Read();
1106+
return read && reader.FieldCount != 0 ? reader.GetValue(0) : null;
1107+
}
1108+
finally
1109+
{
1110+
if (async)
1111+
await reader.DisposeAsync();
1112+
else
1113+
reader.Dispose();
1114+
}
10941115
}
10951116

10961117
#endregion Execute Scalar

src/Npgsql/NpgsqlDataAdapter.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,18 @@ internal async Task<int> Fill(DataTable dataTable, bool async, CancellationToken
152152
if (ConnectionState.Closed == originalState)
153153
await activeConnection.Open(async, cancellationToken);
154154

155-
using var dataReader = await command.ExecuteReader(CommandBehavior.Default, async, cancellationToken);
156-
157-
return await Fill(dataTable, dataReader, async, cancellationToken);
155+
var dataReader = await command.ExecuteReader(CommandBehavior.Default, async, cancellationToken);
156+
try
157+
{
158+
return await Fill(dataTable, dataReader, async, cancellationToken);
159+
}
160+
finally
161+
{
162+
if (async)
163+
await dataReader.DisposeAsync();
164+
else
165+
dataReader.Dispose();
166+
}
158167
}
159168
finally
160169
{

src/Npgsql/NpgsqlLargeObjectManager.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,25 @@ internal async Task<int> ExecuteFunctionGetBytes(
6262
foreach (var argument in arguments)
6363
command.Parameters.Add(new NpgsqlParameter { Value = argument });
6464

65-
using var reader = async
65+
var reader = async
6666
? await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken)
6767
: command.ExecuteReader(CommandBehavior.SequentialAccess);
68-
69-
if (async)
70-
await reader.ReadAsync(cancellationToken);
71-
else
72-
reader.Read();
73-
74-
return (int)reader.GetBytes(0, 0, buffer, offset, len);
68+
try
69+
{
70+
if (async)
71+
await reader.ReadAsync(cancellationToken);
72+
else
73+
reader.Read();
74+
75+
return (int)reader.GetBytes(0, 0, buffer, offset, len);
76+
}
77+
finally
78+
{
79+
if (async)
80+
await reader.DisposeAsync();
81+
else
82+
reader.Dispose();
83+
}
7584
}
7685

7786
/// <summary>

src/Npgsql/PostgresDatabaseInfo.cs

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -210,38 +210,40 @@ internal async Task<List<PostgresType>> LoadBackendTypes(NpgsqlConnector conn, N
210210
command.AllResultTypesAreUnknown = true;
211211

212212
timeout.CheckAndApply(conn);
213-
using var reader = async ? await command.ExecuteReaderAsync() : command.ExecuteReader();
214-
var byOID = new Dictionary<uint, PostgresType>();
215-
216-
// First the PostgreSQL version
217-
if (async)
218-
{
219-
await reader.ReadAsync();
220-
LongVersion = reader.GetString(0);
221-
await reader.NextResultAsync();
222-
}
223-
else
213+
var reader = async ? await command.ExecuteReaderAsync() : command.ExecuteReader();
214+
try
224215
{
225-
reader.Read();
226-
LongVersion = reader.GetString(0);
227-
reader.NextResult();
228-
}
216+
var byOID = new Dictionary<uint, PostgresType>();
229217

230-
// Then load the types
231-
while (async ? await reader.ReadAsync() : reader.Read())
232-
{
233-
var ns = reader.GetString("nspname");
234-
var internalName = reader.GetString("typname");
235-
var oid = uint.Parse(reader.GetString("oid"), NumberFormatInfo.InvariantInfo);
236-
Debug.Assert(oid != 0);
237-
238-
var elementOID = reader.IsDBNull("elemtypoid")
239-
? 0
240-
: uint.Parse(reader.GetString("elemtypoid"), NumberFormatInfo.InvariantInfo);
218+
// First the PostgreSQL version
219+
if (async)
220+
{
221+
await reader.ReadAsync();
222+
LongVersion = reader.GetString(0);
223+
await reader.NextResultAsync();
224+
}
225+
else
226+
{
227+
reader.Read();
228+
LongVersion = reader.GetString(0);
229+
reader.NextResult();
230+
}
241231

242-
var typeChar = reader.GetChar("typtype");
243-
switch (typeChar)
232+
// Then load the types
233+
while (async ? await reader.ReadAsync() : reader.Read())
244234
{
235+
var ns = reader.GetString("nspname");
236+
var internalName = reader.GetString("typname");
237+
var oid = uint.Parse(reader.GetString("oid"), NumberFormatInfo.InvariantInfo);
238+
Debug.Assert(oid != 0);
239+
240+
var elementOID = reader.IsDBNull("elemtypoid")
241+
? 0
242+
: uint.Parse(reader.GetString("elemtypoid"), NumberFormatInfo.InvariantInfo);
243+
244+
var typeChar = reader.GetChar("typtype");
245+
switch (typeChar)
246+
{
245247
case 'b': // Normal base type
246248
var baseType = new PostgresBaseType(ns, internalName, oid);
247249
byOID[baseType.OID] = baseType;
@@ -301,27 +303,35 @@ internal async Task<List<PostgresType>> LoadBackendTypes(NpgsqlConnector conn, N
301303

302304
default:
303305
throw new ArgumentOutOfRangeException($"Unknown typtype for type '{internalName}' in pg_type: {typeChar}");
306+
}
304307
}
305-
}
306-
307-
if (async)
308-
await reader.NextResultAsync();
309-
else
310-
reader.NextResult();
311308

312-
LoadCompositeFields(reader, byOID);
313-
314-
if (SupportsEnumTypes)
315-
{
316309
if (async)
317310
await reader.NextResultAsync();
318311
else
319312
reader.NextResult();
320313

321-
LoadEnumLabels(reader, byOID);
322-
}
314+
LoadCompositeFields(reader, byOID);
315+
316+
if (SupportsEnumTypes)
317+
{
318+
if (async)
319+
await reader.NextResultAsync();
320+
else
321+
reader.NextResult();
322+
323+
LoadEnumLabels(reader, byOID);
324+
}
323325

324-
return byOID.Values.ToList();
326+
return byOID.Values.ToList();
327+
}
328+
finally
329+
{
330+
if (async)
331+
await reader.DisposeAsync();
332+
else
333+
reader.Dispose();
334+
}
325335
}
326336

327337
/// <summary>

src/Npgsql/Schema/DbColumnSchemaGenerator.cs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -128,29 +128,39 @@ internal async Task<ReadOnlyCollection<NpgsqlDbColumn>> GetColumnSchema(bool asy
128128
using var connection = (NpgsqlConnection)((ICloneable)_connection).Clone();
129129

130130
await connection.Open(async, cancellationToken);
131-
132-
using var cmd = new NpgsqlCommand(query, connection);
133-
using var reader = await cmd.ExecuteReader(CommandBehavior.Default, async, cancellationToken);
134-
while (async ? await reader.ReadAsync(cancellationToken): reader.Read())
135-
{
136-
var column = LoadColumnDefinition(reader, _connection.Connector!.TypeMapper.DatabaseInfo, oldQueryMode);
137-
for (var ordinal = 0; ordinal < numFields; ordinal++)
138-
{
139-
var field = _rowDescription[ordinal];
140-
if (field.TableOID == column.TableOID &&
141-
field.ColumnAttributeNumber == column.ColumnAttributeNumber)
142-
{
143-
populatedColumns++;
144-
145-
if (column.ColumnOrdinal.HasValue)
146-
column = column.Clone();
147-
148-
// The column's ordinal is with respect to the resultset, not its table
149-
column.ColumnOrdinal = ordinal;
150-
result[ordinal] = column;
151-
}
152-
}
153-
}
131+
132+
using var cmd = new NpgsqlCommand(query, connection);
133+
var reader = await cmd.ExecuteReader(CommandBehavior.Default, async, cancellationToken);
134+
try
135+
{
136+
while (async ? await reader.ReadAsync(cancellationToken) : reader.Read())
137+
{
138+
var column = LoadColumnDefinition(reader, _connection.Connector!.TypeMapper.DatabaseInfo, oldQueryMode);
139+
for (var ordinal = 0; ordinal < numFields; ordinal++)
140+
{
141+
var field = _rowDescription[ordinal];
142+
if (field.TableOID == column.TableOID &&
143+
field.ColumnAttributeNumber == column.ColumnAttributeNumber)
144+
{
145+
populatedColumns++;
146+
147+
if (column.ColumnOrdinal.HasValue)
148+
column = column.Clone();
149+
150+
// The column's ordinal is with respect to the resultset, not its table
151+
column.ColumnOrdinal = ordinal;
152+
result[ordinal] = column;
153+
}
154+
}
155+
}
156+
}
157+
finally
158+
{
159+
if (async)
160+
await reader.DisposeAsync();
161+
else
162+
reader.Dispose();
163+
}
154164
}
155165
}
156166

0 commit comments

Comments
 (0)