@@ -27,19 +27,19 @@ public override bool Read()
27
27
{
28
28
VerifyNotDisposed ( ) ;
29
29
Command ! . CancellableCommand . ResetCommandTimeout ( ) ;
30
- return m_resultSet ! . Read ( ) ;
30
+ return m_resultSet . Read ( ) ;
31
31
}
32
32
33
33
public override async Task < bool > ReadAsync ( CancellationToken cancellationToken )
34
34
{
35
35
VerifyNotDisposed ( ) ;
36
36
Command ! . CancellableCommand . ResetCommandTimeout ( ) ;
37
37
using var registration = Command . CancellableCommand . RegisterCancel ( cancellationToken ) ;
38
- return await m_resultSet ! . ReadAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
38
+ return await m_resultSet . ReadAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
39
39
}
40
40
41
41
internal Task < bool > ReadAsync ( IOBehavior ioBehavior , CancellationToken cancellationToken ) =>
42
- m_resultSet ! . ReadAsync ( ioBehavior , cancellationToken ) ;
42
+ m_resultSet . ReadAsync ( ioBehavior , cancellationToken ) ;
43
43
44
44
public override async Task < bool > NextResultAsync ( CancellationToken cancellationToken )
45
45
{
@@ -58,7 +58,7 @@ internal async Task<bool> NextResultAsync(IOBehavior ioBehavior, CancellationTok
58
58
{
59
59
while ( true )
60
60
{
61
- await m_resultSet ! . ReadEntireAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
61
+ await m_resultSet . ReadEntireAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
62
62
await ScanResultSetAsync ( ioBehavior , m_resultSet , cancellationToken ) . ConfigureAwait ( false ) ;
63
63
if ( m_hasMoreResults && m_resultSet . ContainsCommandParameters )
64
64
await ReadOutParametersAsync ( Command ! , m_resultSet , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
@@ -74,7 +74,7 @@ internal async Task<bool> NextResultAsync(IOBehavior ioBehavior, CancellationTok
74
74
using ( Command . CancellableCommand . RegisterCancel ( cancellationToken ) )
75
75
{
76
76
var writer = new ByteBufferWriter ( ) ;
77
- if ( ! Command . Connection ! . Session . IsCancelingQuery && m_payloadCreator . WriteQueryCommand ( ref m_commandListPosition , m_cachedProcedures ! , writer , false ) )
77
+ if ( ! Command . Connection ! . Session . IsCancelingQuery && m_payloadCreator ! . WriteQueryCommand ( ref m_commandListPosition , m_cachedProcedures ! , writer , false ) )
78
78
{
79
79
using var payload = writer . ToPayloadData ( ) ;
80
80
await Command . Connection . Session . SendAsync ( payload , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
@@ -99,7 +99,7 @@ internal async Task<bool> NextResultAsync(IOBehavior ioBehavior, CancellationTok
99
99
}
100
100
catch ( MySqlException )
101
101
{
102
- m_resultSet ! . Reset ( ) ;
102
+ m_resultSet . Reset ( ) ;
103
103
m_hasMoreResults = false ;
104
104
<
10000
/td> m_schemaTable = null ;
105
105
throw ;
@@ -108,7 +108,7 @@ internal async Task<bool> NextResultAsync(IOBehavior ioBehavior, CancellationTok
108
108
109
109
private void ActivateResultSet ( CancellationToken cancellationToken )
110
110
{
111
- if ( m_resultSet ! . ReadResultSetHeaderException is not null )
111
+ if ( m_resultSet . ReadResultSetHeaderException is not null )
112
112
{
113
113
var mySqlException = m_resultSet . ReadResultSetHeaderException . SourceException as MySqlException ;
114
114
@@ -350,8 +350,8 @@ public override long GetChars(int ordinal, long dataOffset, char[]? buffer, int
350
350
/// <returns>A <see cref="System.Collections.ObjectModel.ReadOnlyCollection{DbColumn}"/> containing metadata about the result set.</returns>
351
351
public ReadOnlyCollection < DbColumn > GetColumnSchema ( )
352
352
{
353
- var columnDefinitions = m_resultSet ? . ColumnDefinitions ;
354
- var hasNoSchema = columnDefinitions is null || m_resultSet ! . ContainsCommandParameters ;
353
+ var columnDefinitions = m_resultSet . ColumnDefinitions ;
354
+ var hasNoSchema = columnDefinitions is null || m_resultSet . ContainsCommandParameters ;
355
355
return hasNoSchema ? new List < DbColumn > ( ) . AsReadOnly ( ) :
356
356
columnDefinitions !
357
357
. Select ( ( c , n ) => ( DbColumn ) new MySqlDbColumn ( n , c , Connection ! . AllowZeroDateTime , GetResultSet ( ) . ColumnTypes ! [ n ] ) )
@@ -451,30 +451,49 @@ protected override void Dispose(bool disposing)
451
451
public Task DisposeAsync ( ) => DisposeAsync ( Connection ? . AsyncIOBehavior ?? IOBehavior . Asynchronous , CancellationToken . None ) ;
452
452
#endif
453
453
454
- internal Activity ? Activity { get ; }
454
+ internal Activity ? Activity { get ; private set ; }
455
455
internal IMySqlCommand ? Command { get ; private set ; }
456
456
internal MySqlConnection ? Connection => Command ? . Connection ;
457
457
internal ulong ? RealRecordsAffected { get ; set ; }
458
458
internal ServerSession ? Session => Command ? . Connection ! . Session ;
459
459
460
- internal static async Task < MySqlDataReader > CreateAsync ( CommandListPosition commandListPosition , ICommandPayloadCreator payloadCreator , IDictionary < string , CachedProcedure ? > ? cachedProcedures , IMySqlCommand command , CommandBehavior behavior , Activity ? activity , IOBehavior ioBehavior , CancellationToken cancellationToken )
460
+ internal async Task InitAsync ( CommandListPosition commandListPosition , ICommandPayloadCreator payloadCreator , IDictionary < string , CachedProcedure ? > ? cachedProcedures , IMySqlCommand command , CommandBehavior behavior , Activity ? activity , IOBehavior ioBehavior , CancellationToken cancellationToken )
461
461
{
462
- var dataReader = new MySqlDataReader ( commandListPosition , payloadCreator , cachedProcedures , command , behavior , activity ) ;
463
- command . Connection ! . SetActiveReader ( dataReader ) ;
462
+ // reset fields from last use of this MySqlDataReader
463
+ if ( m_hasMoreResults )
464
+ throw new InvalidOperationException ( "Expected m_hasMoreResults to be false" ) ;
465
+ if ( m_resultSet . BufferState != ResultSetState . None || m_resultSet . State != ResultSetState . None )
466
+ throw new InvalidOperationException ( "Expected BufferState and State to be ResultSetState.None." ) ;
467
+ if ( m_resultSet . ColumnDefinitions is not null )
468
+ throw new InvalidOperationException ( "Expected ColumnDefinitions to be null" ) ;
469
+ m_closed = false ;
470
+ m_hasWarnings = false ;
471
+ m_initializationFailed = false ;
472
+ RealRecordsAffected = null ;
473
+
474
+ // initialize for new command
475
+ m_commandListPosition = commandListPosition ;
476
+ m_payloadCreator = payloadCreator ;
477
+ m_cachedProcedures = cachedProcedures ;
478
+ Command = command ;
479
+ m_behavior = behavior ;
480
+ Activity = activity ;
481
+
482
+ command . Connection ! . SetActiveReader ( this ) ;
464
483
465
484
try
466
485
{
467
- await dataReader . m_resultSet ! . ReadResultSetHeaderAsync ( ioBehavior ) . ConfigureAwait ( false ) ;
468
- dataReader . ActivateResultSet ( cancellationToken ) ;
469
- dataReader . m_hasMoreResults = true ;
486
+ await m_resultSet . ReadResultSetHeaderAsync ( ioBehavior ) . ConfigureAwait ( false ) ;
487
+ ActivateResultSet ( cancellationToken ) ;
488
+ m_hasMoreResults = true ;
470
489
471
- if ( dataReader . m_resultSet . ContainsCommandParameters )
472
- await ReadOutParametersAsync ( dataReader . Command ! , dataReader . m_resultSet , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
490
+ if ( m_resultSet . ContainsCommandParameters )
491
+ await ReadOutParametersAsync ( command , m_resultSet , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
473
492
474
493
// if the command list has multiple commands, keep reading until a result set is found
475
- while ( dataReader . m_resultSet . State == ResultSetState . NoMoreData && commandListPosition . CommandIndex < commandListPosition . Commands . Count )
494
+ while ( m_resultSet . State == ResultSetState . NoMoreData && commandListPosition . CommandIndex < commandListPosition . Commands . Count )
476
495
{
477
- await dataReader . NextResultAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
496
+ await NextResultAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
478
497
}
479
498
}
480
499
catch ( Exception ex )
@@ -484,18 +503,16 @@ internal static async Task<MySqlDataReader> CreateAsync(CommandListPosition comm
484
503
activity . SetException ( ex ) ;
485
504
activity . Stop ( ) ;
486
505
}
487
- dataReader . m_creationFailed = true ;
488
- dataReader . Dispose ( ) ;
506
+ m_initializationFailed = true ;
507
+ Dispose ( ) ;
489
508
throw ;
490
509
}
491
-
492
- return dataReader ;
493
510
}
494
511
495
512
internal DataTable ? BuildSchemaTable ( )
496
513
{
497
- var columnDefinitions = m_resultSet ? . ColumnDefinitions ;
498
- if ( columnDefinitions is null || m_resultSet ! . ContainsCommandParameters )
514
+ var columnDefinitions = m_resultSet . ColumnDefinitions ;
515
+ if ( columnDefinitions is null || m_resultSet . ContainsCommandParameters )
499
516
return null ;
500
517
501
518
var schemaTable = new DataTable ( "SchemaTable" ) { Locale = CultureInfo . InvariantCulture } ;
@@ -583,15 +600,9 @@ internal static async Task<MySqlDataReader> CreateAsync(CommandListPosition comm
583
600
return schemaTable ;
584
601
}
585
602
586
- private MySqlDataReader ( CommandListPosition commandListPosition , ICommandPayloadCreator payloadCreator , IDictionary < string , CachedProcedure ? > ? cachedProcedures , IMySqlCommand command , CommandBehavior behavior , Activity ? activity )
603
+ internal MySqlDataReader ( )
587
604
{
588
- m_commandListPosition = commandListPosition ;
589
- m_payloadCreator = payloadCreator ;
590
- m_cachedProcedures = cachedProcedures ;
591
- Command = command ;
592
- m_behavior = behavior ;
593
605
m_resultSet = new ( this ) ;
594
- Activity = activity ;
595
606
}
596
607
597
608
#if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
@@ -619,7 +630,6 @@ internal async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancel
619
630
if ( ex . ErrorCode != MySqlErrorCode . QueryInterrupted )
620
631
Log . IgnoringExceptionInDisposeAsync ( Command . Logger , ex , Command . Connection . Session . Id , ex . Message , Command . CommandText ! ) ;
621
632
}
622
- m_resultSet = null ;
623
633
}
624
634
625
635
m_hasMoreResults = false ;
@@ -628,13 +638,19 @@ internal async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancel
628
638
Command . CancellableCommand . SetTimeout ( Constants . InfiniteTimeout ) ;
629
639
connection . FinishQuerying ( m_hasWarnings ) ;
630
640
631
- if ( ! m_creationFailed )
641
+ if ( ! m_initializationFailed )
632
642
Activity ? . SetSuccess ( ) ;
633
643
Activity ? . Stop ( ) ;
644
+ Activity = null ;
634
645
635
646
if ( ( m_behavior & CommandBehavior . CloseConnection ) != 0 )
636
647
await connection . CloseAsync ( ioBehavior ) . ConfigureAwait ( false ) ;
648
+
649
+ // clear fields (so that MySqlConnection can be GCed if the user doesn't hold a reference to it)
637
650
Command = null ;
651
+ m_commandListPosition = default ;
652
+ m_payloadCreator = null ;
653
+ m_cachedProcedures = null ;
638
654
}
639
655
}
640
656
@@ -683,14 +699,14 @@ private ResultSet GetResultSet()
683
699
return m_resultSet ;
684
700
}
685
701
686
- private readonly CommandBehavior m_behavior ;
687
- private readonly ICommandPayloadCreator m_payloadCreator ;
688
- private readonly IDictionary < string , CachedProcedure ? > ? m_cachedProcedures ;
702
+ private readonly ResultSet m_resultSet ;
703
+ private CommandBehavior m_behavior ;
704
+ private ICommandPayloadCreator ? m_payloadCreator ;
705
+ private IDictionary < string , CachedProcedure ? > ? m_cachedProcedures ;
689
706
private CommandListPosition m_commandListPosition ;
690
707
private bool m_closed ;
691
708
private bool m_hasWarnings ;
692
709
private bool m_hasMoreResults ;
693
- private bool m_creationFailed ;
694
- private ResultSet ? m_resultSet ;
710
+ private bool m_initializationFailed ;
695
711
private DataTable ? m_schemaTable ;
696
712
}
0 commit comments