Skip to content

Commit 1690e02

Browse files
authored
Port PR 499 (#3255)
1 parent ae02b60 commit 1690e02

File tree

2 files changed

+53
-12
lines changed

2 files changed

+53
-12
lines changed

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace Microsoft.Data.SqlClient
3030
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml' path='docs/members[@name="SqlDataReader"]/SqlDataReader/*' />
3131
public class SqlDataReader : DbDataReader, IDataReader, IDbColumnSchemaGenerator
3232
{
33-
private enum ALTROWSTATUS
33+
internal enum ALTROWSTATUS
3434
{
3535
Null = 0, // default and after Done
3636
AltRow, // after calling NextResult and the first AltRow is available for read
@@ -97,9 +97,6 @@ internal class SharedState
9797
private SqlSequentialStream _currentStream;
9898
private SqlSequentialTextReader _currentTextReader;
9999

100-
private IsDBNullAsyncCallContext _cachedIsDBNullContext;
101-
private ReadAsyncCallContext _cachedReadAsyncContext;
102-
103100
internal SqlDataReader(SqlCommand command, CommandBehavior behavior)
104101
{
105102
SqlConnection.VerifyExecutePermission();
@@ -4387,6 +4384,10 @@ internal TdsOperationStatus TryReadColumnInternal(int i, bool readHeaderOnly/* =
43874384
{
43884385
// reset snapshot to save memory use. We can safely do that here because all SqlDataReader values are stable.
43894386
// The retry logic can use the current values to get back to the right state.
4387+
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection && sqlInternalConnection.CachedDataReaderSnapshot is null)
4388+
{
4389+
sqlInternalConnection.CachedDataReaderSnapshot = _snapshot;
4390+
}
43904391
_snapshot = null;
43914392
PrepareAsyncInvocation(useSnapshot: true);
43924393
}
@@ -5318,7 +5319,15 @@ public override Task<bool> ReadAsync(CancellationToken cancellationToken)
53185319
return source.Task;
53195320
}
53205321

5321-
var context = Interlocked.Exchange(ref _cachedReadAsyncContext, null) ?? new ReadAsyncCallContext();
5322+
ReadAsyncCallContext context = null;
5323+
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection)
5324+
{
5325+
context = Interlocked.Exchange(ref sqlInternalConnection.CachedDataReaderReadAsyncContext, null);
5326+
}
5327+
if (context is null)
5328+
{
5329+
context = new ReadAsyncCallContext();
5330+
}
53225331

53235332
Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ReadAsyncCallContext was not properly disposed");
53245333

@@ -5358,6 +5367,10 @@ private static Task<bool> ReadAsyncExecute(Task task, object state)
53585367
if (!hasReadRowToken)
53595368
{
53605369
hasReadRowToken = true;
5370+
if (reader.Connection?.InnerConnection is SqlInternalConnection sqlInternalConnection && sqlInternalConnection.CachedDataReaderSnapshot is null)
5371+
{
5372+
sqlInternalConnection.CachedDataReaderSnapshot = reader._snapshot;
5373+
}
53615374
reader._snapshot = null;
53625375
reader.PrepareAsyncInvocation(useSnapshot: true);
53635376
}
@@ -5377,7 +5390,10 @@ private static Task<bool> ReadAsyncExecute(Task task, object state)
53775390

53785391
private void SetCachedReadAsyncCallContext(ReadAsyncCallContext instance)
53795392
{
5380-
Interlocked.CompareExchange(ref _cachedReadAsyncContext, instance, null);
5393+
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection)
5394+
{
5395+
Interlocked.CompareExchange(ref sqlInternalConnection.CachedDataReaderReadAsyncContext, instance, null);
5396+
}
53815397
}
53825398

53835399
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml' path='docs/members[@name="SqlDataReader"]/IsDBNullAsync/*' />
@@ -5479,7 +5495,15 @@ override public Task<bool> IsDBNullAsync(int i, CancellationToken cancellationTo
54795495
registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command));
54805496
}
54815497

5482-
IsDBNullAsyncCallContext context = Interlocked.Exchange(ref _cachedIsDBNullContext, null) ?? new IsDBNullAsyncCallContext();
5498+
IsDBNullAsyncCallContext context = null;
5499+
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection)
5500+
{
5501+
context = Interlocked.Exchange(ref sqlInternalConnection.CachedDataReaderIsDBNullContext, null);
5502+
}
5503+
if (context is null)
5504+
{
5505+
context = new IsDBNullAsyncCallContext();
5506+
}
54835507

54845508
Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ISDBNullAsync context not properly disposed");
54855509

@@ -5517,7 +5541,10 @@ private static Task<bool> IsDBNullAsyncExecute(Task task, object state)
55175541

55185542
private void SetCachedIDBNullAsyncCallContext(IsDBNullAsyncCallContext instance)
55195543
{
5520-
Interlocked.CompareExchange(ref _cachedIsDBNullContext, instance, null);
5544+
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection)
5545+
{
5546+
Interlocked.CompareExchange(ref sqlInternalConnection.CachedDataReaderIsDBNullContext, instance, null);
5547+
}
55215548
}
55225549

55235550
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml' path='docs/members[@name="SqlDataReader"]/GetFieldValueAsync/*' />
@@ -6019,7 +6046,7 @@ private void CompleteAsyncCall<T>(Task<T> task, SqlDataReaderBaseAsyncCallContex
60196046
}
60206047
}
60216048

6022-
private sealed class Snapshot
6049+
internal sealed class Snapshot
60236050
{
60246051
public bool _dataReady;
60256052
public bool _haltRead;
@@ -6051,7 +6078,14 @@ private void PrepareAsyncInvocation(bool useSnapshot)
60516078

60526079
if (_snapshot == null)
60536080
{
6054-
_snapshot = new Snapshot();
6081+
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection)
6082+
{
6083+
_snapshot = Interlocked.Exchange(ref sqlInternalConnection.CachedDataReaderSnapshot, null) ?? new Snapshot();
6084+
}
6085+
else
6086+
{
6087+
_snapshot = new Snapshot();
6088+
}
60556089

60566090
_snapshot._dataReady = _sharedState._dataReady;
60576091
_snapshot._haltRead = _haltRead;
@@ -6124,6 +6158,10 @@ private void CleanupAfterAsyncInvocationInternal(TdsParserStateObject stateObj,
61246158
stateObj._permitReplayStackTraceToDiffer = false;
61256159
#endif
61266160

6161+
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection && sqlInternalConnection.CachedDataReaderSnapshot is null)
6162+
{
6163+
sqlInternalConnection.CachedDataReaderSnapshot = _snapshot;
6164+
}
61276165
// We are setting this to null inside the if-statement because stateObj==null means that the reader hasn't been initialized or has been closed (either way _snapshot should already be null)
61286166
_snapshot = null;
61296167
}
@@ -6162,6 +6200,10 @@ private void SwitchToAsyncWithoutSnapshot()
61626200
Debug.Assert(_snapshot != null, "Should currently have a snapshot");
61636201
Debug.Assert(_stateObj != null && !_stateObj._asyncReadWithoutSnapshot, "Already in async without snapshot");
61646202

6203+
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection && sqlInternalConnection.CachedDataReaderSnapshot is null)
6204+
{
6205+
sqlInternalConnection.CachedDataReaderSnapshot = _snapshot;
6206+
}
61656207
_snapshot = null;
61666208
_stateObj.ResetSnapshot();
61676209
_stateObj._asyncReadWithoutSnapshot = true;

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,10 @@ internal abstract class SqlInternalConnection : DbConnectionInternal
3131
internal SqlCommand.ExecuteReaderAsyncCallContext CachedCommandExecuteReaderAsyncContext;
3232
internal SqlCommand.ExecuteNonQueryAsyncCallContext CachedCommandExecuteNonQueryAsyncContext;
3333
internal SqlCommand.ExecuteXmlReaderAsyncCallContext CachedCommandExecuteXmlReaderAsyncContext;
34-
34+
#endif
3535
internal SqlDataReader.Snapshot CachedDataReaderSnapshot;
3636
internal SqlDataReader.IsDBNullAsyncCallContext CachedDataReaderIsDBNullContext;
3737
internal SqlDataReader.ReadAsyncCallContext CachedDataReaderReadAsyncContext;
38-
#endif
3938

4039
// if connection is not open: null
4140
// if connection is open: currently active database

0 commit comments

Comments
 (0)