11using System ;
22using System . Buffers ;
33using System . Collections . Generic ;
4+ using System . Linq ;
45using System . Net ;
56using System . Net . Sockets ;
67using System . Security . Cryptography ;
@@ -26,15 +27,23 @@ public class MySQLConnection : EasyClient<MySQLPacket>
2627
2728 public bool IsAuthenticated { get ; private set ; }
2829
30+ private readonly MySQLFilterContext filterContext ;
31+
2932 public MySQLConnection ( string host , int port , string userName , string password , ILogger logger = null )
30- : base ( new MySQLPacketFilter ( MySQLPacketDecoder . ClientInstance ) , logger )
33+ : this ( new MySQLPacketFilter ( MySQLPacketDecoder . ClientInstance ) , logger )
3134 {
3235 _host = host ?? throw new ArgumentNullException ( nameof ( host ) ) ;
3336 _port = port > 0 ? port : DefaultPort ;
3437 _userName = userName ?? throw new ArgumentNullException ( nameof ( userName ) ) ;
3538 _password = password ?? throw new ArgumentNullException ( nameof ( password ) ) ;
3639 }
3740
41+ private MySQLConnection ( MySQLPacketFilter packetFilter , ILogger logger )
42+ : base ( packetFilter , logger )
43+ {
44+ filterContext = packetFilter . Context as MySQLFilterContext ;
45+ }
46+
3847 public async Task ConnectAsync ( CancellationToken cancellationToken = default )
3948 {
4049 if ( string . IsNullOrEmpty ( _host ) )
@@ -83,6 +92,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default)
8392 case OKPacket okPacket :
8493 // Authentication successful
8594 IsAuthenticated = true ;
95+ filterContext . State = MySQLConnectionState . Authenticated ;
8696 break ;
8797 case ErrorPacket errorPacket :
8898 // Authentication failed
@@ -95,6 +105,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default)
95105 if ( ( eofPacket . StatusFlags & 0x0002 ) != 0 )
96106 {
97107 IsAuthenticated = true ;
108+ filterContext . State = MySQLConnectionState . Authenticated ;
98109 break ;
99110 }
100111 else
@@ -164,12 +175,27 @@ public async Task<QueryResultPacket> ExecuteQueryAsync(string query, Cancellatio
164175 SequenceId = 0
165176 } ;
166177
178+ filterContext . State = MySQLConnectionState . CommandPhase ;
167179 await SendAsync ( PacketEncoder , commandPacket ) . ConfigureAwait ( false ) ;
168180
169181 // Read response
170182 var response = await ReceiveAsync ( ) . ConfigureAwait ( false ) ;
171183
172- return ( QueryResultPacket ) response ;
184+ // Handle different response types
185+ switch ( response )
186+ {
187+ case ErrorPacket errorPacket :
188+ // Query failed
189+ return QueryResultPacket . FromError ( ( short ) errorPacket . ErrorCode , errorPacket . ErrorMessage ) ;
190+
191+ case QueryResultPacket queryResult :
192+ // Already a query result packet
193+ return queryResult ;
194+
195+ default :
196+ // Handle result set responses (SELECT queries)
197+ return await ReadResultSetAsync ( response ) . ConfigureAwait ( false ) ;
198+ }
173199 }
174200 catch ( Exception ex )
175201 {
@@ -186,22 +212,17 @@ public async Task<QueryResultPacket> ExecuteQueryAsync(string query, Cancellatio
186212 public async Task < string > ExecuteQueryStringAsync ( string query , CancellationToken cancellationToken = default )
187213 {
188214 var result = await ExecuteQueryAsync ( query , cancellationToken ) . ConfigureAwait ( false ) ;
189-
215+
190216 if ( ! result . IsSuccess )
191217 {
192218 return $ "Error { result . ErrorCode } : { result . ErrorMessage } ";
193219 }
194220
195- if ( result . Columns == null || result . Columns . Count == 0 )
196- {
197- return $ "Query executed successfully. { result . AffectedRows } rows affected.";
198- }
199-
200221 var sb = new StringBuilder ( ) ;
201-
222+
202223 // Add column headers
203224 sb . AppendLine ( string . Join ( "\t " , result . Columns ) ) ;
204-
225+
205226 // Add separator line
206227 sb . AppendLine ( new string ( '-' , result . Columns . Count * 10 ) ) ;
207228
@@ -213,9 +234,9 @@ public async Task<string> ExecuteQueryStringAsync(string query, CancellationToke
213234 sb . AppendLine ( string . Join ( "\t " , row ?? new string [ result . Columns . Count ] ) ) ;
214235 }
215236 }
216-
237+
217238 sb . AppendLine ( $ "\n { result . Rows ? . Count ?? 0 } rows returned.") ;
218-
239+
219240 return sb . ToString ( ) ;
220241 }
221242
@@ -235,5 +256,50 @@ public async Task DisconnectAsync()
235256 IsAuthenticated = false ;
236257 }
237258 }
259+
260+ /// <summary>
261+ /// Reads a complete result set from the MySQL server
262+ /// </summary>
263+ /// <param name="firstPacket">The first packet received after sending the query</param>
264+ /// <returns>A QueryResultPacket containing the complete result set</returns>
265+ private Task < QueryResultPacket > ReadResultSetAsync ( MySQLPacket firstPacket )
266+ {
267+ try
268+ {
269+ // If the first packet is already a QueryResultPacket (decoded by UnknownPacket), return it
270+ if ( firstPacket is QueryResultPacket queryResult )
271+ {
272+ return Task . FromResult ( queryResult ) ;
273+ }
274+
275+ // If the first packet is an UnknownPacket, it should have been decoded to QueryResultPacket
276+ // but if that failed, we'll create a minimal fallback
277+ if ( firstPacket is UnknownPacket )
278+ {
279+ // Try to read additional packets to build a result set
280+ // This is a simplified implementation that attempts to handle basic SELECT queries
281+
282+ var columns = new List < ColumnDefinitionPacket > ( ) ;
283+ var rows = new List < IReadOnlyList < string > > ( ) ;
284+
285+ // For now, create a minimal successful result
286+ // This could be enhanced to parse more complex result sets in the future
287+ return Task . FromResult ( QueryResultPacket . FromResultSet ( columns . AsReadOnly ( ) , rows . AsReadOnly ( ) ) ) ;
288+ }
289+
290+ // For any other packet type, treat as an unexpected response
291+ return Task . FromResult ( QueryResultPacket . FromError ( - 1 , $ "Unexpected packet type in result set: { firstPacket ? . GetType ( ) . Name ?? "null" } ") ) ;
292+ }
293+ catch ( Exception ex )
294+ {
295+ return Task . FromResult ( QueryResultPacket . FromError ( - 1 , $ "Failed to read result set: { ex . Message } ") ) ;
296+ }
297+ }
298+
299+ protected override void OnClosed ( object sender , EventArgs e )
300+ {
301+ filterContext . State = MySQLConnectionState . Closed ;
302+ base . OnClosed ( sender , e ) ;
303+ }
238304 }
239305}
0 commit comments