Skip to content

Merge | SqlCommand (Part 1) #3473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Jul 24, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d78c53c
Aligning CallerMemberName arguments
benrr101 Jun 27, 2025
73dd08a
Sync TriggerInternalEndAndRetryIfNecessary signatures (as part of syn…
benrr101 Jul 11, 2025
904bb06
Sync attribute formatting and some low stakes stylistic/typo stuff
benrr101 Jul 2, 2025
8b97a46
Move ExecuteReader methods to align with netcore implementation
benrr101 Jul 11, 2025
6fccc8f
Remove SqlCommand from TriggerInternalEndAndRetryIfNecessary function…
benrr101 Jul 11, 2025
75765ed
Round one of syncing method signatures
benrr101 Jul 2, 2025
64244b2
Align keysToBeSentToEnclave, requiresEnclaveComputations, ShouldCache…
benrr101 Jul 2, 2025
780cf6c
Align CancelIgnoreFailureCallback and CancelIgnoreFailure
benrr101 Jul 2, 2025
29dd1ff
Remove unsed CompletePendingReadWith* Methods
benrr101 Jul 2, 2025
ee0660b
Align Write*ExecuteEvent methods
benrr101 Jul 2, 2025
61a5e28
Align Clone, ICloneable.Clone and NotifyDependency
benrr101 Jul 2, 2025
1d4a266
Align BeginExecuteReader and ExecuteReader methods as per netcore imp…
benrr101 Jul 11, 2025
2c0b6b6
Align InternalExecuteNonQueryWithRetryAsync
benrr101 Jul 2, 2025
0b85116
Align ExecuteReaderAsync methods
benrr101 Jul 2, 2025
e78f841
Align ExecuteXmlReaderAsync methods
benrr101 Jul 2, 2025
8f4252b
Sync some more things, like spaces, comments
benrr101 Jul 14, 2025
8bce702
sync _prepareHandle
benrr101 Jul 14, 2025
b3cd36d
Rename CachedAsyncState to AsyncState to allow for CachedAsyncState p…
benrr101 Jul 14, 2025
fdbe141
sync isRetry and isAsync variable names
benrr101 Jul 14, 2025
3ae6f88
Sync { // lines
benrr101 Jul 14, 2025
1aca93c
Sync event/trace/correlation messages
benrr101 Jul 14, 2025
c5920a9
Revert "Remove SqlCommand from TriggerInternalEndAndRetryIfNecessary …
benrr101 Jul 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,9 @@ internal bool IsColumnEncryptionEnabled
_customColumnEncryptionKeyStoreProviders is not null && _customColumnEncryptionKeyStoreProviders.Count > 0;

// Cached info for async executions
private sealed class CachedAsyncState
private sealed class AsyncState
{
// @TODO: Autoproperties
private int _cachedAsyncCloseCount = -1; // value of the connection's CloseCount property when the asyncResult was set; tracks when connections are closed after an async operation
private TaskCompletionSource<object> _cachedAsyncResult = null;
private SqlConnection _cachedAsyncConnection = null; // Used to validate that the connection hasn't changed when end the connection;
Expand All @@ -275,7 +276,7 @@ private sealed class CachedAsyncState
private string _cachedSetOptions = null;
private string _cachedEndMethod = null;

internal CachedAsyncState()
internal AsyncState()
{
}

Expand Down Expand Up @@ -354,16 +355,14 @@ internal void SetAsyncReaderState(SqlDataReader ds, RunBehavior runBehavior, str
}
}

private CachedAsyncState _cachedAsyncState = null;
private AsyncState _cachedAsyncState = null;

private CachedAsyncState cachedAsyncState
// @TODO: This is never null, so we can remove the null checks from usages of it.
private AsyncState CachedAsyncState
{
get
{
if (_cachedAsyncState == null)
{
_cachedAsyncState = new CachedAsyncState();
}
_cachedAsyncState ??= new AsyncState();
return _cachedAsyncState;
}
}
Expand Down Expand Up @@ -489,7 +488,7 @@ private SqlCommand(SqlCommand from) : this()
// Don't allow the connection to be changed while in an async operation.
if (_activeConnection != value && _activeConnection != null)
{ // If new value...
if (_cachedAsyncState != null && _cachedAsyncState.PendingAsyncOperation)
if (CachedAsyncState != null && CachedAsyncState.PendingAsyncOperation)
{ // If in pending async state, throw.
throw SQL.CannotModifyPropertyAsyncOperationInProgress();
}
Expand Down Expand Up @@ -626,7 +625,7 @@ internal SqlStatistics Statistics
// Don't allow the transaction to be changed while in an async operation.
if (_transaction != value && _activeConnection != null)
{ // If new value...
if (cachedAsyncState.PendingAsyncOperation)
if (CachedAsyncState.PendingAsyncOperation)
{ // If in pending async state, throw
throw SQL.CannotModifyPropertyAsyncOperationInProgress();
}
Expand Down Expand Up @@ -1108,7 +1107,7 @@ protected override void Dispose(bool disposing)
_cachedMetaData = null;

// reset async cache information to allow a second async execute
_cachedAsyncState?.ResetAsyncState();
CachedAsyncState?.ResetAsyncState();
}
// release unmanaged objects
base.Dispose(disposing);
Expand Down Expand Up @@ -1392,7 +1391,7 @@ private void BeginExecuteNonQueryInternalReadStage(TaskCompletionSource<object>
try
{
// must finish caching information before ReadSni which can activate the callback before returning
cachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteNonQuery), _activeConnection);
CachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteNonQuery), _activeConnection);
_stateObj.ReadSni(completion);
}
// Cause of a possible unstable runtime situation on facing with `OutOfMemoryException` and `StackOverflowException` exceptions,
Expand All @@ -1411,7 +1410,7 @@ private void BeginExecuteNonQueryInternalReadStage(TaskCompletionSource<object>
{
// Similarly, if an exception occurs put the stateObj back into the pool.
// and reset async cache information to allow a second async execute
_cachedAsyncState?.ResetAsyncState();
CachedAsyncState?.ResetAsyncState();
ReliablePutStateObject();
throw;
}
Expand Down Expand Up @@ -1456,15 +1455,15 @@ private void VerifyEndExecuteState(Task completionTask, string endMethod, bool f
return;
}

if (cachedAsyncState.EndMethodName == null)
if (CachedAsyncState.EndMethodName == null)
{
throw ADP.MethodCalledTwice(endMethod);
}
if (endMethod != cachedAsyncState.EndMethodName)
if (endMethod != CachedAsyncState.EndMethodName)
{
throw ADP.MismatchedAsyncResult(cachedAsyncState.EndMethodName, endMethod);
throw ADP.MismatchedAsyncResult(CachedAsyncState.EndMethodName, endMethod);
}
if ((_activeConnection.State != ConnectionState.Open) || (!cachedAsyncState.IsActiveConnectionValid(_activeConnection)))
if ((_activeConnection.State != ConnectionState.Open) || (!CachedAsyncState.IsActiveConnectionValid(_activeConnection)))
{
// If the connection is not 'valid' then it was closed while we were executing
throw ADP.ClosedConnectionError();
Expand Down Expand Up @@ -1529,7 +1528,7 @@ private int EndExecuteNonQueryAsync(IAsyncResult asyncResult)
if (asyncException != null)
{
// Leftover exception from the Begin...InternalReadStage
cachedAsyncState?.ResetAsyncState();
CachedAsyncState?.ResetAsyncState();
ReliablePutStateObject();
throw asyncException.InnerException;
}
Expand Down Expand Up @@ -1568,15 +1567,15 @@ private int EndExecuteNonQueryInternal(IAsyncResult asyncResult)
catch (SqlException e)
{
sqlExceptionNumber = e.Number;
_cachedAsyncState?.ResetAsyncState();
CachedAsyncState?.ResetAsyncState();

// SqlException is always catchable
ReliablePutStateObject();
throw;
}
catch (Exception e)
{
_cachedAsyncState?.ResetAsyncState();
CachedAsyncState?.ResetAsyncState();
if (ADP.IsCatchableExceptionType(e))
{
ReliablePutStateObject();
Expand Down Expand Up @@ -1622,7 +1621,7 @@ private object InternalEndExecuteNonQuery(
Debug.Assert(_stateObj == null);

// Reset the state since we exit early.
cachedAsyncState.ResetAsyncState();
CachedAsyncState.ResetAsyncState();

return _rowsAffected;
}
Expand All @@ -1647,7 +1646,7 @@ private object InternalEndExecuteNonQuery(
// Don't reset the state for internal End. The user End will do that eventually.
if (!isInternal)
{
cachedAsyncState.ResetAsyncState();
CachedAsyncState.ResetAsyncState();
}
}
}
Expand Down Expand Up @@ -1944,7 +1943,7 @@ private void BeginExecuteXmlReaderInternalReadStage(TaskCompletionSource<object>
try
{
// must finish caching information before ReadSni which can activate the callback before returning
_cachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteXmlReader), _activeConnection);
CachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteXmlReader), _activeConnection);
_stateObj.ReadSni(completion);
}
// Cause of a possible unstable runtime situation on facing with `OutOfMemoryException` and `StackOverflowException` exceptions,
Expand All @@ -1965,7 +1964,7 @@ private void BeginExecuteXmlReaderInternalReadStage(TaskCompletionSource<object>
{
// Similarly, if an exception occurs put the stateObj back into the pool.
// and reset async cache information to allow a second async execute
_cachedAsyncState?.ResetAsyncState();
CachedAsyncState?.ResetAsyncState();
ReliablePutStateObject();
completion.TrySetException(e);
}
Expand All @@ -1992,7 +1991,7 @@ private XmlReader EndExecuteXmlReaderAsync(IAsyncResult asyncResult)
Exception asyncException = ((Task)asyncResult).Exception;
if (asyncException != null)
{
cachedAsyncState?.ResetAsyncState();
CachedAsyncState?.ResetAsyncState();
ReliablePutStateObject();
throw asyncException.InnerException;
}
Expand Down Expand Up @@ -2031,9 +2030,9 @@ private XmlReader EndExecuteXmlReaderInternal(IAsyncResult asyncResult)
SqlException ex = (SqlException)e;
sqlExceptionNumber = ex.Number;
}
if (cachedAsyncState != null)
if (CachedAsyncState != null)
{
cachedAsyncState.ResetAsyncState();
CachedAsyncState.ResetAsyncState();
};
if (ADP.IsCatchableExceptionType(e))
{
Expand Down Expand Up @@ -2192,7 +2191,7 @@ private SqlDataReader EndExecuteReaderAsync(IAsyncResult asyncResult)
Exception asyncException = ((Task)asyncResult).Exception;
if (asyncException != null)
{
cachedAsyncState?.ResetAsyncState();
CachedAsyncState?.ResetAsyncState();
ReliablePutStateObject();
throw asyncException.InnerException;
}
Expand Down Expand Up @@ -2236,9 +2235,9 @@ private SqlDataReader EndExecuteReaderInternal(IAsyncResult asyncResult)
sqlExceptionNumber = exception.Number;
}

