public sealed class SqlCommand : DbCommand, ICloneable
{
private SqlParameterCollection _parameters;
private SqlConnection _activeConnection;
TaskCompletionSource<object> _reconnectionCompletionSource = null;
private SqlNotificationRequest _notification;
private bool _notificationAutoEnlist = true;
private SqlTransaction _transaction;
public SqlCommand()
: base()
{
GC.SuppressFinalize(this);
}
public SqlCommand(string cmdText)
: this()
{
CommandText = cmdText;
}
public SqlCommand(string cmdText, SqlConnection connection)
: this()
{
CommandText = cmdText;
Connection = connection;
}
public SqlCommand(string cmdText, SqlConnection connection, SqlTransaction transaction)
: this()
{
CommandText = cmdText;
Connection = connection;
Transaction = transaction;
}
override protected void Dispose(bool disposing)
{
if (disposing)
{
_cachedMetaData = null;
}
base.Dispose(disposing);
}
override public int ExecuteNonQuery()
{
SqlConnection.ExecutePermission.Demand();
_pendingCancel = false;
SqlStatistics statistics = null;
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<sc.SqlCommand.ExecuteNonQuery|API> %d#", ObjectID);
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteNonQuery|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
bool success = false;
int? sqlExceptionNumber = null;
try
{
statistics = SqlStatistics.StartTimer(Statistics);
WriteBeginExecuteEvent();
bool usedCache;
InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, false, CommandTimeout, out usedCache);
success = true;
return _rowsAffected;
}
catch (SqlException ex)
{
sqlExceptionNumber = ex.Number;
throw;
}
finally
{
SqlStatistics.StopTimer(statistics);
Bid.ScopeLeave(ref hscp);
WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true);
}
}
[System.Security.Permissions.HostProtectionAttribute(ExternalThreading = true)]
public IAsyncResult BeginExecuteNonQuery()
{
return BeginExecuteNonQuery(null, null);
}
[System.Security.Permissions.HostProtectionAttribute(ExternalThreading = true)]
public IAsyncResult BeginExecuteNonQuery(AsyncCallback callback, object stateObject)
{
Bid.CorrelationTrace("<sc.SqlCommand.BeginExecuteNonQuery|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
SqlConnection.ExecutePermission.Demand();
return BeginExecuteNonQueryInternal(0, callback, stateObject, 0, inRetry: false);
}
private IAsyncResult BeginExecuteNonQueryAsync(AsyncCallback callback, object stateObject)
{
return BeginExecuteNonQueryInternal(0, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite: true);
}
private IAsyncResult BeginExecuteNonQueryInternal(CommandBehavior behavior, AsyncCallback callback, object stateObject, int timeout, bool inRetry, bool asyncWrite = false)
{
TaskCompletionSource<object> globalCompletion = new TaskCompletionSource<object>(stateObject);
TaskCompletionSource<object> localCompletion = new TaskCompletionSource<object>(stateObject);
if (!inRetry)
{
_pendingCancel = false;
ValidateAsyncCommand();
}
SqlStatistics statistics = null;
try
{
if (!inRetry)
{
statistics = SqlStatistics.StartTimer(Statistics);
WriteBeginExecuteEvent();
}
bool usedCache;
try
{
Task execNQ = InternalExecuteNonQuery(localCompletion, ADP.BeginExecuteNonQuery, false, timeout, out usedCache, asyncWrite, inRetry: inRetry);
if (execNQ != null)
{
AsyncHelper.ContinueTask(execNQ, localCompletion, () => BeginExecuteNonQueryInternalReadStage(localCompletion));
}
else
{
BeginExecuteNonQueryInternalReadStage(localCompletion);
}
}
catch (Exception e)
{
if (!ADP.IsCatchableOrSecurityExceptionType(e))
{
throw;
}
ReliablePutStateObject();
throw;
}
if (!TriggerInternalEndAndRetryIfNecessary(behavior, stateObject, timeout, ADP.EndExecuteNonQuery, usedCache, inRetry, asyncWrite, globalCompletion, localCompletion, InternalEndExecuteNonQuery, BeginExecuteNonQueryInternal))
{
globalCompletion = localCompletion;
}
if (callback != null)
{
globalCompletion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default);
}
return globalCompletion.Task;
}
finally
{
SqlStatistics.StopTimer(statistics);
}
}
public int EndExecuteNonQuery(IAsyncResult asyncResult)
{
try
{
return EndExecuteNonQueryInternal(asyncResult);
}
finally
{
Bid.CorrelationTrace("<sc.SqlCommand.EndExecuteNonQuery|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
}
}
private int EndExecuteNonQueryAsync(IAsyncResult asyncResult)
{
Bid.CorrelationTrace("<sc.SqlCommand.EndExecuteNonQueryAsync|Info|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
Debug.Assert(!_internalEndExecuteInitiated || _stateObj == null);
Exception asyncException = ((Task)asyncResult).Exception;
if (asyncException != null)
{
ReliablePutStateObject();
throw asyncException.InnerException;
}
else
{
ThrowIfReconnectionHasBeenCanceled();
if (!_internalEndExecuteInitiated)
{
lock (_stateObj)
{
return EndExecuteNonQueryInternal(asyncResult);
}
}
else
{
return EndExecuteNonQueryInternal(asyncResult);
}
}
}
[System.Security.Permissions.HostProtectionAttribute(ExternalThreading = true)]
public IAsyncResult BeginExecuteReader()
{
return BeginExecuteReader(null, null, CommandBehavior.Default);
}
[System.Security.Permissions.HostProtectionAttribute(ExternalThreading = true)]
public IAsyncResult BeginExecuteReader(AsyncCallback callback, object stateObject)
{
return BeginExecuteReader(callback, stateObject, CommandBehavior.Default);
}
override protected DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
{
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteDbDataReader|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
return ExecuteReader(behavior, ADP.ExecuteReader);
}
new public SqlDataReader ExecuteReader()
{
SqlStatistics statistics = null;
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<sc.SqlCommand.ExecuteReader|API> %d#", ObjectID);
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteReader|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
try
{
statistics = SqlStatistics.StartTimer(Statistics);
return ExecuteReader(CommandBehavior.Default, ADP.ExecuteReader);
}
finally
{
SqlStatistics.StopTimer(statistics);
Bid.ScopeLeave(ref hscp);
}
}
new public SqlDataReader ExecuteReader(CommandBehavior behavior)
{
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<sc.SqlCommand.ExecuteReader|API> %d#, behavior=%d{ds.CommandBehavior}", ObjectID, (int)behavior);
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteReader|API|Correlation> ObjectID%d#, behavior=%d{ds.CommandBehavior}, ActivityID %ls\n", ObjectID, (int)behavior);
try
{
return ExecuteReader(behavior, ADP.ExecuteReader);
}
finally
{
Bid.ScopeLeave(ref hscp);
}
}
[System.Security.Permissions.HostProtectionAttribute(ExternalThreading = true)]
public IAsyncResult BeginExecuteReader(CommandBehavior behavior)
{
return BeginExecuteReader(null, null, behavior);
}
[System.Security.Permissions.HostProtectionAttribute(ExternalThreading = true)]
public IAsyncResult BeginExecuteReader(AsyncCallback callback, object stateObject, CommandBehavior behavior)
{
Bid.CorrelationTrace("<sc.SqlCommand.BeginExecuteReader|API|Correlation> ObjectID%d#, behavior=%d{ds.CommandBehavior}, ActivityID %ls\n", ObjectID, (int)behavior);
SqlConnection.ExecutePermission.Demand();
return BeginExecuteReaderInternal(behavior, callback, stateObject, 0, inRetry: false);
}
internal SqlDataReader ExecuteReader(CommandBehavior behavior, string method)
{
SqlConnection.ExecutePermission.Demand();
_pendingCancel = false;
SqlStatistics statistics = null;
TdsParser bestEffortCleanupTarget = null;
RuntimeHelpers.PrepareConstrainedRegions();
bool success = false;
int? sqlExceptionNumber = null;
try
{
WriteBeginExecuteEvent();
#if DEBUG
TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
RuntimeHelpers.PrepareConstrainedRegions();
try {
tdsReliabilitySection.Start();
#else
{
#endif //DEBUG
bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection);
statistics = SqlStatistics.StartTimer(Statistics);
SqlDataReader result = RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true, method);
success = true;
return result;
}
#if DEBUG
finally {
tdsReliabilitySection.Stop();
}
#endif //DEBUG
}
catch (SqlException e)
{
sqlExceptionNumber = e.Number;
throw;
}
catch (System.OutOfMemoryException e)
{
_activeConnection.Abort(e);
throw;
}
catch (System.StackOverflowException e)
{
_activeConnection.Abort(e);
throw;
}
catch (System.Threading.ThreadAbortException e)
{
_activeConnection.Abort(e);
SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
throw;
}
finally
{
SqlStatistics.StopTimer(statistics);
WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true);
}
}
public SqlDataReader EndExecuteReader(IAsyncResult asyncResult)
{
try
{
return EndExecuteReaderInternal(asyncResult);
}
finally
{
Bid.CorrelationTrace("<sc.SqlCommand.EndExecuteReader|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
}
}
private SqlDataReader EndExecuteReaderAsync(IAsyncResult asyncResult)
{
Bid.CorrelationTrace("<sc.SqlCommand.EndExecuteReaderAsync|Info|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
Debug.Assert(!_internalEndExecuteInitiated || _stateObj == null);
Exception asyncException = ((Task)asyncResult).Exception;
if (asyncException != null)
{
ReliablePutStateObject();
throw asyncException.InnerException;
}
else
{
ThrowIfReconnectionHasBeenCanceled();
if (!_internalEndExecuteInitiated)
{
lock (_stateObj)
{
return EndExecuteReaderInternal(asyncResult);
}
}
else
{
return EndExecuteReaderInternal(asyncResult);
}
}
}
private IAsyncResult BeginExecuteReaderAsync(CommandBehavior behavior, AsyncCallback callback, object stateObject)
{
return BeginExecuteReaderInternal(behavior, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite: true);
}
public override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)
{
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteNonQueryAsync|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
SqlConnection.ExecutePermission.Demand();
TaskCompletionSource<int> source = new TaskCompletionSource<int>();
CancellationTokenRegistration registration = new CancellationTokenRegistration();
if (cancellationToken.CanBeCanceled)
{
if (cancellationToken.IsCancellationRequested)
{
source.SetCanceled();
return source.Task;
}
registration = cancellationToken.Register(CancelIgnoreFailure);
}
Task<int> returnedTask = source.Task;
try
{
RegisterForConnectionCloseNotification(ref returnedTask);
Task<int>.Factory.FromAsync(BeginExecuteNonQueryAsync, EndExecuteNonQueryAsync, null).ContinueWith((t) =>
{
registration.Dispose();
if (t.IsFaulted)
{
Exception e = t.Exception.InnerException;
source.SetException(e);
}
else
{
if (t.IsCanceled)
{
source.SetCanceled();
}
else
{
source.SetResult(t.Result);
}
}
}, TaskScheduler.Default);
}
catch (Exception e)
{
source.SetException(e);
}
return returnedTask;
}
protected override Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
{
return ExecuteReaderAsync(behavior, cancellationToken).ContinueWith<DbDataReader>((result) =>
{
if (result.IsFaulted)
{
throw result.Exception.InnerException;
}
return result.Result;
}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default);
}
new public Task<SqlDataReader> ExecuteReaderAsync()
{
return ExecuteReaderAsync(CommandBehavior.Default, CancellationToken.None);
}
new public Task<SqlDataReader> ExecuteReaderAsync(CommandBehavior behavior)
{
return ExecuteReaderAsync(behavior, CancellationToken.None);
}
new public Task<SqlDataReader> ExecuteReaderAsync(CancellationToken cancellationToken)
{
return ExecuteReaderAsync(CommandBehavior.Default, cancellationToken);
}
new public Task<SqlDataReader> ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
{
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteReaderAsync|API|Correlation> ObjectID%d#, behavior=%d{ds.CommandBehavior}, ActivityID %ls\n", ObjectID, (int)behavior);
SqlConnection.ExecutePermission.Demand();
TaskCompletionSource<SqlDataReader> source = new TaskCompletionSource<SqlDataReader>();
CancellationTokenRegistration registration = new CancellationTokenRegistration();
if (cancellationToken.CanBeCanceled)
{
if (cancellationToken.IsCancellationRequested)
{
source.SetCanceled();
return source.Task;
}
registration = cancellationToken.Register(CancelIgnoreFailure);
}
Task<SqlDataReader> returnedTask = source.Task;
try
{
RegisterForConnectionCloseNotification(ref returnedTask);
Task<SqlDataReader>.Factory.FromAsync(BeginExecuteReaderAsync, EndExecuteReaderAsync, behavior, null).ContinueWith((t) =>
{
registration.Dispose();
if (t.IsFaulted)
{
Exception e = t.Exception.InnerException;
source.SetException(e);
}
else
{
if (t.IsCanceled)
{
source.SetCanceled();
}
else
{
source.SetResult(t.Result);
}
}
}, TaskScheduler.Default);
}
catch (Exception e)
{
source.SetException(e);
}
return returnedTask;
}
internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, string method)
{
Task unused; // sync execution
bool usedCache;
SqlDataReader reader = RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, completion: null, timeout: CommandTimeout, task: out unused, usedCache: out usedCache);
Debug.Assert(unused == null, "returned task during synchronous execution");
return reader;
}
internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, string method, TaskCompletionSource<object> completion, int timeout, out Task task, out bool usedCache, bool asyncWrite = false, bool inRetry = false)
{
bool async = (null != completion);
usedCache = false;
task = null;
_rowsAffected = -1;
_rowsAffectedBySpDescribeParameterEncryption = -1;
if (0 != (CommandBehavior.SingleRow & cmdBehavior))
{
cmdBehavior |= CommandBehavior.SingleResult;
}
if (!inRetry)
{
ValidateCommand(method, async);
}
CheckNotificationStateAndAutoEnlist();
TdsParser bestEffortCleanupTarget = null;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
#if DEBUG
TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
RuntimeHelpers.PrepareConstrainedRegions();
try {
tdsReliabilitySection.Start();
#else
{
#endif //DEBUG
bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection);
SqlStatistics statistics = Statistics;
if (null != statistics)
{
if ((!this.IsDirty && this.IsPrepared && !_hiddenPrepare)
|| (this.IsPrepared && _execType == EXECTYPE.PREPAREPENDING))
{
statistics.SafeIncrement(ref statistics._preparedExecs);
}
else
{
statistics.SafeIncrement(ref statistics._unpreparedExecs);
}
}
ResetEncryptionState();
if (_activeConnection.IsContextConnection)
{
return RunExecuteReaderSmi(cmdBehavior, runBehavior, returnStream);
}
else if (IsColumnEncryptionEnabled)
{
Task returnTask = null;
PrepareForTransparentEncryption(cmdBehavior, returnStream, async, timeout, completion, out returnTask, asyncWrite && async, out usedCache, inRetry);
Debug.Assert(usedCache || (async == (returnTask != null)), @"if we didn't use the cache, returnTask should be null if and only if async is false.");
long firstAttemptStart = ADP.TimerCurrent();
try
{
return RunExecuteReaderTdsWithTransparentParameterEncryption(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry, ds: null,
describeParameterEncryptionRequest: false, describeParameterEncryptionTask: returnTask);
}
catch (SqlException ex)
{
if (inRetry || async || !usedCache)
{
throw;
}
bool shouldRetry = false;
for (int i = 0; i < ex.Errors.Count; i++)
{
if (ex.Errors[i].Number == TdsEnums.TCE_CONVERSION_ERROR_CLIENT_RETRY)
{
shouldRetry = true;
break;
}
}
if (!shouldRetry)
{
throw;
}
else
{
SqlQueryMetadataCache.GetInstance().InvalidateCacheEntry(this);
return RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, null, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, async, inRetry: true);
}
}
}
else
{
return RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry);
}
}
#if DEBUG
finally {
tdsReliabilitySection.Stop();
}
#endif //DEBUG
}
catch (System.OutOfMemoryException e)
{
_activeConnection.Abort(e);
throw;
}
catch (System.StackOverflowException e)
{
_activeConnection.Abort(e);
throw;
}
catch (System.Threading.ThreadAbortException e)
{
_activeConnection.Abort(e);
SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
throw;
}
}
private SqlDataReader RunExecuteReaderTdsWithTransparentParameterEncryption(CommandBehavior cmdBehavior,
RunBehavior runBehavior,
bool returnStream,
bool async,
int timeout,
out Task task,
bool asyncWrite,
bool inRetry,
SqlDataReader ds = null,
bool describeParameterEncryptionRequest = false,
Task describeParameterEncryptionTask = null)
{
Debug.Assert(!asyncWrite || async, "AsyncWrite should be always accompanied by Async");
if (ds == null && returnStream)
{
ds = new SqlDataReader(this, cmdBehavior);
}
if (describeParameterEncryptionTask != null)
{
long parameterEncryptionStart = ADP.TimerCurrent();
TaskCompletionSource<object> completion = new TaskCompletionSource<object>();
AsyncHelper.ContinueTask(describeParameterEncryptionTask, completion,
() =>
{
Task subTask = null;
RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, parameterEncryptionStart), out subTask, asyncWrite, inRetry, ds);
if (subTask == null)
{
completion.SetResult(null);
}
else
{
AsyncHelper.ContinueTask(subTask, completion, () => completion.SetResult(null));
}
}, connectionToDoom: null,
onFailure: ((exception) =>
{
if (_cachedAsyncState != null)
{
_cachedAsyncState.ResetAsyncState();
}
if (exception != null)
{
throw exception;
}
}),
onCancellation: (() =>
{
if (_cachedAsyncState != null)
{
_cachedAsyncState.ResetAsyncState();
}
}),
connectionToAbort: _activeConnection);
task = completion.Task;
return ds;
}
else
{
// Synchronous execution.
return RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite, inRetry, ds);
}
}
private SqlDataReader RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, bool async, int timeout, out Task task, bool asyncWrite, bool inRetry, SqlDataReader ds = null, bool describeParameterEncryptionRequest = false)
{
Debug.Assert(!asyncWrite || async, "AsyncWrite should be always accompanied by Async");
if (ds == null && returnStream)
{
ds = new SqlDataReader(this, cmdBehavior);
}
Task reconnectTask = _activeConnection.ValidateAndReconnect(null, timeout);
if (reconnectTask != null)
{
long reconnectionStart = ADP.TimerCurrent();
if (async)
{
TaskCompletionSource<object> completion = new TaskCompletionSource<object>();
_activeConnection.RegisterWaitingForReconnect(completion.Task);
_reconnectionCompletionSource = completion;
CancellationTokenSource timeoutCTS = new CancellationTokenSource();
AsyncHelper.SetTimeoutException(completion, timeout, SQL.CR_ReconnectTimeout, timeoutCTS.Token);
AsyncHelper.ContinueTask(reconnectTask, completion,
() =>
{
if (completion.Task.IsCompleted)
{
return;
}
Interlocked.CompareExchange(ref _reconnectionCompletionSource, null, completion);
timeoutCTS.Cancel();
Task subTask;
RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, reconnectionStart), out subTask, asyncWrite, inRetry, ds);
if (subTask == null)
{
completion.SetResult(null);
}
else
{
AsyncHelper.ContinueTask(subTask, completion, () => completion.SetResult(null));
}
}, connectionToAbort: _activeConnection);
task = completion.Task;
return ds;
}
else
{
AsyncHelper.WaitForCompletion(reconnectTask, timeout, () => { throw SQL.CR_ReconnectTimeout(); });
timeout = TdsParserStaticMethods.GetRemainingTimeout(timeout, reconnectionStart);
}
}
Debug.Assert(null != _activeConnection.Parser, "TdsParser class should not be null in Command.Execute!");
bool inSchema = (0 != (cmdBehavior & CommandBehavior.SchemaOnly));
// create a new RPC
_SqlRPC rpc = null;
task = null;
string optionSettings = null;
bool processFinallyBlock = true;
bool decrementAsyncCountOnFailure = false;
if (async && !inRetry)
{
_activeConnection.GetOpenTdsConnection().IncrementAsyncCount();
decrementAsyncCountOnFailure = true;
}
try
{
if (asyncWrite)
{
_activeConnection.AddWeakReference(this, SqlReferenceCollection.CommandTag);
}
GetStateObject();
Task writeTask = null;
if (describeParameterEncryptionRequest)
{
#if DEBUG
if (_sleepDuringRunExecuteReaderTdsForSpDescribeParameterEncryption) {
Thread.Sleep(10000);
}
#endif
Debug.Assert(_sqlRPCParameterEncryptionReqArray != null, "RunExecuteReader rpc array not provided for describe parameter encryption request.");
writeTask = _stateObj.Parser.TdsExecuteRPC(this, _sqlRPCParameterEncryptionReqArray, timeout, inSchema, this.Notification, _stateObj, CommandType.StoredProcedure == CommandType, sync: !asyncWrite);
}
else if (BatchRPCMode)
{
Debug.Assert(inSchema == false, "Batch RPC does not support schema only command beahvior");
Debug.Assert(!IsPrepared, "Batch RPC should not be prepared!");
Debug.Assert(!IsDirty, "Batch RPC should not be marked as dirty!");
//Currently returnStream is always false, but we may want to return a Reader later.
//if (returnStream) {
// Bid.Trace("<sc.SqlCommand.ExecuteReader|INFO> %d#, Command executed as batch RPC.\n", ObjectID);
//}
Debug.Assert(_SqlRPCBatchArray != null, "RunExecuteReader rpc array not provided");
writeTask = _stateObj.Parser.TdsExecuteRPC(this, _SqlRPCBatchArray, timeout, inSchema, this.Notification, _stateObj, CommandType.StoredProcedure == CommandType, sync: !asyncWrite);
}
else if ((System.Data.CommandType.Text == this.CommandType) && (0 == GetParameterCount(_parameters)))
{
Debug.Assert(!IsUserPrepared, "CommandType.Text with no params should not be prepared!");
if (returnStream)
{
Bid.Trace("<sc.SqlCommand.ExecuteReader|INFO> %d#, Command executed as SQLBATCH.\n", ObjectID);
}
string text = GetCommandText(cmdBehavior) + GetResetOptionsString(cmdBehavior);
writeTask = _stateObj.Parser.TdsExecuteSQLBatch(text, timeout, this.Notification, _stateObj, sync: !asyncWrite);
}
else if (System.Data.CommandType.Text == this.CommandType)
{
if (this.IsDirty)
{
Debug.Assert(_cachedMetaData == null || !_dirty, "dirty query should not have cached metadata!");
if (_execType == EXECTYPE.PREPARED)
{
_hiddenPrepare = true;
}
Unprepare();
IsDirty = false;
}
if (_execType == EXECTYPE.PREPARED)
{
Debug.Assert(this.IsPrepared && (_prepareHandle != -1), "invalid attempt to call sp_execute without a handle!");
rpc = BuildExecute(inSchema);
}
else if (_execType == EXECTYPE.PREPAREPENDING)
{
Debug.Assert(_activeConnection.IsShiloh, "Invalid attempt to call sp_prepexec on non 7.x server");
rpc = BuildPrepExec(cmdBehavior);
// next time through, only do an exec
_execType = EXECTYPE.PREPARED;
_preparedConnectionCloseCount = _activeConnection.CloseCount;
_preparedConnectionReconnectCount = _activeConnection.ReconnectCount;
// mark ourselves as preparing the command
_inPrepare = true;
}
else
{
Debug.Assert(_execType == EXECTYPE.UNPREPARED, "Invalid execType!");
BuildExecuteSql(cmdBehavior, null, _parameters, ref rpc);
}
// if shiloh, then set NOMETADATA_UNLESSCHANGED flag
if (_activeConnection.IsShiloh)
rpc.options = TdsEnums.RPC_NOMETADATA;
if (returnStream)
{
Bid.Trace("<sc.SqlCommand.ExecuteReader|INFO> %d#, Command executed as RPC.\n", ObjectID);
}
Debug.Assert(_rpcArrayOf1[0] == rpc);
writeTask = _stateObj.Parser.TdsExecuteRPC(this, _rpcArrayOf1, timeout, inSchema, this.Notification, _stateObj, CommandType.StoredProcedure == CommandType, sync: !asyncWrite);
}
else
{
Debug.Assert(this.CommandType == System.Data.CommandType.StoredProcedure, "unknown command type!");
Debug.Assert(IsShiloh || !IsPrepared, "RPC should not be prepared!");
Debug.Assert(IsShiloh || !IsDirty, "RPC should not be marked as dirty!");
BuildRPC(inSchema, _parameters, ref rpc);
optionSettings = GetSetOptionsString(cmdBehavior);
if (returnStream)
{
Bid.Trace("<sc.SqlCommand.ExecuteReader|INFO> %d#, Command executed as RPC.\n", ObjectID);
}
// turn set options ON
if (null != optionSettings)
{
Task executeTask = _stateObj.Parser.TdsExecuteSQLBatch(optionSettings, timeout, this.Notification, _stateObj, sync: true);
Debug.Assert(executeTask == null, "Shouldn't get a task when doing sync writes");
bool dataReady;
Debug.Assert(_stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
bool result = _stateObj.Parser.TryRun(RunBehavior.UntilDone, this, null, null, _stateObj, out dataReady);
if (!result) { throw SQL.SynchronousCallMayNotPend(); }
// and turn OFF when the ds exhausts the stream on Close()
optionSettings = GetResetOptionsString(cmdBehavior);
}
// turn debugging on
_activeConnection.CheckSQLDebug();
// execute sp
Debug.Assert(_rpcArrayOf1[0] == rpc);
writeTask = _stateObj.Parser.TdsExecuteRPC(this, _rpcArrayOf1, timeout, inSchema, this.Notification, _stateObj, CommandType.StoredProcedure == CommandType, sync: !asyncWrite);
}
Debug.Assert(writeTask == null || async, "Returned task in sync mode");
if (async)
{
decrementAsyncCountOnFailure = false;
if (writeTask != null)
{
task = AsyncHelper.CreateContinuationTask(writeTask, () =>
{
_activeConnection.GetOpenTdsConnection(); // it will throw if connection is closed
cachedAsyncState.SetAsyncReaderState(ds, runBehavior, optionSettings);
},
onFailure: (exc) =>
{
_activeConnection.GetOpenTdsConnection().DecrementAsyncCount();
});
}
else
{
cachedAsyncState.SetAsyncReaderState(ds, runBehavior, optionSettings);
}
}
else
{
// Always execute - even if no reader!
FinishExecuteReader(ds, runBehavior, optionSettings, isInternal: false, forDescribeParameterEncryption: false);
}
}
catch (Exception e)
{
processFinallyBlock = ADP.IsCatchableExceptionType(e);
if (decrementAsyncCountOnFailure)
{
SqlInternalConnectionTds innerConnectionTds = (_activeConnection.InnerConnection as SqlInternalConnectionTds);
if (null != innerConnectionTds)
{ // it may be closed
innerConnectionTds.DecrementAsyncCount();
}
}
throw;
}
finally
{
TdsParser.ReliabilitySection.Assert("unreliable call to RunExecuteReaderTds");
if (processFinallyBlock && !async)
{
PutStateObject();
}
}
Debug.Assert(async || null == _stateObj, "non-null state object in RunExecuteReader");
return ds;
}
}