diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index dcafb119eb..d589463e3d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -1185,10 +1185,10 @@ private object CompleteExecuteScalar(SqlDataReader ds, bool returnLastResult) return retResult; } - private Task InternalExecuteNonQueryWithRetry(bool sendToPipe, int timeout, out bool usedCache, bool asyncWrite, bool inRetry, [CallerMemberName] string methodName = "") + private Task InternalExecuteNonQueryWithRetry(int timeout, out bool usedCache, bool asyncWrite, bool inRetry, [CallerMemberName] string methodName = "") { bool innerUsedCache = false; - Task result = RetryLogicProvider.Execute(this, () => InternalExecuteNonQuery(completion: null, sendToPipe, timeout, out innerUsedCache, asyncWrite, inRetry, methodName)); + Task result = RetryLogicProvider.Execute(this, () => InternalExecuteNonQuery(completion: null, timeout, out innerUsedCache, asyncWrite, inRetry, methodName)); usedCache = innerUsedCache; return result; } @@ -1214,11 +1214,11 @@ public override int ExecuteNonQuery() WriteBeginExecuteEvent(); if (IsProviderRetriable) { - InternalExecuteNonQueryWithRetry(sendToPipe: false, timeout: CommandTimeout, out _, asyncWrite: false, inRetry: false); + InternalExecuteNonQueryWithRetry(timeout: CommandTimeout, out _, asyncWrite: false, inRetry: false); } else { - InternalExecuteNonQuery(completion: null, sendToPipe: false, timeout: CommandTimeout, out _); + InternalExecuteNonQuery(completion: null, timeout: CommandTimeout, out _); } success = true; return _rowsAffected; @@ -1283,7 +1283,7 @@ private IAsyncResult BeginExecuteNonQueryInternal(CommandBehavior behavior, Asyn try { // InternalExecuteNonQuery already has reliability block, but if failure will not put stateObj back into pool. - Task execNQ = InternalExecuteNonQuery(localCompletion, false, timeout, out usedCache, asyncWrite, inRetry: inRetry, methodName: nameof(BeginExecuteNonQuery)); + Task execNQ = InternalExecuteNonQuery(localCompletion, timeout, out usedCache, asyncWrite, inRetry: inRetry, methodName: nameof(BeginExecuteNonQuery)); if (execNQ != null) { @@ -1647,7 +1647,7 @@ private object InternalEndExecuteNonQuery(IAsyncResult asyncResult, bool isInter return _rowsAffected; } - private Task InternalExecuteNonQuery(TaskCompletionSource completion, bool sendToPipe, int timeout, out bool usedCache, bool asyncWrite = false, bool inRetry = false, [CallerMemberName] string methodName = "") + private Task InternalExecuteNonQuery(TaskCompletionSource completion, int timeout, out bool usedCache, bool asyncWrite = false, bool inRetry = false, [CallerMemberName] string methodName = "") { SqlClientEventSource.Log.TryTraceEvent("SqlCommand.InternalExecuteNonQuery | INFO | ObjectId {0}, Client Connection Id {1}, AsyncCommandInProgress={2}", _activeConnection?.ObjectID, _activeConnection?.ClientConnectionId, _activeConnection?.AsyncCommandInProgress); @@ -1670,10 +1670,8 @@ private Task InternalExecuteNonQuery(TaskCompletionSource completion, bo // Always Encrypted generally operates only on parameterized queries. However enclave based Always encrypted also supports unparameterized queries // We skip this block for enclave based always encrypted so that we can make a call to SQL Server to get the encryption information - if (!ShouldUseEnclaveBasedWorkflow && !_batchRPCMode && (CommandType.Text == CommandType) && (0 == GetParameterCount(_parameters))) + if (!ShouldUseEnclaveBasedWorkflow && !_batchRPCMode && CommandType == CommandType.Text && GetParameterCount(_parameters) == 0) { - Debug.Assert(!sendToPipe, "Trying to send non-context command to pipe"); - if (statistics != null) { if (!IsDirty && IsPrepared) @@ -1695,7 +1693,6 @@ private Task InternalExecuteNonQuery(TaskCompletionSource completion, bo else { // otherwise, use a full-fledged execute that can handle params and stored procs - Debug.Assert(!sendToPipe, "Trying to send non-context command to pipe"); SqlClientEventSource.Log.TryTraceEvent("SqlCommand.InternalExecuteNonQuery | INFO | Object Id {0}, RPC execute method name {1}, isAsync {2}, inRetry {3}", ObjectID, methodName, isAsync, inRetry); SqlDataReader reader = RunExecuteReader(0, RunBehavior.UntilDone, false, completion, timeout, out task, out usedCache, asyncWrite, inRetry, methodName); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index d45c126fdb..4608b17843 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -941,17 +941,12 @@ - - - - - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs index 8eaaa51c12..07f985acd7 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs @@ -181,7 +181,6 @@ public SourceColumnMetadata(ValueMethod method, bool isSqlType, bool isDataFeed) private object _rowSource; private SqlDataReader _sqlDataReaderRowSource; - private bool _rowSourceIsSqlDataReaderSmi; private DbDataReader _dbDataReaderRowSource; private DataTable _dataTableSource; @@ -1253,7 +1252,7 @@ private SourceColumnMetadata GetColumnMetadata(int ordinal) } } // Check for data streams - else if ((_enableStreaming) && ((metadata.length == MAX_LENGTH) || metadata.metaType.SqlDbType == SqlDbTypeExtensions.Json) && (!_rowSourceIsSqlDataReaderSmi)) + else if ((_enableStreaming) && ((metadata.length == MAX_LENGTH) || metadata.metaType.SqlDbType == SqlDbTypeExtensions.Json)) { isSqlType = false; @@ -1697,10 +1696,6 @@ public void WriteToServer(DbDataReader reader) _dbDataReaderRowSource = reader; _sqlDataReaderRowSource = reader as SqlDataReader; - if (_sqlDataReaderRowSource != null) - { - _rowSourceIsSqlDataReaderSmi = _sqlDataReaderRowSource is SqlDataReaderSmi; - } _rowSourceType = ValueSourceType.DbDataReader; WriteRowSourceToServerAsync(reader.FieldCount, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; @@ -1733,10 +1728,6 @@ public void WriteToServer(IDataReader reader) ResetWriteToServerGlobalVariables(); _rowSource = reader; _sqlDataReaderRowSource = _rowSource as SqlDataReader; - if (_sqlDataReaderRowSource != null) - { - _rowSourceIsSqlDataReaderSmi = _sqlDataReaderRowSource is SqlDataReaderSmi; - } _dbDataReaderRowSource = _rowSource as DbDataReader; _rowSourceType = ValueSourceType.IDataReader; WriteRowSourceToServerAsync(reader.FieldCount, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientWrapperSmiStream.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientWrapperSmiStream.cs deleted file mode 100644 index a728b608ed..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientWrapperSmiStream.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.IO; - -namespace Microsoft.Data.SqlClient.Server -{ - // Simple wrapper over SmiStream that handles server events on the SqlClient side of Smi - internal class SqlClientWrapperSmiStream : Stream - { - - private SmiEventSink_Default _sink; - private SmiStream _stream; - - internal SqlClientWrapperSmiStream(SmiEventSink_Default sink, SmiStream stream) - { - Debug.Assert(sink != null); - Debug.Assert(stream != null); - _sink = sink; - _stream = stream; - } - - public override bool CanRead - { - get - { - return _stream.CanRead; - } - } - - // If CanSeek is false, Position, Seek, Length, and SetLength should throw. - public override bool CanSeek - { - get - { - return _stream.CanSeek; - } - } - - public override bool CanWrite - { - get - { - return _stream.CanWrite; - } - } - - public override long Length - { - get - { - long length = _stream.GetLength(_sink); - _sink.ProcessMessagesAndThrow(); - return length; - } - } - - public override long Position - { - get - { - long position = _stream.GetPosition(_sink); - _sink.ProcessMessagesAndThrow(); - return position; - } - set - { - _stream.SetPosition(_sink, value); - _sink.ProcessMessagesAndThrow(); - } - } - - public override void Flush() - { - _stream.Flush(_sink); - _sink.ProcessMessagesAndThrow(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - long result = _stream.Seek(_sink, offset, origin); - _sink.ProcessMessagesAndThrow(); - return result; - } - - public override void SetLength(long value) - { - _stream.SetLength(_sink, value); - _sink.ProcessMessagesAndThrow(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - int bytesRead = _stream.Read(_sink, buffer, offset, count); - _sink.ProcessMessagesAndThrow(); - return bytesRead; - } - - public override void Write(byte[] buffer, int offset, int count) - { - _stream.Write(_sink, buffer, offset, count); - _sink.ProcessMessagesAndThrow(); - } - } - -} - - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientWrapperSmiStreamChars.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientWrapperSmiStreamChars.cs deleted file mode 100644 index 99eeb4d91c..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientWrapperSmiStreamChars.cs +++ /dev/null @@ -1,147 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.IO; -using Microsoft.Data.Common; -using Microsoft.Data.SqlTypes; - -namespace Microsoft.Data.SqlClient.Server -{ - // Simple SqlStreamChars wrapper over SmiStream that handles server events on the - // SqlClient side of Smi - internal class SqlClientWrapperSmiStreamChars : SqlStreamChars - { - - private SmiEventSink_Default _sink; - private SmiStream _stream; - - internal SqlClientWrapperSmiStreamChars(SmiEventSink_Default sink, SmiStream stream) - { - Debug.Assert(sink != null); - Debug.Assert(stream != null); - _sink = sink; - _stream = stream; - } - - public override bool IsNull - { - get - { - return _stream == null; - } - } - - public override bool CanRead - { - get - { - return _stream.CanRead; - } - } - - // If CanSeek is false, Position, Seek, Length, and SetLength should throw. - public override bool CanSeek - { - get - { - return _stream.CanSeek; - } - } - - public override bool CanWrite - { - get - { - return _stream.CanWrite; - } - } - - public override long Length - { - get - { - long length = _stream.GetLength(_sink); - _sink.ProcessMessagesAndThrow(); - if (length > 0) - return length / sizeof(char); - else - return length; - } - } - - public override long Position - { - get - { - long position = _stream.GetPosition(_sink) / sizeof(char); - _sink.ProcessMessagesAndThrow(); - return position; - } - set - { - if (value < 0) - { - throw ADP.ArgumentOutOfRange("Position"); - } - _stream.SetPosition(_sink, value * sizeof(char)); - _sink.ProcessMessagesAndThrow(); - } - } - - public override void Flush() - { - _stream.Flush(_sink); - _sink.ProcessMessagesAndThrow(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - long result = _stream.Seek(_sink, offset * sizeof(char), origin); - _sink.ProcessMessagesAndThrow(); - return result; - } - - public override void SetLength(long value) - { - if (value < 0) - { - throw ADP.ArgumentOutOfRange("value"); - } - _stream.SetLength(_sink, value * sizeof(char)); - _sink.ProcessMessagesAndThrow(); - } - - public override int Read(char[] buffer, int offset, int count) - { - int bytesRead = _stream.Read(_sink, buffer, offset * sizeof(char), count); - _sink.ProcessMessagesAndThrow(); - return bytesRead; - } - - public override void Write(char[] buffer, int offset, int count) - { - _stream.Write(_sink, buffer, offset, count); - _sink.ProcessMessagesAndThrow(); - } - - // Convenience methods to allow simple pulling/pushing of raw bytes - internal int Read(byte[] buffer, int offset, int count) - { - int bytesRead = _stream.Read(_sink, buffer, offset, count); - _sink.ProcessMessagesAndThrow(); - return bytesRead; - } - - internal void Write(byte[] buffer, int offset, int count) - { - _stream.Write(_sink, buffer, offset, count); - _sink.ProcessMessagesAndThrow(); - } - } - -} - - - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs index 70d9f72ebc..dcc81ffe88 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -1448,10 +1448,10 @@ private object CompleteExecuteScalar(SqlDataReader ds, bool returnLastResult) return retResult; } - private Task InternalExecuteNonQueryWithRetry(string methodName, bool sendToPipe, int timeout, out bool usedCache, bool asyncWrite, bool inRetry) + private Task InternalExecuteNonQueryWithRetry(string methodName, int timeout, out bool usedCache, bool asyncWrite, bool inRetry) { bool innerUsedCache = false; - Task result = RetryLogicProvider.Execute(this, () => InternalExecuteNonQuery(completion: null, methodName, sendToPipe, timeout, out innerUsedCache, asyncWrite, inRetry)); + Task result = RetryLogicProvider.Execute(this, () => InternalExecuteNonQuery(completion: null, methodName, timeout, out innerUsedCache, asyncWrite, inRetry)); usedCache = innerUsedCache; return result; } @@ -1479,11 +1479,11 @@ public override int ExecuteNonQuery() WriteBeginExecuteEvent(); if (IsProviderRetriable) { - InternalExecuteNonQueryWithRetry(nameof(ExecuteNonQuery), sendToPipe: false, CommandTimeout, out _, asyncWrite: false, inRetry: false); + InternalExecuteNonQueryWithRetry(nameof(ExecuteNonQuery), CommandTimeout, out _, asyncWrite: false, inRetry: false); } else { - InternalExecuteNonQuery(null, nameof(ExecuteNonQuery), sendToPipe: false, CommandTimeout, out _); + InternalExecuteNonQuery(null, nameof(ExecuteNonQuery), CommandTimeout, out _); } success = true; return _rowsAffected; @@ -1501,32 +1501,6 @@ public override int ExecuteNonQuery() } } - // Handles in-proc execute-to-pipe functionality - // Identical to ExecuteNonQuery - internal void ExecuteToPipe(SmiContext pipeContext) - { - SqlConnection.ExecutePermission.Demand(); - - // Reset _pendingCancel upon entry into any Execute - used to synchronize state - // between entry into Execute* API and the thread obtaining the stateObject. - _pendingCancel = false; - - SqlStatistics statistics = null; - - using (TryEventScope.Create(" {0}", ObjectID)) - { - try - { - statistics = SqlStatistics.StartTimer(Statistics); - InternalExecuteNonQuery(null, nameof(ExecuteNonQuery), true, CommandTimeout, out _); - } - finally - { - SqlStatistics.StopTimer(statistics); - } - } - } - /// [System.Security.Permissions.HostProtectionAttribute(ExternalThreading = true)] public IAsyncResult BeginExecuteNonQuery() @@ -1576,7 +1550,7 @@ private IAsyncResult BeginExecuteNonQueryInternal(CommandBehavior behavior, Asyn bool usedCache; try { // InternalExecuteNonQuery already has reliability block, but if failure will not put stateObj back into pool. - Task execNQ = InternalExecuteNonQuery(localCompletion, nameof(BeginExecuteNonQuery), false, timeout, out usedCache, asyncWrite, inRetry: inRetry); + Task execNQ = InternalExecuteNonQuery(localCompletion, nameof(BeginExecuteNonQuery), timeout, out usedCache, asyncWrite, inRetry: inRetry); if (execNQ != null) { AsyncHelper.ContinueTaskWithState(execNQ, localCompletion, this, (object state) => ((SqlCommand)state).BeginExecuteNonQueryInternalReadStage(localCompletion)); @@ -1940,7 +1914,7 @@ private object InternalEndExecuteNonQuery(IAsyncResult asyncResult, string endMe } } - private Task InternalExecuteNonQuery(TaskCompletionSource completion, string methodName, bool sendToPipe, int timeout, out bool usedCache, bool asyncWrite = false, bool inRetry = false) + private Task InternalExecuteNonQuery(TaskCompletionSource completion, string methodName, int timeout, out bool usedCache, bool asyncWrite = false, bool inRetry = false) { SqlClientEventSource.Log.TryTraceEvent("SqlCommand.InternalExecuteNonQuery | INFO | ObjectId {0}, Client Connection Id {1}, AsyncCommandInProgress={2}", _activeConnection?.ObjectID, _activeConnection?.ClientConnectionId, _activeConnection?.AsyncCommandInProgress); @@ -1965,44 +1939,31 @@ private Task InternalExecuteNonQuery(TaskCompletionSource completion, st Task task = null; - // only send over SQL Batch command if we are not a stored proc and have no parameters and not in batch RPC mode - if (_activeConnection.IsContextConnection) - { - if (statistics != null) - { - statistics.SafeIncrement(ref statistics._unpreparedExecs); - } - - RunExecuteNonQuerySmi(sendToPipe); - } - - //Always Encrypted generally operates only on parameterized queries. However enclave based Always encrypted also supports unparameterized queries - //We skip this block for enclave based always encrypted so that we can make a call to SQL Server to get the encryption information - else if (!ShouldUseEnclaveBasedWorkflow && !_batchRPCMode && (System.Data.CommandType.Text == this.CommandType) && (0 == GetParameterCount(_parameters))) - { - Debug.Assert(!sendToPipe, "trying to send non-context command to pipe"); - if (statistics != null) + //Always Encrypted generally operates only on parameterized queries. However enclave based Always encrypted also supports unparameterized queries + //We skip this block for enclave based always encrypted so that we can make a call to SQL Server to get the encryption information + if (!ShouldUseEnclaveBasedWorkflow && !_batchRPCMode && CommandType == CommandType.Text && GetParameterCount(_parameters) == 0) { - if (!this.IsDirty && this.IsPrepared) - { - statistics.SafeIncrement(ref statistics._preparedExecs); - } - else + if (statistics != null) { - statistics.SafeIncrement(ref statistics._unpreparedExecs); + if (!this.IsDirty && this.IsPrepared) + { + statistics.SafeIncrement(ref statistics._preparedExecs); + } + else + { + statistics.SafeIncrement(ref statistics._unpreparedExecs); + } } - } // We should never get here for a retry since we only have retries for parameters. Debug.Assert(!inRetry); - task = RunExecuteNonQueryTds(methodName, async, timeout, asyncWrite); - } - else - { - // otherwise, use a full-fledged execute that can handle params and stored procs - Debug.Assert(!sendToPipe, "trying to send non-context command to pipe"); - SqlClientEventSource.Log.TryTraceEvent(" {0}, Command executed as RPC.", ObjectID); + task = RunExecuteNonQueryTds(methodName, async, timeout, asyncWrite); + } + else + { + // otherwise, use a full-fledged execute that can handle params and stored procs + SqlClientEventSource.Log.TryTraceEvent(" {0}, Command executed as RPC.", ObjectID); SqlDataReader reader = RunExecuteReader(0, RunBehavior.UntilDone, false, methodName, completion, timeout, out task, out usedCache, asyncWrite, inRetry); if (reader != null) @@ -3841,83 +3802,6 @@ private Task RunExecuteNonQueryTds(string methodName, bool async, int timeout, b return null; } - // Smi-specific logic for ExecuteNonQuery - private void RunExecuteNonQuerySmi(bool sendToPipe) - { - SqlInternalConnectionSmi innerConnection = InternalSmiConnection; - - // Set it up, process all of the events, and we're done! - SmiRequestExecutor requestExecutor = null; - try - { - requestExecutor = SetUpSmiRequest(innerConnection); - SmiExecuteType execType; - if (sendToPipe) - execType = SmiExecuteType.ToPipe; - else - execType = SmiExecuteType.NonQuery; - - - SmiEventStream eventStream = null; - // Don't need a CER here because caller already has one that will doom the - // connection if it's a finally-skipping type of problem. - bool processFinallyBlock = true; - try - { - long transactionId; - Transaction transaction; - innerConnection.GetCurrentTransactionPair(out transactionId, out transaction); - - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, innerConnection={1}, transactionId=0x{2}, cmdBehavior={3}.", ObjectID, innerConnection.ObjectID, transactionId, (int)CommandBehavior.Default); - - if (SmiContextFactory.Instance.NegotiatedSmiVersion >= SmiContextFactory.Sql2008Version) - { - eventStream = requestExecutor.Execute( - innerConnection.SmiConnection, - transactionId, - transaction, - CommandBehavior.Default, - execType); - } - else - { - eventStream = requestExecutor.Execute( - innerConnection.SmiConnection, - transactionId, - CommandBehavior.Default, - execType); - } - - while (eventStream.HasEvents) - { - eventStream.ProcessEvent(EventSink); - } - } - catch (Exception e) - { - processFinallyBlock = ADP.IsCatchableExceptionType(e); - throw; - } - finally - { - if (eventStream != null && processFinallyBlock) - { - eventStream.Close(EventSink); - } - } - - EventSink.ProcessMessagesAndThrow(); - } - finally - { - if (requestExecutor != null) - { - requestExecutor.Close(EventSink); - EventSink.ProcessMessagesAndThrow(ignoreNonFatalMessages: true); - } - } - } - /// /// Resets the encryption related state of the command object and each of the parameters. /// BatchRPC doesn't need special handling to cleanup the state of each RPC object and its parameters since a new RPC object and @@ -4956,15 +4840,11 @@ internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior // Reset the encryption related state of the command and its parameters. 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."); + 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(); @@ -5431,89 +5311,6 @@ private SqlDataReader RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavi return ds; } - private SqlDataReader RunExecuteReaderSmi(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream) - { - SqlInternalConnectionSmi innerConnection = InternalSmiConnection; - - SmiEventStream eventStream = null; - SqlDataReader ds = null; - SmiRequestExecutor requestExecutor = null; - try - { - // Set it up, process all of the events, and we're done! - requestExecutor = SetUpSmiRequest(innerConnection); - - long transactionId; - Transaction transaction; - innerConnection.GetCurrentTransactionPair(out transactionId, out transaction); - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, innerConnection={1}, transactionId=0x{2}, commandBehavior={(int)cmdBehavior}.", ObjectID, innerConnection.ObjectID, transactionId); - - if (SmiContextFactory.Instance.NegotiatedSmiVersion >= SmiContextFactory.Sql2008Version) - { - eventStream = requestExecutor.Execute( - innerConnection.SmiConnection, - transactionId, - transaction, - cmdBehavior, - SmiExecuteType.Reader - ); - } - else - { - eventStream = requestExecutor.Execute( - innerConnection.SmiConnection, - transactionId, - cmdBehavior, - SmiExecuteType.Reader - ); - } - - if ((runBehavior & RunBehavior.UntilDone) != 0) - { - - // Consume the results - while (eventStream.HasEvents) - { - eventStream.ProcessEvent(EventSink); - } - eventStream.Close(EventSink); - } - - if (returnStream) - { - ds = new SqlDataReaderSmi(eventStream, this, cmdBehavior, innerConnection, EventSink, requestExecutor); - ds.NextResult(); // Position on first set of results - _activeConnection.AddWeakReference(ds, SqlReferenceCollection.DataReaderTag); - } - - EventSink.ProcessMessagesAndThrow(); - } - catch (Exception e) - { - // VSTS 159716 - we do not want to handle ThreadAbort, OutOfMemory or similar critical exceptions - // because the state of used objects might remain invalid in this case - if (!ADP.IsCatchableOrSecurityExceptionType(e)) - { - throw; - } - - if (eventStream != null) - { - eventStream.Close(EventSink); // UNDONE: should cancel instead! - } - - if (requestExecutor != null) - { - requestExecutor.Close(EventSink); - EventSink.ProcessMessagesAndThrow(ignoreNonFatalMessages: true); - } - - throw; - } - - return ds; - } - private SqlDataReader CompleteAsyncExecuteReader(bool isInternal = false, bool forDescribeParameterEncryption = false) { SqlDataReader ds = cachedAsyncState.CachedAsyncReader; // should not be null @@ -7220,190 +7017,6 @@ internal SqlException GetErrors(int commandIndex) return result; } - // Allocates and initializes a new SmiRequestExecutor based on the current command state - private SmiRequestExecutor SetUpSmiRequest(SqlInternalConnectionSmi innerConnection) - { - - // General Approach To Ensure Security of Marshalling: - // Only touch each item in the command once - // (i.e. only grab a reference to each param once, only - // read the type from that param once, etc.). The problem is - // that if the user changes something on the command in the - // middle of marshaling, it can overwrite the native buffers - // set up. For example, if max length is used to allocate - // buffers, but then re-read from the parameter to truncate - // strings, the user could extend the length and overwrite - // the buffer. - - if (Notification != null) - { - throw SQL.NotificationsNotAvailableOnContextConnection(); - } - - SmiParameterMetaData[] requestMetaData = null; - ParameterPeekAheadValue[] peekAheadValues = null; - - // Length of rgMetadata becomes *the* official count of parameters to use, - // don't rely on Parameters.Count after this point, as the user could change it. - int count = GetParameterCount(Parameters); - if (0 < count) - { - requestMetaData = new SmiParameterMetaData[count]; - peekAheadValues = new ParameterPeekAheadValue[count]; - - // set up the metadata - for (int index = 0; index < count; index++) - { - SqlParameter param = Parameters[index]; - param.Validate(index, CommandType.StoredProcedure == CommandType); - requestMetaData[index] = param.MetaDataForSmi(out peekAheadValues[index]); - - // Check for valid type for version negotiated - if (!innerConnection.Is2008OrNewer) - { - MetaType mt = MetaType.GetMetaTypeFromSqlDbType(requestMetaData[index].SqlDbType, requestMetaData[index].IsMultiValued); - if (!mt.Is90Supported) - { - throw ADP.VersionDoesNotSupportDataType(mt.TypeName); - } - } - } - } - - // Allocate the new request - CommandType cmdType = CommandType; - _smiRequestContext = innerConnection.InternalContext; - SmiRequestExecutor requestExecutor = _smiRequestContext.CreateRequestExecutor( - CommandText, - cmdType, - requestMetaData, - EventSink - ); - - // deal with errors - EventSink.ProcessMessagesAndThrow(); - - // Now assign param values - for (int index = 0; index < count; index++) - { - if (ParameterDirection.Output != requestMetaData[index].Direction && - ParameterDirection.ReturnValue != requestMetaData[index].Direction) - { - SqlParameter param = Parameters[index]; - // going back to command for parameter is ok, since we'll only pick up values now. - object value = param.GetCoercedValue(); - if (value is XmlDataFeed && requestMetaData[index].SqlDbType != SqlDbType.Xml) - { - value = MetaType.GetStringFromXml(((XmlDataFeed)value)._source); - } - ExtendedClrTypeCode typeCode = MetaDataUtilsSmi.DetermineExtendedTypeCodeForUseWithSqlDbType(requestMetaData[index].SqlDbType, requestMetaData[index].IsMultiValued, value, null /* parameters don't use CLR Type for UDTs */, SmiContextFactory.Instance.NegotiatedSmiVersion); - - // Handle null reference as special case for parameters - if (CommandType.StoredProcedure == cmdType && - ExtendedClrTypeCode.Empty == typeCode) - { - requestExecutor.SetDefault(index); - } - else - { - // SQLBU 402391 & 403631: Exception to prevent Parameter.Size data corruption cases from working. - // This should be temporary until changing to correct behavior can be safely implemented. - // initial size criteria is the same for all affected types - // NOTE: assumes size < -1 is handled by SqlParameter.Size setter - int size = param.Size; - if (size != 0 && size != SmiMetaData.UnlimitedMaxLengthIndicator && !param.SizeInferred) - { - switch (requestMetaData[index].SqlDbType) - { - case SqlDbType.Image: - case SqlDbType.Text: - if (size != Int32.MaxValue) - { - throw SQL.ParameterSizeRestrictionFailure(index); - } - break; - - case SqlDbType.NText: - if (size != Int32.MaxValue / 2) - { - throw SQL.ParameterSizeRestrictionFailure(index); - } - break; - - case SqlDbType.VarBinary: - case SqlDbType.VarChar: - // Allow size==Int32.MaxValue because of DeriveParameters - if (size > 0 && size != Int32.MaxValue && requestMetaData[index].MaxLength == SmiMetaData.UnlimitedMaxLengthIndicator) - { - throw SQL.ParameterSizeRestrictionFailure(index); - } - break; - - case SqlDbType.NVarChar: - // Allow size==Int32.MaxValue/2 because of DeriveParameters - if (size > 0 && size != Int32.MaxValue / 2 && requestMetaData[index].MaxLength == SmiMetaData.UnlimitedMaxLengthIndicator) - { - throw SQL.ParameterSizeRestrictionFailure(index); - } - break; - - case SqlDbType.Timestamp: - // Size limiting for larger values will happen due to MaxLength - if (size < SmiMetaData.DefaultTimestamp.MaxLength) - { - throw SQL.ParameterSizeRestrictionFailure(index); - } - break; - - case SqlDbType.Variant: - // Variant problems happen when Size is less than maximums for character and binary values - // Size limiting for larger values will happen due to MaxLength - // NOTE: assumes xml and udt types are handled in parameter value coercion - // since server does not allow these types in a variant - if (value != null) - { - MetaType mt = MetaType.GetMetaTypeFromValue(value); - - if ((mt.IsNCharType && size < SmiMetaData.MaxUnicodeCharacters) || - (mt.IsBinType && size < SmiMetaData.MaxBinaryLength) || - (mt.IsAnsiType && size < SmiMetaData.MaxANSICharacters)) - { - throw SQL.ParameterSizeRestrictionFailure(index); - } - } - break; - - case SqlDbType.Xml: - // Xml is an issue for non-SqlXml types - if (value != null && ExtendedClrTypeCode.SqlXml != typeCode) - { - throw SQL.ParameterSizeRestrictionFailure(index); - } - break; - - // NOTE: Char, NChar, Binary and UDT do not need restricting because they are always 8k or less, - // so the metadata MaxLength will match the Size setting. - - default: - break; - } - } - - if (innerConnection.Is2008OrNewer) - { - ValueUtilsSmi.SetCompatibleValueV200(EventSink, requestExecutor, index, requestMetaData[index], value, typeCode, param.Offset, peekAheadValues[index]); - } - else - { - ValueUtilsSmi.SetCompatibleValue(EventSink, requestExecutor, index, requestMetaData[index], value, typeCode, param.Offset); - } - } - } - } - - return requestExecutor; - } - private void WriteBeginExecuteEvent() { SqlClientEventSource.Log.TryBeginExecuteEvent(ObjectID, Connection?.DataSource, Connection?.Database, CommandText, Connection?.ClientConnectionId); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReaderSmi.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReaderSmi.cs deleted file mode 100644 index 95a45c428d..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReaderSmi.cs +++ /dev/null @@ -1,1341 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Data; -using System.Data.Common; -using System.Data.SqlTypes; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using System.Xml; -using Microsoft.Data.Common; -using Microsoft.Data.ProviderBase; -using Microsoft.Data.SqlClient.Server; - - -using Microsoft.Data.SqlTypes; - -namespace Microsoft.Data.SqlClient -{ - // SqlServer provider's implementation of ISqlReader. - // Supports ISqlReader and ISqlResultSet objects. - // - // User should never be able to create one of these themselves, nor subclass. - // This is accomplished by having no public override constructors. - internal sealed class SqlDataReaderSmi : SqlDataReader - { - // - // IDBRecord properties - // - public override int FieldCount - { - get - { - ThrowIfClosed(); - return InternalFieldCount; - } - } - - public override int VisibleFieldCount - { - get - { - ThrowIfClosed(); - - if (FNotInResults()) - { - return 0; - } - - return _visibleColumnCount; - } - } - - // - // IDBRecord Metadata Methods - // - public override string GetName(int ordinal) - { - EnsureCanGetMetaData(); - return _currentMetaData[ordinal].Name; - } - - public override string GetDataTypeName(int ordinal) - { - EnsureCanGetMetaData(); - SmiExtendedMetaData md = _currentMetaData[ordinal]; - if (SqlDbType.Udt == md.SqlDbType) - { - return md.TypeSpecificNamePart1 + "." + md.TypeSpecificNamePart2 + "." + md.TypeSpecificNamePart3; - } - else - { - return md.TypeName; - } - } - - public override Type GetFieldType(int ordinal) - { - EnsureCanGetMetaData(); - if (_currentMetaData[ordinal].SqlDbType == SqlDbType.Udt) - { - return _currentMetaData[ordinal].Type; - } - else - { - return MetaType.GetMetaTypeFromSqlDbType(_currentMetaData[ordinal].SqlDbType, _currentMetaData[ordinal].IsMultiValued).ClassType; - } - } - - override public Type GetProviderSpecificFieldType(int ordinal) - { - EnsureCanGetMetaData(); - - if (SqlDbType.Udt == _currentMetaData[ordinal].SqlDbType) - { - return _currentMetaData[ordinal].Type; - } - else - { - return MetaType.GetMetaTypeFromSqlDbType(_currentMetaData[ordinal].SqlDbType, _currentMetaData[ordinal].IsMultiValued).SqlType; - } - } - - public override int Depth - { - get - { - ThrowIfClosed(); - return 0; - } - } // UNDONE: (alazela 10/14/2001) Multi-level reader not impl. - - public override object GetValue(int ordinal) - { - EnsureCanGetCol(ordinal); - SmiQueryMetaData metaData = _currentMetaData[ordinal]; - if (_currentConnection.Is2008OrNewer) - { - return ValueUtilsSmi.GetValue200(_readerEventSink, (SmiTypedGetterSetter)_currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); - } - else - { - return ValueUtilsSmi.GetValue(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); - } - } - - public override T GetFieldValue(int ordinal) - { - EnsureCanGetCol(ordinal); - SmiQueryMetaData metaData = _currentMetaData[ordinal]; - - if (typeof(INullable).IsAssignableFrom(typeof(T))) - { - // If its a SQL Type or Nullable UDT - if (_currentConnection.Is2008OrNewer) - { - return (T)ValueUtilsSmi.GetSqlValue200(_readerEventSink, (SmiTypedGetterSetter)_currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); - } - else - { - return (T)ValueUtilsSmi.GetSqlValue(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); - } - } - else - { - // Otherwise Its a CLR or non-Nullable UDT - if (_currentConnection.Is2008OrNewer) - { - return (T)ValueUtilsSmi.GetValue200(_readerEventSink, (SmiTypedGetterSetter)_currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); - } - else - { - return (T)ValueUtilsSmi.GetValue(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); - } - } - } - - public override Task GetFieldValueAsync(int ordinal, CancellationToken cancellationToken) - { - // As per Async spec, Context Connections do not support async - return ADP.CreatedTaskWithException(ADP.ExceptionWithStackTrace(SQL.NotAvailableOnContextConnection())); - } - - override internal SqlBuffer.StorageType GetVariantInternalStorageType(int ordinal) - { - Debug.Assert(_currentColumnValuesV3 != null, "Attempting to get variant internal storage type without calling GetValue first"); - if (IsDBNull(ordinal)) - { - return SqlBuffer.StorageType.Empty; - } - - SmiMetaData valueMetaData = _currentColumnValuesV3.GetVariantType(_readerEventSink, ordinal); - if (valueMetaData == null) - { - return SqlBuffer.StorageType.Empty; - } - else - { - return ValueUtilsSmi.SqlDbTypeToStorageType(valueMetaData.SqlDbType); - } - } - - public override int GetValues(object[] values) - { - EnsureCanGetCol(0); - if (values == null) - { - throw ADP.ArgumentNull(nameof(values)); - } - - int copyLength = (values.Length < _visibleColumnCount) ? values.Length : _visibleColumnCount; - for (int i = 0; i < copyLength; i++) - { - values[_indexMap[i]] = GetValue(i); - } - return copyLength; - } - - public override int GetOrdinal(string name) - { - EnsureCanGetMetaData(); - if (_fieldNameLookup == null) - { - _fieldNameLookup = new FieldNameLookup((IDataReader)this, -1); // TODO: Need to support DefaultLCID for name comparisons - } - return _fieldNameLookup.GetOrdinal(name); // MDAC 71470 - } - - // Generic array access by column index (accesses column value) - public override object this[int ordinal] => GetValue(ordinal); - - // Generic array access by column name (accesses column value) - public override object this[string strName] => GetValue(GetOrdinal(strName)); - - // - // IDataRecord Data Access methods - // - public override bool IsDBNull(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.IsDBNull(_readerEventSink, _currentColumnValuesV3, ordinal); - } - - public override Task IsDBNullAsync(int ordinal, CancellationToken cancellationToken) - { - // As per Async spec, Context Connections do not support async - return ADP.CreatedTaskWithException(ADP.ExceptionWithStackTrace(SQL.NotAvailableOnContextConnection())); - } - - public override bool GetBoolean(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetBoolean(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override byte GetByte(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetByte(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override long GetBytes(int ordinal, long fieldOffset, byte[] buffer, int bufferOffset, int length) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetBytes(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], fieldOffset, buffer, bufferOffset, length, true); - } - - // XmlReader support code calls this method. - internal override long GetBytesInternal(int ordinal, long fieldOffset, byte[] buffer, int bufferOffset, int length) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetBytesInternal(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], fieldOffset, buffer, bufferOffset, length, false); - } - - public override char GetChar(int ordinal) => throw ADP.NotSupported(); - - public override long GetChars(int ordinal, long fieldOffset, char[] buffer, int bufferOffset, int length) - { - EnsureCanGetCol(ordinal); - SmiExtendedMetaData metaData = _currentMetaData[ordinal]; - if (IsCommandBehavior(CommandBehavior.SequentialAccess)) - { - if (metaData.SqlDbType == SqlDbType.Xml) - { - return GetStreamingXmlChars(ordinal, fieldOffset, buffer, bufferOffset, length); - } - } - return ValueUtilsSmi.GetChars(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, fieldOffset, buffer, bufferOffset, length); - } - - public override Guid GetGuid(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetGuid(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override short GetInt16(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetInt16(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override int GetInt32(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetInt32(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override long GetInt64(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetInt64(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override float GetFloat(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSingle(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override double GetDouble(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetDouble(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override string GetString(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetString(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override decimal GetDecimal(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetDecimal(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override DateTime GetDateTime(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetDateTime(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - // - // IDataReader properties - // - // Logically closed test. I.e. is this object closed as far as external access is concerned? - public override bool IsClosed => IsReallyClosed(); - - public override int RecordsAffected => Command.InternalRecordsAffected; - - // - // IDataReader methods - // - internal override void CloseReaderFromConnection() - { - // Context Connections do not support async - so there is no threading issues with closing from the connection - CloseInternal(closeConnection: false); - } - - public override void Close() - { - // Connection should be open at this point, so we can do multiple checks of HasEvents, and we may need to close the connection afterwards - CloseInternal(closeConnection: IsCommandBehavior(CommandBehavior.CloseConnection)); - } - - private void CloseInternal(bool closeConnection) - { - using (TryEventScope.Create(" {0}", ObjectID)) - { - bool processFinallyBlock = true; - try - { - if (!IsClosed) - { - _hasRows = false; - - // Process the remaining events. This makes sure that environment changes are applied and any errors are picked up. - while (_eventStream.HasEvents) - { - _eventStream.ProcessEvent(_readerEventSink); - _readerEventSink.ProcessMessagesAndThrow(true); - } - - // Close the request executor - _requestExecutor.Close(_readerEventSink); - _readerEventSink.ProcessMessagesAndThrow(true); - } - } - catch (Exception e) - { - processFinallyBlock = ADP.IsCatchableExceptionType(e); - throw; - } - finally - { - if (processFinallyBlock) - { - _isOpen = false; - - if ((closeConnection) && (Connection != null)) - { - Connection.Close(); - } - } - } - } - } - - // Move to the next resultset - public override unsafe bool NextResult() - { - ThrowIfClosed(); - - bool hasAnotherResult = InternalNextResult(false); - - return hasAnotherResult; - } - - public override Task NextResultAsync(CancellationToken cancellationToken) - { - // Async not supported on Context Connections - return ADP.CreatedTaskWithException(ADP.ExceptionWithStackTrace(SQL.NotAvailableOnContextConnection())); - } - - internal unsafe bool InternalNextResult(bool ignoreNonFatalMessages) - { - long scopeID = SqlClientEventSource.Log.TryAdvancedScopeEnterEvent(" {0}", ObjectID); - try - { - _hasRows = false; - - if (PositionState.AfterResults != _currentPosition) - { - // Consume any remaning rows in the current result. - - while (InternalRead(ignoreNonFatalMessages)) - { - // This space intentionally left blank - } - - // reset resultset metadata - it will be created again if there is a pending resultset - ResetResultSet(); - - // Process the events until metadata is found or all of the - // available events have been consumed. If there is another - // result, the metadata for it will be available after the last - // read on the prior result. - - while (_currentMetaData == null && _eventStream.HasEvents) - { - _eventStream.ProcessEvent(_readerEventSink); - _readerEventSink.ProcessMessagesAndThrow(ignoreNonFatalMessages); - } - } - - return PositionState.AfterResults != _currentPosition; - } - finally - { - SqlClientEventSource.Log.TryAdvanceScopeLeave(scopeID); - } - } - - public override bool Read() - { - ThrowIfClosed(); - bool hasAnotherRow = InternalRead(false); - - return hasAnotherRow; - } - - public override Task ReadAsync(CancellationToken cancellationToken) - { - // Async not supported on Context Connections - return ADP.CreatedTaskWithException(ADP.ExceptionWithStackTrace(SQL.NotAvailableOnContextConnection())); - } - - internal unsafe bool InternalRead(bool ignoreNonFatalErrors) - { - long scopeID = SqlClientEventSource.Log.TryAdvancedScopeEnterEvent(" {0}", ObjectID); - try - { - // Don't move unless currently in results. - if (FInResults()) - { - - // Set current row to null so we can see if we get a new one - _currentColumnValues = null; - _currentColumnValuesV3 = null; - - // Reset blobs - if (_currentStream != null) - { - _currentStream.SetClosed(); - _currentStream = null; - } - if (_currentTextReader != null) - { - _currentTextReader.SetClosed(); - _currentTextReader = null; - } - - // NOTE: SQLBUDT #386118 -- may indicate that we want to break this loop when we get a MessagePosted callback, but we can't prove that. - while (_currentColumnValues == null && // Did we find a row? - _currentColumnValuesV3 == null && // Did we find a V3 row? - FInResults() && // Was the batch terminated due to a serious error? - PositionState.AfterRows != _currentPosition && // Have we seen a statement completed event? - _eventStream.HasEvents) - { // Have we processed all events? - _eventStream.ProcessEvent(_readerEventSink); - _readerEventSink.ProcessMessagesAndThrow(ignoreNonFatalErrors); - } - } - - return PositionState.OnRow == _currentPosition; - } - finally - { - SqlClientEventSource.Log.TryAdvanceScopeLeave(scopeID); - } - } - - public override DataTable GetSchemaTable() - { - ThrowIfClosed(); - - if (_schemaTable == null && FInResults()) - { - - DataTable schemaTable = new DataTable("SchemaTable") - { - Locale = System.Globalization.CultureInfo.InvariantCulture, - MinimumCapacity = InternalFieldCount - }; - - DataColumn ColumnName = new DataColumn(SchemaTableColumn.ColumnName, typeof(string)); - DataColumn Ordinal = new DataColumn(SchemaTableColumn.ColumnOrdinal, typeof(int)); - DataColumn Size = new DataColumn(SchemaTableColumn.ColumnSize, typeof(int)); - DataColumn Precision = new DataColumn(SchemaTableColumn.NumericPrecision, typeof(short)); - DataColumn Scale = new DataColumn(SchemaTableColumn.NumericScale, typeof(short)); - - DataColumn DataType = new DataColumn(SchemaTableColumn.DataType, typeof(Type)); - DataColumn ProviderSpecificDataType = new DataColumn(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type)); - DataColumn ProviderType = new DataColumn(SchemaTableColumn.ProviderType, typeof(int)); - DataColumn NonVersionedProviderType = new DataColumn(SchemaTableColumn.NonVersionedProviderType, typeof(int)); - - DataColumn IsLong = new DataColumn(SchemaTableColumn.IsLong, typeof(bool)); - DataColumn AllowDBNull = new DataColumn(SchemaTableColumn.AllowDBNull, typeof(bool)); - DataColumn IsReadOnly = new DataColumn(SchemaTableOptionalColumn.IsReadOnly, typeof(bool)); - DataColumn IsRowVersion = new DataColumn(SchemaTableOptionalColumn.IsRowVersion, typeof(bool)); - - DataColumn IsUnique = new DataColumn(SchemaTableColumn.IsUnique, typeof(bool)); - DataColumn IsKey = new DataColumn(SchemaTableColumn.IsKey, typeof(bool)); - DataColumn IsAutoIncrement = new DataColumn(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool)); - DataColumn IsHidden = new DataColumn(SchemaTableOptionalColumn.IsHidden, typeof(bool)); - - DataColumn BaseCatalogName = new DataColumn(SchemaTableOptionalColumn.BaseCatalogName, typeof(string)); - DataColumn BaseSchemaName = new DataColumn(SchemaTableColumn.BaseSchemaName, typeof(string)); - DataColumn BaseTableName = new DataColumn(SchemaTableColumn.BaseTableName, typeof(string)); - DataColumn BaseColumnName = new DataColumn(SchemaTableColumn.BaseColumnName, typeof(string)); - - // unique to SqlClient - DataColumn BaseServerName = new DataColumn(SchemaTableOptionalColumn.BaseServerName, typeof(string)); - DataColumn IsAliased = new DataColumn(SchemaTableColumn.IsAliased, typeof(bool)); - DataColumn IsExpression = new DataColumn(SchemaTableColumn.IsExpression, typeof(bool)); - DataColumn IsIdentity = new DataColumn("IsIdentity", typeof(bool)); - // UDT specific. Holds UDT typename ONLY if the type of the column is UDT, otherwise the data type - DataColumn DataTypeName = new DataColumn("DataTypeName", typeof(string)); - DataColumn UdtAssemblyQualifiedName = new DataColumn("UdtAssemblyQualifiedName", typeof(string)); - // Xml metadata specific - DataColumn XmlSchemaCollectionDatabase = new DataColumn("XmlSchemaCollectionDatabase", typeof(string)); - DataColumn XmlSchemaCollectionOwningSchema = new DataColumn("XmlSchemaCollectionOwningSchema", typeof(string)); - DataColumn XmlSchemaCollectionName = new DataColumn("XmlSchemaCollectionName", typeof(string)); - // SparseColumnSet - DataColumn IsColumnSet = new DataColumn("IsColumnSet", typeof(bool)); - - Ordinal.DefaultValue = 0; - IsLong.DefaultValue = false; - - DataColumnCollection columns = schemaTable.Columns; - - // must maintain order for backward compatibility - columns.Add(ColumnName); - columns.Add(Ordinal); - columns.Add(Size); - columns.Add(Precision); - columns.Add(Scale); - columns.Add(IsUnique); - columns.Add(IsKey); - columns.Add(BaseServerName); - columns.Add(BaseCatalogName); - columns.Add(BaseColumnName); - columns.Add(BaseSchemaName); - columns.Add(BaseTableName); - columns.Add(DataType); - columns.Add(AllowDBNull); - columns.Add(ProviderType); - columns.Add(IsAliased); - columns.Add(IsExpression); - columns.Add(IsIdentity); - columns.Add(IsAutoIncrement); - columns.Add(IsRowVersion); - columns.Add(IsHidden); - columns.Add(IsLong); - columns.Add(IsReadOnly); - columns.Add(ProviderSpecificDataType); - columns.Add(DataTypeName); - columns.Add(XmlSchemaCollectionDatabase); - columns.Add(XmlSchemaCollectionOwningSchema); - columns.Add(XmlSchemaCollectionName); - columns.Add(UdtAssemblyQualifiedName); - columns.Add(NonVersionedProviderType); - columns.Add(IsColumnSet); - - for (int i = 0; i < InternalFieldCount; i++) - { - SmiQueryMetaData colMetaData = _currentMetaData[i]; - - long maxLength = colMetaData.MaxLength; - - MetaType metaType = MetaType.GetMetaTypeFromSqlDbType(colMetaData.SqlDbType, colMetaData.IsMultiValued); - if (SmiMetaData.UnlimitedMaxLengthIndicator == maxLength) - { - metaType = MetaType.GetMaxMetaTypeFromMetaType(metaType); - maxLength = (metaType.IsSizeInCharacters && !metaType.IsPlp) ? (0x7fffffff / 2) : 0x7fffffff; - } - - DataRow schemaRow = schemaTable.NewRow(); - - // NOTE: there is an impedence mismatch here - the server always - // treats numeric data as variable length and sends a maxLength - // based upon the precision, whereas TDS always sends 17 for - // the max length; rather than push this logic into the server, - // I've elected to make a fixup here instead. - if (SqlDbType.Decimal == colMetaData.SqlDbType) - { - // TODO: Consider moving this into SmiMetaData itself... - maxLength = TdsEnums.MAX_NUMERIC_LEN; // SQLBUDT 339686 - } - else if (SqlDbType.Variant == colMetaData.SqlDbType) - { - // TODO: Consider moving this into SmiMetaData itself... - maxLength = 8009; // SQLBUDT 340726 - } - - schemaRow[ColumnName] = colMetaData.Name; - schemaRow[Ordinal] = i; - schemaRow[Size] = maxLength; - - schemaRow[ProviderType] = (int)colMetaData.SqlDbType; // SqlDbType - schemaRow[NonVersionedProviderType] = (int)colMetaData.SqlDbType; // SqlDbType - - if (colMetaData.SqlDbType != SqlDbType.Udt) - { - schemaRow[DataType] = metaType.ClassType; // com+ type - schemaRow[ProviderSpecificDataType] = metaType.SqlType; - } - else - { - schemaRow[UdtAssemblyQualifiedName] = colMetaData.Type.AssemblyQualifiedName; - schemaRow[DataType] = colMetaData.Type; - schemaRow[ProviderSpecificDataType] = colMetaData.Type; - } - - // NOTE: there is also an impedence mismatch here - the server - // has different ideas about what the precision value should be - // than does the client bits. I tried fixing up the default - // meta data values in SmiMetaData, however, it caused the - // server suites to fall over dead. Rather than attempt to - // bake it into the server, I'm fixing it up in the client. - byte precision; // default for everything, except certain numeric types. - - // TODO: Consider moving this into SmiMetaData itself... - switch (colMetaData.SqlDbType) - { - case SqlDbType.BigInt: - case SqlDbType.DateTime: - case SqlDbType.Decimal: - case SqlDbType.Int: - case SqlDbType.Money: - case SqlDbType.SmallDateTime: - case SqlDbType.SmallInt: - case SqlDbType.SmallMoney: - case SqlDbType.TinyInt: - precision = colMetaData.Precision; - break; - case SqlDbType.Float: - precision = 15; - break; - case SqlDbType.Real: - precision = 7; - break; - default: - precision = 0xff; // everything else is unknown; - break; - } - - schemaRow[Precision] = precision; - - // TODO: Consider moving this to a utitlity class if we end up with a bunch more of this stuff... - if (SqlDbType.Decimal == colMetaData.SqlDbType || - SqlDbType.Time == colMetaData.SqlDbType || - SqlDbType.DateTime2 == colMetaData.SqlDbType || - SqlDbType.DateTimeOffset == colMetaData.SqlDbType) - { - schemaRow[Scale] = colMetaData.Scale; - } - else - { - schemaRow[Scale] = MetaType.GetMetaTypeFromSqlDbType(colMetaData.SqlDbType, colMetaData.IsMultiValued).Scale; - } - - schemaRow[AllowDBNull] = colMetaData.AllowsDBNull; - if (!(colMetaData.IsAliased.IsNull)) - { - schemaRow[IsAliased] = colMetaData.IsAliased.Value; - } - - if (!(colMetaData.IsKey.IsNull)) - { - schemaRow[IsKey] = colMetaData.IsKey.Value; - } - - if (!(colMetaData.IsHidden.IsNull)) - { - schemaRow[IsHidden] = colMetaData.IsHidden.Value; - } - - if (!(colMetaData.IsExpression.IsNull)) - { - schemaRow[IsExpression] = colMetaData.IsExpression.Value; - } - - schemaRow[IsReadOnly] = colMetaData.IsReadOnly; - schemaRow[IsIdentity] = colMetaData.IsIdentity; - schemaRow[IsColumnSet] = colMetaData.IsColumnSet; - schemaRow[IsAutoIncrement] = colMetaData.IsIdentity; - schemaRow[IsLong] = metaType.IsLong; - - // mark unique for timestamp columns - if (SqlDbType.Timestamp == colMetaData.SqlDbType) - { - schemaRow[IsUnique] = true; - schemaRow[IsRowVersion] = true; - } - else - { - schemaRow[IsUnique] = false; - schemaRow[IsRowVersion] = false; - } - - if (!string.IsNullOrEmpty(colMetaData.ColumnName)) - { - schemaRow[BaseColumnName] = colMetaData.ColumnName; - } - else if (!string.IsNullOrEmpty(colMetaData.Name)) - { - // Use projection name if base column name is not present - schemaRow[BaseColumnName] = colMetaData.Name; - } - - if (!string.IsNullOrEmpty(colMetaData.TableName)) - { - schemaRow[BaseTableName] = colMetaData.TableName; - } - - if (!string.IsNullOrEmpty(colMetaData.SchemaName)) - { - schemaRow[BaseSchemaName] = colMetaData.SchemaName; - } - - if (!string.IsNullOrEmpty(colMetaData.CatalogName)) - { - schemaRow[BaseCatalogName] = colMetaData.CatalogName; - } - - if (!string.IsNullOrEmpty(colMetaData.ServerName)) - { - schemaRow[BaseServerName] = colMetaData.ServerName; - } - - if (SqlDbType.Udt == colMetaData.SqlDbType) - { - schemaRow[DataTypeName] = colMetaData.TypeSpecificNamePart1 + "." + colMetaData.TypeSpecificNamePart2 + "." + colMetaData.TypeSpecificNamePart3; - } - else - { - schemaRow[DataTypeName] = metaType.TypeName; - } - - // Add Xml metadata - if (SqlDbType.Xml == colMetaData.SqlDbType) - { - schemaRow[XmlSchemaCollectionDatabase] = colMetaData.TypeSpecificNamePart1; - schemaRow[XmlSchemaCollectionOwningSchema] = colMetaData.TypeSpecificNamePart2; - schemaRow[XmlSchemaCollectionName] = colMetaData.TypeSpecificNamePart3; - } - - schemaTable.Rows.Add(schemaRow); - schemaRow.AcceptChanges(); - } - - // mark all columns as readonly - foreach (DataColumn column in columns) - { - column.ReadOnly = true; // MDAC 70943 - } - - _schemaTable = schemaTable; - } - - return _schemaTable; - } - - // - // ISqlRecord methods - // - public override SqlBinary GetSqlBinary(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlBinary(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlBoolean GetSqlBoolean(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlBoolean(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlByte GetSqlByte(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlByte(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlInt16 GetSqlInt16(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlInt16(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlInt32 GetSqlInt32(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlInt32(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlInt64 GetSqlInt64(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlInt64(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlSingle GetSqlSingle(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlSingle(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlDouble GetSqlDouble(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlDouble(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlMoney GetSqlMoney(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlMoney(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlDateTime GetSqlDateTime(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlDateTime(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - - public override SqlDecimal GetSqlDecimal(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlDecimal(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlString GetSqlString(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlString(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlGuid GetSqlGuid(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlGuid(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); - } - - public override SqlChars GetSqlChars(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlChars(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.InternalContext); - } - - public override SqlBytes GetSqlBytes(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlBytes(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.InternalContext); - } - - public override SqlXml GetSqlXml(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetSqlXml(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.InternalContext); - } - - public override TimeSpan GetTimeSpan(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetTimeSpan(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.Is2008OrNewer); - } - - public override DateTimeOffset GetDateTimeOffset(int ordinal) - { - EnsureCanGetCol(ordinal); - return ValueUtilsSmi.GetDateTimeOffset(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.Is2008OrNewer); - } - - public override object GetSqlValue(int ordinal) - { - EnsureCanGetCol(ordinal); - - SmiMetaData metaData = _currentMetaData[ordinal]; - if (_currentConnection.Is2008OrNewer) - { - return ValueUtilsSmi.GetSqlValue200(_readerEventSink, (SmiTypedGetterSetter)_currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); - } - return ValueUtilsSmi.GetSqlValue(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); - ; - } - - public override int GetSqlValues(object[] values) - { - EnsureCanGetCol(0); - - if (values == null) - { - throw ADP.ArgumentNull(nameof(values)); - } - - int copyLength = (values.Length < _visibleColumnCount) ? values.Length : _visibleColumnCount; - for (int i = 0; i < copyLength; i++) - { - values[_indexMap[i]] = GetSqlValue(i); - } - - return copyLength; - } - - // - // ISqlReader methods/properties - // - public override bool HasRows - { - get { return _hasRows; } - } - - // - // SqlDataReader method/properties - // - public override Stream GetStream(int ordinal) - { - EnsureCanGetCol(ordinal); - - SmiQueryMetaData metaData = _currentMetaData[ordinal]; - - // For non-null, non-variant types with sequential access, we support proper streaming - if ((metaData.SqlDbType != SqlDbType.Variant) && (IsCommandBehavior(CommandBehavior.SequentialAccess)) && (!ValueUtilsSmi.IsDBNull(_readerEventSink, _currentColumnValuesV3, ordinal))) - { - if (HasActiveStreamOrTextReaderOnColumn(ordinal)) - { - throw ADP.NonSequentialColumnAccess(ordinal, ordinal + 1); - } - _currentStream = ValueUtilsSmi.GetSequentialStream(_readerEventSink, _currentColumnValuesV3, ordinal, metaData); - return _currentStream; - } - else - { - return ValueUtilsSmi.GetStream(_readerEventSink, _currentColumnValuesV3, ordinal, metaData); - } - } - - public override TextReader GetTextReader(int ordinal) - { - EnsureCanGetCol(ordinal); - - SmiQueryMetaData metaData = _currentMetaData[ordinal]; - - // For non-variant types with sequential access, we support proper streaming - if ((metaData.SqlDbType != SqlDbType.Variant) && (IsCommandBehavior(CommandBehavior.SequentialAccess)) && (!ValueUtilsSmi.IsDBNull(_readerEventSink, _currentColumnValuesV3, ordinal))) - { - if (HasActiveStreamOrTextReaderOnColumn(ordinal)) - { - throw ADP.NonSequentialColumnAccess(ordinal, ordinal + 1); - } - _currentTextReader = ValueUtilsSmi.GetSequentialTextReader(_readerEventSink, _currentColumnValuesV3, ordinal, metaData); - return _currentTextReader; - } - else - { - return ValueUtilsSmi.GetTextReader(_readerEventSink, _currentColumnValuesV3, ordinal, metaData); - } - } - - public override XmlReader GetXmlReader(int ordinal) - { - // NOTE: sql_variant can not contain a XML data type: http://msdn.microsoft.com/en-us/library/ms173829.aspx - - EnsureCanGetCol(ordinal); - if (_currentMetaData[ordinal].SqlDbType != SqlDbType.Xml) - { - throw ADP.InvalidCast(); - } - - Stream stream; - if ((IsCommandBehavior(CommandBehavior.SequentialAccess)) && (!ValueUtilsSmi.IsDBNull(_readerEventSink, _currentColumnValuesV3, ordinal))) - { - if (HasActiveStreamOrTextReaderOnColumn(ordinal)) - { - throw ADP.NonSequentialColumnAccess(ordinal, ordinal + 1); - } - // Need to bypass the type check since streams are not usually allowed on XML types - _currentStream = ValueUtilsSmi.GetSequentialStream(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], bypassTypeCheck: true); - stream = _currentStream; - } - else - { - stream = ValueUtilsSmi.GetStream(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], bypassTypeCheck: true); - } - - return SqlTypeWorkarounds.SqlXmlCreateSqlXmlReader(stream, closeInput: false, async: false); - } - - // - // Internal reader state - // - - // Logical state of reader/resultset as viewed by the client - // Does not necessarily match up with server state. - internal enum PositionState - { - BeforeResults, // Before all resultset in request - BeforeRows, // Before all rows in current resultset - OnRow, // On a valid row in the current resultset - AfterRows, // After all rows in current resultset - AfterResults // After all resultsets in request - } - - private PositionState _currentPosition; // Where is the reader relative to incoming results? - private bool _isOpen; // Is the reader open? - private SmiQueryMetaData[] _currentMetaData; // Metadata for current resultset - private int[] _indexMap; // map of indices for visible column - private int _visibleColumnCount; // number of visible columns - private DataTable _schemaTable; // Cache of user-visible extended metadata while in results. - private ITypedGetters _currentColumnValues; // Unmanaged-managed data marshalers/cache - private ITypedGettersV3 _currentColumnValuesV3; // Unmanaged-managed data marshalers/cache for SMI V3 - private bool _hasRows; // Are there any rows in the current resultset? Must be able to say before moving to first row. - private SmiEventStream _eventStream; // The event buffer that receives the events from the execution engine. - private SmiRequestExecutor _requestExecutor; // The used to request actions from the execution engine. - private SqlInternalConnectionSmi _currentConnection; - private ReaderEventSink _readerEventSink; // The event sink that will process events from the event buffer. - private FieldNameLookup _fieldNameLookup; // cached lookup object to improve access time based on field name - private SqlSequentialStreamSmi _currentStream; // The stream on the current column (if any) - private SqlSequentialTextReaderSmi _currentTextReader; // The text reader on the current column (if any) - - // Assumes that if there were any results, the first chunk of them are in the data stream - // (up to the first actual row or the end of the resultsets). - unsafe internal SqlDataReaderSmi( - SmiEventStream eventStream, // the event stream that receives the events from the execution engine - SqlCommand parent, // command that owns reader - CommandBehavior behavior, // behavior specified for this execution - SqlInternalConnectionSmi connection, // connection that owns everybody - SmiEventSink parentSink, // Event sink of parent command - SmiRequestExecutor requestExecutor - ) : base(parent, behavior) - { // UNDONE: handle other command behaviors - _eventStream = eventStream; - _currentConnection = connection; - _readerEventSink = new ReaderEventSink(this, parentSink); - _currentPosition = PositionState.BeforeResults; - _isOpen = true; - _indexMap = null; - _visibleColumnCount = 0; - _currentStream = null; - _currentTextReader = null; - _requestExecutor = requestExecutor; - } - - internal override SmiExtendedMetaData[] GetInternalSmiMetaData() - { - if (_currentMetaData == null || _visibleColumnCount == InternalFieldCount) - { - return _currentMetaData; - } - else - { -#if DEBUG - // DEVNOTE: Interpretation of returned array currently depends on hidden columns - // always appearing at the end, since there currently is no access to the index map - // outside of this class. In Debug code, we check this assumption. - bool sawHiddenColumn = false; -#endif - SmiExtendedMetaData[] visibleMetaData = new SmiExtendedMetaData[_visibleColumnCount]; - for (int i = 0; i < _visibleColumnCount; i++) - { -#if DEBUG - if (_currentMetaData[_indexMap[i]].IsHidden.IsTrue) - { - sawHiddenColumn = true; - } - else - { - Debug.Assert(!sawHiddenColumn); - } -#endif - visibleMetaData[i] = _currentMetaData[_indexMap[i]]; - } - - return visibleMetaData; - } - } - - internal override int GetLocaleId(int ordinal) - { - EnsureCanGetMetaData(); - return (int)_currentMetaData[ordinal].LocaleId; - } - private int InternalFieldCount - { - get - { - if (FNotInResults()) - { - return 0; - } - else - { - return _currentMetaData.Length; - } - } - } - - // Have we cleaned up internal resources? - private bool IsReallyClosed() => !_isOpen; - - // Central checkpoint for closed recordset. - // Any code that requires an open recordset should call this method first! - // Especially any code that accesses unmanaged memory structures whose lifetime - // matches the lifetime of the unmanaged recordset. - internal void ThrowIfClosed([CallerMemberName] string operationName = null) - { - if (IsClosed) - { - throw ADP.DataReaderClosed(operationName); - } - } - - // Central checkpoint to ensure the requested column can be accessed. - // Calling this function serves to notify that it has been accessed by the user. - private void EnsureCanGetCol(int ordinal, [CallerMemberName] string operationName = null) - { - EnsureOnRow(operationName); - } - - internal void EnsureOnRow(string operationName) - { - ThrowIfClosed(operationName); - if (_currentPosition != PositionState.OnRow) - { - throw SQL.InvalidRead(); - } - } - - internal void EnsureCanGetMetaData([CallerMemberName] string operationName = null) - { - ThrowIfClosed(operationName); - if (FNotInResults()) - { - throw SQL.InvalidRead(); // UNDONE: Shouldn't this be a bit more descriptive? - } - } - - private bool FInResults() - { - return !FNotInResults(); - } - - private bool FNotInResults() - { - return (PositionState.AfterResults == _currentPosition || PositionState.BeforeResults == _currentPosition); - } - - private void MetaDataAvailable(SmiQueryMetaData[] md, bool nextEventIsRow) - { - Debug.Assert(_currentPosition != PositionState.AfterResults); - - _currentMetaData = md; - _hasRows = nextEventIsRow; - _fieldNameLookup = null; - _schemaTable = null; // will be rebuilt based on new metadata - _currentPosition = PositionState.BeforeRows; - - // calculate visible column indices - _indexMap = new int[_currentMetaData.Length]; - int i; - int visibleCount = 0; - for (i = 0; i < _currentMetaData.Length; i++) - { - if (!_currentMetaData[i].IsHidden.IsTrue) - { - _indexMap[visibleCount] = i; - visibleCount++; - } - } - _visibleColumnCount = visibleCount; - } - - private bool HasActiveStreamOrTextReaderOnColumn(int columnIndex) - { - bool active = false; - - active |= (_currentStream != null) && (_currentStream.ColumnIndex == columnIndex); - active |= (_currentTextReader != null) && (_currentTextReader.ColumnIndex == columnIndex); - - return active; - } - - // Obsolete V2- method - private void RowAvailable(ITypedGetters row) - { - Debug.Assert(_currentPosition != PositionState.AfterResults); - - _currentColumnValues = row; - _currentPosition = PositionState.OnRow; - } - - private void RowAvailable(ITypedGettersV3 row) - { - Debug.Assert(_currentPosition != PositionState.AfterResults); - - _currentColumnValuesV3 = row; - _currentPosition = PositionState.OnRow; - } - - private void StatementCompleted() - { - Debug.Assert(_currentPosition != PositionState.AfterResults); - - _currentPosition = PositionState.AfterRows; - } - - private void ResetResultSet() - { - _currentMetaData = null; - _visibleColumnCount = 0; - _schemaTable = null; - } - - private void BatchCompleted() - { - Debug.Assert(_currentPosition != PositionState.AfterResults); - - ResetResultSet(); - - _currentPosition = PositionState.AfterResults; - _eventStream.Close(_readerEventSink); - } - - // An implementation of the IEventSink interface that either performs - // the required enviornment changes or forwards the events on to the - // corresponding reader instance. Having the event sink be a separate - // class keeps the IEventSink methods out of SqlDataReader's inteface. - - private sealed class ReaderEventSink : SmiEventSink_Default - { - private readonly SqlDataReaderSmi _reader; - - internal ReaderEventSink(SqlDataReaderSmi reader, SmiEventSink parent) - : base(parent) - { - _reader = reader; - } - - internal override void MetaDataAvailable(SmiQueryMetaData[] md, bool nextEventIsRow) - { - var mdLength = (md != null) ? md.Length : -1; - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, md.Length={1} nextEventIsRow={2}.", _reader.ObjectID, mdLength, nextEventIsRow); - - if (SqlClientEventSource.Log.IsAdvancedTraceOn()) - { - if (md != null) - { - for (int i = 0; i < md.Length; i++) - { - SqlClientEventSource.Log.TraceEvent(" {0}, metaData[{1}] is {2}{3}", _reader.ObjectID, i, md[i].GetType(), md[i].TraceString()); - } - } - } - _reader.MetaDataAvailable(md, nextEventIsRow); - } - - // Obsolete V2- method - internal override void RowAvailable(ITypedGetters row) - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} (v2).", _reader.ObjectID); - _reader.RowAvailable(row); - } - - internal override void RowAvailable(ITypedGettersV3 row) - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} (ITypedGettersV3).", _reader.ObjectID); - _reader.RowAvailable(row); - } - - internal override void RowAvailable(SmiTypedGetterSetter rowData) - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} (SmiTypedGetterSetter).", _reader.ObjectID); - _reader.RowAvailable(rowData); - } - - internal override void StatementCompleted(int recordsAffected) - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} recordsAffected= {1}.", _reader.ObjectID, recordsAffected); - - // devnote: relies on SmiEventSink_Default to pass event to parent - // Both command and reader care about StatementCompleted, but for different reasons. - base.StatementCompleted(recordsAffected); - _reader.StatementCompleted(); - } - - internal override void BatchCompleted() - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}.", _reader.ObjectID); - - // devnote: relies on SmiEventSink_Default to pass event to parent - // parent's callback *MUST* come before reader's BatchCompleted, since - // reader will close the event stream during this call, and parent wants - // to extract parameter values before that happens. - base.BatchCompleted(); - _reader.BatchCompleted(); - } - } - - } -} - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlSequentialStreamSmi.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlSequentialStreamSmi.cs deleted file mode 100644 index 9705d32abc..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlSequentialStreamSmi.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using Microsoft.Data.Common; -using Microsoft.Data.SqlClient.Server; - -namespace Microsoft.Data.SqlClient -{ - sealed internal class SqlSequentialStreamSmi : System.IO.Stream - { - private SmiEventSink_Default _sink; - private ITypedGettersV3 _getters; - private int _columnIndex; // The index of out column in the table - private long _position; // Current position in the stream - private long _length; // Total length of the stream - - internal SqlSequentialStreamSmi(SmiEventSink_Default sink, ITypedGettersV3 getters, int columnIndex, long length) - { - _sink = sink; - _getters = getters; - _columnIndex = columnIndex; - _length = length; - _position = 0; - } - - public override bool CanRead - { - get { return ((_sink != null) && (_getters != null)); } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { } - - public override long Length - { - get { throw ADP.NotSupported(); } - } - - public override long Position - { - get { throw ADP.NotSupported(); } - set { throw ADP.NotSupported(); } - } - - internal int ColumnIndex - { - get { return _columnIndex; } - } - - public override int Read(byte[] buffer, int offset, int count) - { - SqlSequentialStream.ValidateReadParameters(buffer, offset, count); - if (!CanRead) - { - throw ADP.ObjectDisposed(this); - } - - try - { - // Read whichever is less: however much the user asked for, or however much we have - // NOTE: It is safe to do this since count <= Int32.MaxValue, therefore the Math.Min should always result in an int - int bytesNeeded = (int)Math.Min((long)count, _length - _position); - int bytesRead = 0; - if (bytesNeeded > 0) - { - bytesRead = ValueUtilsSmi.GetBytes_Unchecked(_sink, _getters, _columnIndex, _position, buffer, offset, bytesNeeded); - _position += bytesRead; - } - return bytesRead; - } - catch (SqlException ex) - { - // Stream.Read() can't throw a SqlException - so wrap it in an IOException - throw ADP.ErrorReadingFromStream(ex); - } - } - - public override long Seek(long offset, System.IO.SeekOrigin origin) - { - throw ADP.NotSupported(); - } - - public override void SetLength(long value) - { - throw ADP.NotSupported(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw ADP.NotSupported(); - } - - /// - /// Forces the stream to act as if it was closed (i.e. CanRead=false and Read() throws) - /// This does not actually close the stream, read off the rest of the data or dispose this - /// - internal void SetClosed() - { - _sink = null; - _getters = null; - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - SetClosed(); - } - - base.Dispose(disposing); - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlSequentialTextReaderSmi.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlSequentialTextReaderSmi.cs deleted file mode 100644 index 7adbb67f21..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlSequentialTextReaderSmi.cs +++ /dev/null @@ -1,137 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics; -using Microsoft.Data.Common; -using Microsoft.Data.SqlClient.Server; - -namespace Microsoft.Data.SqlClient -{ - sealed internal class SqlSequentialTextReaderSmi : System.IO.TextReader - { - private SmiEventSink_Default _sink; - private ITypedGettersV3 _getters; - private int _columnIndex; // The index of out column in the table - private long _position; // Current position in the stream - private long _length; // Total length of the stream - private int _peekedChar; // Current peeked character (if any) - - internal SqlSequentialTextReaderSmi(SmiEventSink_Default sink, ITypedGettersV3 getters, int columnIndex, long length) - { - _sink = sink; - _getters = getters; - _columnIndex = columnIndex; - _length = length; - _position = 0; - _peekedChar = -1; - } - - internal int ColumnIndex - { - get { return _columnIndex; } - } - - public override int Peek() - { - if (!HasPeekedChar) - { - _peekedChar = Read(); - } - - Debug.Assert(_peekedChar == -1 || ((_peekedChar >= char.MinValue) && (_peekedChar <= char.MaxValue)), string.Format("Bad peeked character: {0}", _peekedChar)); - return _peekedChar; - } - - public override int Read() - { - if (IsClosed) - { - throw ADP.ObjectDisposed(this); - } - - int readChar = -1; - - // If there is already a peeked char, then return it - if (HasPeekedChar) - { - readChar = _peekedChar; - _peekedChar = -1; - } - // If there is data available try to read a char - else if (_position < _length) - { - char[] tempBuffer = new char[1]; - int charsRead = ValueUtilsSmi.GetChars_Unchecked(_sink, _getters, _columnIndex, _position, tempBuffer, 0, 1); - if (charsRead == 1) - { - readChar = tempBuffer[0]; - _position++; - } - } - - Debug.Assert(readChar == -1 || ((readChar >= char.MinValue) && (readChar <= char.MaxValue)), string.Format("Bad read character: {0}", readChar)); - return readChar; - } - - public override int Read(char[] buffer, int index, int count) - { - SqlSequentialTextReader.ValidateReadParameters(buffer, index, count); - if (IsClosed) - { - throw ADP.ObjectDisposed(this); - } - - int charsRead = 0; - // Load in peeked char - if ((count > 0) && (HasPeekedChar)) - { - Debug.Assert((_peekedChar >= char.MinValue) && (_peekedChar <= char.MaxValue), string.Format("Bad peeked character: {0}", _peekedChar)); - buffer[index + charsRead] = (char)_peekedChar; - charsRead++; - _peekedChar = -1; - } - - // Read whichever is less: however much the user asked for, or however much we have - // NOTE: It is safe to do this since count <= Int32.MaxValue, therefore the Math.Min should always result in an int - int charsNeeded = (int)Math.Min((long)(count - charsRead), _length - _position); - // If we need more data and there is data avaiable, read - if (charsNeeded > 0) - { - int newCharsRead = ValueUtilsSmi.GetChars_Unchecked(_sink, _getters, _columnIndex, _position, buffer, index + charsRead, charsNeeded); - _position += newCharsRead; - charsRead += newCharsRead; - } - - return charsRead; - } - - /// - /// Forces the TextReader to act as if it was closed - /// This does not actually close the stream, read off the rest of the data or dispose this - /// - internal void SetClosed() - { - _sink = null; - _getters = null; - _peekedChar = -1; - } - - /// - /// True if this TextReader is supposed to be closed - /// - private bool IsClosed - { - get { return ((_sink == null) || (_getters == null)); } - } - - /// - /// True if there is a peeked character available - /// - private bool HasPeekedChar - { - get { return (_peekedChar >= char.MinValue); } - } - } -} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlDataRecord.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlDataRecord.cs index 1a0f92fdbe..9c85fa2659 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlDataRecord.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/SqlDataRecord.cs @@ -387,18 +387,9 @@ public SqlDataRecord(params SqlMetaData[] metaData) _eventSink = new SmiEventSink_Default(); #if NETFRAMEWORK - if (InOutOfProcHelper.InProc) - { - _recordContext = SmiContextFactory.Instance.GetCurrentContext(); - _recordBuffer = _recordContext.CreateRecordBuffer(_columnSmiMetaData, _eventSink); - _usesStringStorageForXml = false; - } - else - { - _recordContext = null; - _recordBuffer = new MemoryRecordBuffer(_columnSmiMetaData); - _usesStringStorageForXml = true; - } + _recordContext = null; + _recordBuffer = new MemoryRecordBuffer(_columnSmiMetaData); + _usesStringStorageForXml = true; #else _recordBuffer = new MemoryRecordBuffer(_columnSmiMetaData); _eventSink.ProcessMessagesAndThrow(); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs index bc259585ff..60d44dbdd0 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs @@ -482,28 +482,8 @@ internal static SqlChars GetSqlChars(SmiEventSink_Default sink, ITypedGettersV3 } else { -#if NETFRAMEWORK - long length = GetCharsLength_Unchecked(sink, getters, ordinal); - if (length < MaxByteChunkSize || !InOutOfProcHelper.InProc) - { - char[] charBuffer = GetCharArray_Unchecked(sink, getters, ordinal); - result = new SqlChars(charBuffer); - } - else - { // InProc only - Stream s = new SmiGettersStream(sink, getters, ordinal, metaData); - SqlStreamChars sc = CopyIntoNewSmiScratchStreamChars(s, sink, context); - - Type SqlCharsType = (typeof(SqlChars)); - Type[] argTypes = new Type[] { typeof(SqlStreamChars) }; - SqlChars SqlCharsInstance = (SqlChars)SqlCharsType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, - null, argTypes, null).Invoke(new object[] { sc }); - result = SqlCharsInstance; - } -#else char[] charBuffer = GetCharArray_Unchecked(sink, getters, ordinal); result = new SqlChars(charBuffer); -#endif } } else @@ -3184,16 +3164,6 @@ private static SqlMoney GetSqlMoney_Unchecked(SmiEventSink_Default sink, ITypedG private static SqlXml GetSqlXml_Unchecked(SmiEventSink_Default sink, ITypedGettersV3 getters, int ordinal, SmiContext context) { Debug.Assert(!IsDBNull_Unchecked(sink, getters, ordinal)); -#if NETFRAMEWORK - // allow context to be null so strongly-typed getters can use - // this method without having to pass along the almost-never-used context as a parameter - // Looking the context up like this will be slightly slower, but still correct behavior - // since it's only used to get a scratch stream. - if (context == null && InOutOfProcHelper.InProc) - { - context = SmiContextFactory.Instance.GetCurrentContext(); // In the future we need to push the context checking to a higher level - } -#endif // Note: must make a copy of getter stream, since it will be used beyond // this method (valid lifetime of getters is limited). Stream s = new SmiGettersStream(sink, getters, ordinal, SmiMetaData.DefaultXml); @@ -3918,12 +3888,7 @@ DataTable value internal static Stream CopyIntoNewSmiScratchStream(Stream source, SmiEventSink_Default sink, SmiContext context) { Stream dest = null; -#if NETFRAMEWORK - if (context != null) - { - dest = new SqlClientWrapperSmiStream(sink, context.GetScratchStream(sink)); - } -#endif + if (dest == null) { dest = new MemoryStream(); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.netfx.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.netfx.cs index 7bed34713b..368c6d5569 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.netfx.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.netfx.cs @@ -17,35 +17,6 @@ namespace Microsoft.Data.SqlClient.Server // as an ExtendedClrTypeCode enum for rapid access (lookup in static array is best, if possible). internal static partial class ValueUtilsSmi { - - internal static SqlSequentialStreamSmi GetSequentialStream(SmiEventSink_Default sink, ITypedGettersV3 getters, int ordinal, SmiMetaData metaData, bool bypassTypeCheck = false) - { - Debug.Assert(!ValueUtilsSmi.IsDBNull_Unchecked(sink, getters, ordinal), "Should not try to get a SqlSequentialStreamSmi on a null column"); - ThrowIfITypedGettersIsNull(sink, getters, ordinal); - if ((!bypassTypeCheck) && (!CanAccessGetterDirectly(metaData, ExtendedClrTypeCode.Stream))) - { - throw ADP.InvalidCast(); - } - - // This will advance the column to ordinal - long length = GetBytesLength_Unchecked(sink, getters, ordinal); - return new SqlSequentialStreamSmi(sink, getters, ordinal, length); - } - - internal static SqlSequentialTextReaderSmi GetSequentialTextReader(SmiEventSink_Default sink, ITypedGettersV3 getters, int ordinal, SmiMetaData metaData) - { - Debug.Assert(!ValueUtilsSmi.IsDBNull_Unchecked(sink, getters, ordinal), "Should not try to get a SqlSequentialTextReaderSmi on a null column"); - ThrowIfITypedGettersIsNull(sink, getters, ordinal); - if (!CanAccessGetterDirectly(metaData, ExtendedClrTypeCode.TextReader)) - { - throw ADP.InvalidCast(); - } - - // This will advance the column to ordinal - long length = GetCharsLength_Unchecked(sink, getters, ordinal); - return new SqlSequentialTextReaderSmi(sink, getters, ordinal, length); - } - internal static Stream GetStream(SmiEventSink_Default sink, ITypedGettersV3 getters, int ordinal, SmiMetaData metaData, bool bypassTypeCheck = false) { bool isDbNull = ValueUtilsSmi.IsDBNull_Unchecked(sink, getters, ordinal); @@ -474,35 +445,5 @@ internal static void FillCompatibleITypedSettersFromRecord(SmiEventSink_Default } } } - - // spool a Stream into a scratch stream from the Smi interface and return it as a SqlStreamChars - internal static SqlStreamChars CopyIntoNewSmiScratchStreamChars(Stream source, SmiEventSink_Default sink, SmiContext context) - { - SqlClientWrapperSmiStreamChars dest = new(sink, context.GetScratchStream(sink)); - - int chunkSize; - if (source.CanSeek && source.Length < MaxByteChunkSize) - { - chunkSize = unchecked((int)source.Length); // unchecked cast is safe due to check on line above - } - else - { - chunkSize = MaxByteChunkSize; - } - - byte[] copyBuffer = new byte[chunkSize]; - int bytesRead; - while (0 != (bytesRead = source.Read(copyBuffer, 0, chunkSize))) - { - dest.Write(copyBuffer, 0, bytesRead); - } - dest.Flush(); - - // SQLBU 494334 - // Need to re-wind scratch stream to beginning before returning - dest.Seek(0, SeekOrigin.Begin); - - return dest; - } } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs index b1be562978..3fd5405c2e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -2429,10 +2429,6 @@ static internal Exception NotAvailableOnContextConnection() { return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_NotAvailableOnContextConnection)); } - static internal Exception NotificationsNotAvailableOnContextConnection() - { - return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_NotificationsNotAvailableOnContextConnection)); - } static internal Exception UserInstanceNotAvailableInProc() {