if (cachedAsyncState != null)
if (CachedAsyncState != null)
{
cachedAsyncState.ResetAsyncState();
CachedAsyncState.ResetAsyncState();
};
if (ADP.IsCatchableExceptionType(e))
{
Expand Down Expand Up @@ -2509,9 +2508,9 @@ long firstAttemptStart
if (!shouldRetry)
{
// If we cannot retry, Reset the async state to make sure we leave a clean state.
if (_cachedAsyncState != null)
if (CachedAsyncState != null)
{
_cachedAsyncState.ResetAsyncState();
CachedAsyncState.ResetAsyncState();
}

try
Expand Down Expand Up @@ -2603,7 +2602,7 @@ private void BeginExecuteReaderInternalReadStage(TaskCompletionSource<object> co
try
{
// must finish caching information before ReadSni which can activate the callback before returning
cachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteReader), _activeConnection);
CachedAsyncState.SetActiveConnectionAndResult(completion, nameof(EndExecuteReader), _activeConnection);
_stateObj.ReadSni(completion);
}
// Cause of a possible unstable runtime situation on facing with `OutOfMemoryException` and `StackOverflowException` exceptions,
Expand All @@ -2624,7 +2623,7 @@ private void BeginExecuteReaderInternalReadStage(TaskCompletionSource<object> co
{
// Similarly, if an exception occurs put the stateObj back into the pool.
// and reset async cache information to allow a second async execute
_cachedAsyncState?.ResetAsyncState();
CachedAsyncState?.ResetAsyncState();
ReliablePutStateObject();
completion.TrySetException(e);
}
Expand Down Expand Up @@ -4059,9 +4058,9 @@ private void PrepareForTransparentEncryption(
}
catch (Exception e)
{
if (cachedAsyncState != null)
if (CachedAsyncState != null)
{
cachedAsyncState.ResetAsyncState();
CachedAsyncState.ResetAsyncState();
}

if (ADP.IsCatchableExceptionType(e))
Expand Down Expand Up @@ -4133,9 +4132,9 @@ private SqlDataReader GetParameterEncryptionDataReader(out Task returnTask, Task
onFailure: static (Exception exception, object state) =>
{
SqlCommand command = (SqlCommand)state;
if (command._cachedAsyncState != null)
if (command.CachedAsyncState != null)
{
command._cachedAsyncState.ResetAsyncState();
command.CachedAsyncState.ResetAsyncState();
}

if (exception != null)
Expand Down Expand Up @@ -5044,15 +5043,15 @@ private SqlDataReader RunExecuteReaderTdsWithTransparentParameterEncryption(
},
onFailure: static (Exception exception, object state) =>
{
((SqlCommand)state)._cachedAsyncState?.ResetAsyncState();
((SqlCommand)state).CachedAsyncState?.ResetAsyncState();
if (exception != null)
{
throw exception;
}
},
onCancellation: static (object state) =>
{
((SqlCommand)state)._cachedAsyncState?.ResetAsyncState();
((SqlCommand)state).CachedAsyncState?.ResetAsyncState();
}
);
task = completion.Task;
Expand Down Expand Up @@ -5324,7 +5323,7 @@ private SqlDataReader RunExecuteReaderTds(
}
else
{
cachedAsyncState.SetAsyncReaderState(ds, runBehavior, optionSettings);
CachedAsyncState.SetAsyncReaderState(ds, runBehavior, optionSettings);
}
}
else
Expand Down Expand Up @@ -5368,7 +5367,7 @@ private Task RunExecuteReaderTdsSetupContinuation(RunBehavior runBehavior, SqlDa
{
SqlConnection sqlConnection = (SqlConnection)state;
sqlConnection.GetOpenTdsConnection(); // it will throw if connection is closed
cachedAsyncState.SetAsyncReaderState(ds, runBehavior, optionSettings);
CachedAsyncState.SetAsyncReaderState(ds, runBehavior, optionSettings);
},
onFailure: static (Exception exc, object state) =>
{
Expand Down Expand Up @@ -5412,11 +5411,11 @@ private void RunExecuteReaderTdsSetupReconnectContinuation(CommandBehavior cmdBe

private SqlDataReader CompleteAsyncExecuteReader(bool isInternal = false, bool forDescribeParameterEncryption = false)
{
SqlDataReader ds = cachedAsyncState.CachedAsyncReader; // should not be null
SqlDataReader ds = CachedAsyncState.CachedAsyncReader; // should not be null
bool processFinallyBlock = true;
try
{
FinishExecuteReader(ds, cachedAsyncState.CachedRunBehavior, cachedAsyncState.CachedSetOptions, isInternal, forDescribeParameterEncryption, shouldCacheForAlwaysEncrypted: !forDescribeParameterEncryption);
FinishExecuteReader(ds, CachedAsyncState.CachedRunBehavior, CachedAsyncState.CachedSetOptions, isInternal, forDescribeParameterEncryption, shouldCacheForAlwaysEncrypted: !forDescribeParameterEncryption);
}
catch (Exception e)
{
Expand All @@ -5430,7 +5429,7 @@ private SqlDataReader CompleteAsyncExecuteReader(bool isInternal = false, bool f
// Don't reset the state for internal End. The user End will do that eventually.
if (!isInternal)
{
cachedAsyncState.ResetAsyncState();
CachedAsyncState.ResetAsyncState();
}
PutStateObject();
}
Expand Down Expand Up @@ -5658,16 +5657,16 @@ private void ValidateCommand(bool isAsync, [CallerMemberName] string method = ""

private void ValidateAsyncCommand()
{
if (_cachedAsyncState != null && _cachedAsyncState.PendingAsyncOperation)
if (CachedAsyncState != null && CachedAsyncState.PendingAsyncOperation)
{ // Enforce only one pending async execute at a time.
if (cachedAsyncState.IsActiveConnectionValid(_activeConnection))
if (CachedAsyncState.IsActiveConnectionValid(_activeConnection))
{
throw SQL.PendingBeginXXXExists();
}
else
{
_stateObj = null; // Session was re-claimed by session pool upon connection close.
_cachedAsyncState.ResetAsyncState();
CachedAsyncState.ResetAsyncState();
}
}
}
Expand Down
Loading