Skip to content

Commit 03aa185

Browse files
committed
Add MySqlConnection.InfoMessage event. Fixes #594
1 parent 943a376 commit 03aa185

File tree

6 files changed

+113
-2
lines changed

6 files changed

+113
-2
lines changed

src/MySqlConnector/Core/ResultSet.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public async Task<ResultSet> ReadResultSetHeaderAsync(IOBehavior ioBehavior)
2828
ColumnTypes = null;
2929
LastInsertId = 0;
3030
RecordsAffected = null;
31+
WarningCount = 0;
3132
State = ResultSetState.None;
3233
m_columnDefinitionPayloadUsedBytes = 0;
3334
m_readBuffer.Clear();
@@ -47,6 +48,7 @@ public async Task<ResultSet> ReadResultSetHeaderAsync(IOBehavior ioBehavior)
4748
var ok = OkPayload.Create(payload.AsSpan());
4849
RecordsAffected = (RecordsAffected ?? 0) + ok.AffectedRowCount;
4950
LastInsertId = unchecked((long) ok.LastInsertId);
51+
WarningCount = ok.WarningCount;
5052
if (ok.NewSchema != null)
5153
Connection.Session.DatabaseOverride = ok.NewSchema;
5254
ColumnDefinitions = null;
@@ -128,6 +130,7 @@ int ReadColumnCount(ReadOnlySpan<byte> span)
128130
}
129131

130132
LastInsertId = -1;
133+
WarningCount = 0;
131134
State = ResultSetState.ReadResultSetHeader;
132135
break;
133136
}
@@ -329,6 +332,7 @@ public Row GetCurrentRow()
329332
public MySqlDbType[] ColumnTypes { get; private set; }
330333
public long LastInsertId { get; private set; }
331334
public int? RecordsAffected { get; private set; }
335+
public int WarningCount { get; private set; }
332336
public ResultSetState State { get; private set; }
333337

334338
ResizableArray<byte> m_columnDefinitionPayloads;

src/MySqlConnector/MySql.Data.MySqlClient/MySqlConnection.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ private SchemaProvider GetSchemaProvider()
309309

310310
public override int ConnectionTimeout => m_connectionSettings.ConnectionTimeout;
311311

312+
public event MySqlInfoMessageEventHandler InfoMessage;
313+
312314
protected override void Dispose(bool disposing)
313315
{
314316
try
@@ -444,10 +446,23 @@ internal void SetActiveReader(MySqlDataReader dataReader)
444446
m_activeReader = dataReader;
445447
}
446448

447-
internal void FinishQuerying()
449+
internal void FinishQuerying(bool hasWarnings)
448450
{
449451
m_session.FinishQuerying();
450452
m_activeReader = null;
453+
454+
if (hasWarnings && InfoMessage != null)
455+
{
456+
var errors = new List<MySqlError>();
457+
using (var command = new MySqlCommand("SHOW WARNINGS;", this))
458+
using (var reader = command.ExecuteReader())
459+
{
460+
while (reader.Read())
461+
errors.Add(new MySqlError(reader.GetString(0), reader.GetInt32(1), reader.GetString(2)));
462+
}
463+
464+
InfoMessage(this, new MySqlInfoMessageEventArgs(errors.ToArray()));
465+
}
451466
}
452467

453468
private async ValueTask<ServerSession> CreateSessionAsync(IOBehavior? ioBehavior, CancellationToken cancellationToken)

src/MySqlConnector/MySql.Data.MySqlClient/MySqlDataReader.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ private void ActivateResultSet(ResultSet resultSet)
9494

9595
Command.LastInsertedId = resultSet.LastInsertId;
9696
m_recordsAffected = m_recordsAffected == null ? resultSet.RecordsAffected : m_recordsAffected.Value + (resultSet.RecordsAffected ?? 0);
97+
m_hasWarnings = resultSet.WarningCount != 0;
9798
}
9899

99100
private ValueTask<ResultSet> ScanResultSetAsync(IOBehavior ioBehavior, ResultSet resultSet, CancellationToken cancellationToken)
@@ -431,7 +432,7 @@ private void DoClose()
431432
m_resultSetBuffered = null;
432433

433434
var connection = Command.Connection;
434-
connection.FinishQuerying();
435+
connection.FinishQuerying(m_hasWarnings);
435436

436437
Command.ReaderClosed();
437438
if ((m_behavior & CommandBehavior.CloseConnection) != 0)
@@ -458,6 +459,7 @@ private ResultSet GetResultSet()
458459
readonly CommandBehavior m_behavior;
459460
bool m_closed;
460461
int? m_recordsAffected;
462+
bool m_hasWarnings;
461463
ResultSet m_resultSet;
462464
ResultSet m_resultSetBuffered;
463465
#if !NETSTANDARD1_3
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace MySql.Data.MySqlClient
2+
{
3+
public sealed class MySqlError
4+
{
5+
internal MySqlError(string level, int code, string message)
6+
{
7+
Level = level;
8+
Code = code;
9+
Message = message;
10+
}
11+
12+
public string Level { get; }
13+
public int Code { get; }
14+
public string Message { get; }
15+
};
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace MySql.Data.MySqlClient
5+
{
6+
public sealed class MySqlInfoMessageEventArgs : EventArgs
7+
{
8+
internal MySqlInfoMessageEventArgs(MySqlError[] errors) => this.errors = errors;
9+
10+
public MySqlError[] errors { get; }
11+
12+
public IReadOnlyList<MySqlError> Errors => errors;
13+
}
14+
15+
public delegate void MySqlInfoMessageEventHandler(object sender, MySqlInfoMessageEventArgs args);
16+
}

tests/SideBySide/ConnectionTests.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Dapper;
2+
using MySql.Data.MySqlClient;
3+
using Xunit;
4+
5+
namespace SideBySide
6+
{
7+
public class ConnectionTests : IClassFixture<DatabaseFixture>
8+
{
9+
public ConnectionTests(DatabaseFixture database)
10+
{
11+
}
12+
13+
[Fact]
14+
public void GotInfoMessageForNonExistentTable()
15+
{
16+
using (var connection = new MySqlConnection(AppConfig.ConnectionString))
17+
{
18+
connection.Open();
19+
20+
var gotEvent = false;
21+
connection.InfoMessage += (s, a) =>
22+
{
23+
gotEvent = true;
24+
Assert.Single(a.errors);
25+
Assert.Equal((int) MySqlErrorCode.BadTable, a.errors[0].Code);
26+
};
27+
28+
connection.Execute(@"drop table if exists table_does_not_exist;");
29+
Assert.True(gotEvent);
30+
}
31+
}
32+
33+
[Fact]
34+
public void NoInfoMessageWhenNotLastStatementInBatch()
35+
{
36+
using (var connection = new MySqlConnection(AppConfig.ConnectionString))
37+
{
38+
connection.Open();
39+
40+
var gotEvent = false;
41+
connection.InfoMessage += (s, a) =>
42+
{
43+
gotEvent = true;
44+
45+
// seeming bug in Connector/NET raises an event with no errors
46+
Assert.Empty(a.errors);
47+
};
48+
49+
connection.Execute(@"drop table if exists table_does_not_exist; select 1;");
50+
#if BASELINE
51+
Assert.True(gotEvent);
52+
#else
53+
Assert.False(gotEvent);
54+
#endif
55+
}
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)