Skip to content

Commit 390d579

Browse files
committed
Fix "Can't replace active reader". Fixes #1469
If an exception happens during MySqlConnection.Close(), the connection may be left in an invalid state, thinking it still has an open MySqlDataReader. Clear this field during cleanup to remove this invalid state.
1 parent 929dd40 commit 390d579

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

src/MySqlConnector/MySqlConnection.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,9 @@ private async Task DoCloseAsync(bool changeState, IOBehavior ioBehavior)
12481248
{
12491249
if (m_session is not null)
12501250
{
1251+
// under exceptional circumstances, we may enter this code without having called FinishQuerying, which clears this field
1252+
m_activeReader = null;
1253+
12511254
if (GetInitializedConnectionSettings().Pooling)
12521255
{
12531256
await m_session.ReturnToPoolAsync(ioBehavior, this).ConfigureAwait(false);

tests/MySqlConnector.Tests/ConnectionTests.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,49 @@ public void ReadInfinity()
234234
Assert.False(reader.Read());
235235
}
236236

237+
[Fact]
238+
public void ReplaceActiveReader()
239+
{
240+
var connection = new MySqlConnection(m_csb.ConnectionString);
241+
connection.Open();
242+
using (var command = connection.CreateCommand())
243+
{
244+
command.CommandText = "select disconnect";
245+
command.CommandTimeout = 600;
246+
var reader = command.ExecuteReader();
247+
Assert.True(reader.Read());
248+
Assert.Equal(1, reader.GetInt32(0));
249+
}
250+
251+
try
252+
{
253+
connection.Close();
254+
}
255+
catch (MySqlEndOfStreamException)
256+
{
257+
}
258+
259+
connection.Open();
260+
using (var command = connection.CreateCommand())
261+
{
262+
command.CommandText = "SELECT 1;";
263+
var reader = command.ExecuteReader();
264+
Assert.True(reader.Read());
265+
Assert.Equal(1, reader.GetInt32(0));
266+
}
267+
connection.Close();
268+
269+
connection.Open();
270+
using (var command = connection.CreateCommand())
271+
{
272+
command.CommandText = "SELECT 2;";
273+
var reader = command.ExecuteReader();
274+
Assert.True(reader.Read());
275+
Assert.Equal(2, reader.GetInt32(0));
276+
}
277+
connection.Close();
278+
}
279+
237280
private static async Task WaitForConditionAsync<T>(T expected, Func<T> getValue)
238281
{
239282
var sw = Stopwatch.StartNew();

tests/MySqlConnector.Tests/FakeMySqlServerConnection.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,20 @@ public async Task RunAsync(TcpClient client, CancellationToken token)
179179
for (var packetIndex = 0; packetIndex < packets.Length; packetIndex++)
180180
await SendAsync(stream, packetIndex + 1, x => x.Write(packets[packetIndex]));
181181
}
182+
else if (query == "select disconnect")
183+
{
184+
var packets = new[]
185+
{
186+
new byte[] { 1 }, // one column
187+
[3, 0x64, 0x65, 0x66, 0, 0, 0, 1, 0x41, 0, 0x0c, 0x3f, 0, 1, 0, 0, 0, 3, 0x01, 0, 0x1F, 0, 0], // column definition (int)
188+
[0xFE, 0, 0, 2, 0], // EOF
189+
[1, 0x31], // 1
190+
};
191+
for (var packetIndex = 0; packetIndex < packets.Length; packetIndex++)
192+
await SendAsync(stream, packetIndex + 1, x => x.Write(packets[packetIndex]));
193+
stream.Close();
194+
client.Close();
195+
}
182196
else
183197
{
184198
await SendAsync(stream, 1, x => WriteError(x, "Unhandled query: " + query));

0 commit comments

Comments
 (0)