static internal SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, SqlInternalConnectionTds internalConnection, Exception innerException = null) { Guid connectionId = Guid.Empty; var exception = CreateException(errorCollection, serverVersion, connectionId, innerException); /* if (internalConnection != null) { if ((internalConnection.OriginalClientConnectionId != Guid.Empty) && (internalConnection.OriginalClientConnectionId != internalConnection.ClientConnectionId)) { exception.Data.Add(OriginalClientConnectionIdKey, internalConnection.OriginalClientConnectionId); } if (!string.IsNullOrEmpty(internalConnection.RoutingDestination)) { exception.Data.Add(RoutingDestinationKey, internalConnection.RoutingDestination); } } */ return exception; }
/// <summary> /// Determines if a column value should be transparently decrypted (based on SqlCommand and Connection String settings). /// </summary> /// <returns>true if the value should be transparently decrypted, false otherwise</returns> internal static bool ShouldHonorTceForRead (SqlCommandColumnEncryptionSetting columnEncryptionSetting, SqlInternalConnectionTds connection) { // Command leve setting trumps all switch (columnEncryptionSetting) { case SqlCommandColumnEncryptionSetting.Disabled: return false; case SqlCommandColumnEncryptionSetting.Enabled: return true; case SqlCommandColumnEncryptionSetting.ResultSetOnly: return true; default: // Check connection level setting! Debug.Assert(SqlCommandColumnEncryptionSetting.UseConnectionSetting == columnEncryptionSetting, "Unexpected value for command level override"); return (connection != null && connection.ConnectionOptions != null && connection.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled); } }
internal void Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, bool ignoreSniOpenTimeout, long timerExpire, bool encrypt, bool trustServerCert, bool integratedSecurity, bool withFailover, bool isFirstTransparentAttempt, SqlAuthenticationMethod authType) { if (_state != TdsParserState.Closed) { Debug.Assert(false, "TdsParser.Connect called on non-closed connection!"); return; } _connHandler = connHandler; _loginWithFailover = withFailover; UInt32 sniStatus = SNILoadHandle.SingletonInstance.SNIStatus; if (sniStatus != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); _physicalStateObj.Dispose(); ThrowExceptionAndWarning(_physicalStateObj); Debug.Assert(false, "SNI returned status != success, but no error thrown?"); } //Create LocalDB instance if necessary if (connHandler.ConnectionOptions.LocalDBInstance != null) LocalDBAPI.CreateLocalDBInstance(connHandler.ConnectionOptions.LocalDBInstance); if (integratedSecurity || authType == SqlAuthenticationMethod.ActiveDirectoryIntegrated) { LoadSSPILibrary(); // now allocate proper length of buffer _sniSpnBuffer = new byte[SNINativeMethodWrapper.SniMaxComposedSpnLength]; Bid.Trace("<sc.TdsParser.Connect|SEC> SSPI or Active Directory Authentication Library for SQL Server based integrated authentication\n"); } else { _sniSpnBuffer = null; if (authType == SqlAuthenticationMethod.ActiveDirectoryPassword) { Bid.Trace("<sc.TdsParser.Connect|SEC> Active Directory Password authentication\n"); } else if (authType == SqlAuthenticationMethod.SqlPassword) { Bid.Trace("<sc.TdsParser.Connect|SEC> SQL Password authentication\n"); } else{ Bid.Trace("<sc.TdsParser.Connect|SEC> SQL authentication\n"); } } byte[] instanceName = null; Debug.Assert(_connHandler != null, "SqlConnectionInternalTds handler can not be null at this point."); _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.InitializeConnection); bool fParallel = _connHandler.ConnectionOptions.MultiSubnetFailover; TransparentNetworkResolutionState transparentNetworkResolutionState; if(_connHandler.ConnectionOptions.TransparentNetworkIPResolution) { if(isFirstTransparentAttempt) transparentNetworkResolutionState = TransparentNetworkResolutionState.SequentialMode; else transparentNetworkResolutionState = TransparentNetworkResolutionState.ParallelMode; } else transparentNetworkResolutionState = TransparentNetworkResolutionState.DisabledMode; int totalTimeout = _connHandler.ConnectionOptions.ConnectTimeout; _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, _sniSpnBuffer, false, true, fParallel, transparentNetworkResolutionState, totalTimeout); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); // Since connect failed, free the unmanaged connection memory. // HOWEVER - only free this after the netlib error was processed - if you // don't, the memory for the connection object might not be accurate and thus // a bad error could be returned (as it was when it was freed to early for me). _physicalStateObj.Dispose(); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); ThrowExceptionAndWarning(_physicalStateObj); Debug.Assert(false, "SNI returned status != success, but no error thrown?"); } _server = serverInfo.ResolvedServerName; if (null != connHandler.PoolGroupProviderInfo) { // If we are pooling, check to see if we were processing an // alias which has changed, which means we need to clean out // the pool. See Webdata 104293. // This should not apply to routing, as it is not an alias change, routed connection // should still use VNN of AlwaysOn cluster as server for pooling purposes. connHandler.PoolGroupProviderInfo.AliasCheck(serverInfo.PreRoutingServerName==null ? serverInfo.ResolvedServerName: serverInfo.PreRoutingServerName); } _state = TdsParserState.OpenNotLoggedIn; _physicalStateObj.SniContext = SniContext.Snix_PreLoginBeforeSuccessfullWrite; // SQL BU DT 376766 _physicalStateObj.TimeoutTime = timerExpire; bool marsCapable = false; _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.InitializeConnection); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.SendPreLoginHandshake); UInt32 result = SNINativeMethodWrapper.SniGetConnectionId(_physicalStateObj.Handle, ref _connHandler._clientConnectionId); Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionId"); // Bid.Trace("<sc.TdsParser.Connect|SEC> Sending prelogin handshake\n"); SendPreLoginHandshake(instanceName, encrypt); _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.SendPreLoginHandshake); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.ConsumePreLoginHandshake); _physicalStateObj.SniContext = SniContext.Snix_PreLogin; Bid.Trace("<sc.TdsParser.Connect|SEC> Consuming prelogin handshake\n"); PreLoginHandshakeStatus status = ConsumePreLoginHandshake(authType, encrypt, trustServerCert, integratedSecurity, out marsCapable, out _connHandler._fedAuthRequired); if (status == PreLoginHandshakeStatus.InstanceFailure) { Bid.Trace("<sc.TdsParser.Connect|SEC> Prelogin handshake unsuccessful. Reattempting prelogin handshake\n"); _physicalStateObj.Dispose(); // Close previous connection // On Instance failure re-connect and flush SNI named instance cache. _physicalStateObj.SniContext=SniContext.Snix_Connect; _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, _sniSpnBuffer, true, true, fParallel, transparentNetworkResolutionState, totalTimeout); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); ThrowExceptionAndWarning(_physicalStateObj); } UInt32 retCode = SNINativeMethodWrapper.SniGetConnectionId(_physicalStateObj.Handle, ref _connHandler._clientConnectionId); Debug.Assert(retCode == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionId"); Bid.Trace("<sc.TdsParser.Connect|SEC> Sending prelogin handshake\n"); SendPreLoginHandshake(instanceName, encrypt); status = ConsumePreLoginHandshake(authType, encrypt, trustServerCert, integratedSecurity, out marsCapable, out _connHandler._fedAuthRequired); // Don't need to check for Sphinx failure, since we've already consumed // one pre-login packet and know we are connecting to Shiloh. if (status == PreLoginHandshakeStatus.InstanceFailure) { Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Prelogin handshake unsuccessful. Login failure\n"); throw SQL.InstanceFailure(); } } Bid.Trace("<sc.TdsParser.Connect|SEC> Prelogin handshake successful\n"); if (_fMARS && marsCapable) { // if user explictly disables mars or mars not supported, don't create the session pool _sessionPool = new TdsParserSessionPool(this); } else { _fMARS = false; } if (authType == SqlAuthenticationMethod.ActiveDirectoryPassword || (authType == SqlAuthenticationMethod.ActiveDirectoryIntegrated && _connHandler._fedAuthRequired)) { Debug.Assert(!integratedSecurity, "The legacy Integrated Security connection string option cannot be true when using Active Directory Authentication Library for SQL Server Based workflows."); LoadADALLibrary(); if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.Connect|SEC> Active directory authentication.Loaded Active Directory Authentication Library for SQL Server\n"); } } return; }
internal static void ContinueTask(Task task, TaskCompletionSource <object> completion, Action onSuccess, SqlInternalConnectionTds connectionToDoom = null, Action <Exception> onFailure = null, Action onCancellation = null, Func <Exception, Exception> exceptionConverter = null, SqlConnection connectionToAbort = null ) { Debug.Assert((connectionToAbort == null) || (connectionToDoom == null), "Should not specify both connectionToDoom and connectionToAbort"); task.ContinueWith( tsk => { if (tsk.Exception != null) { Exception exc = tsk.Exception.InnerException; if (exceptionConverter != null) { exc = exceptionConverter(exc); } try { if (onFailure != null) { onFailure(exc); } } finally { completion.TrySetException(exc); } } else if (tsk.IsCanceled) { try { if (onCancellation != null) { onCancellation(); } } finally { completion.TrySetCanceled(); } } else { try { onSuccess(); } catch (Exception e) { completion.SetException(e); } } }, TaskScheduler.Default ); }
internal static Task CreateContinuationTask <T1, T2>(Task task, Action <T1, T2> onSuccess, T1 arg1, T2 arg2, SqlInternalConnectionTds connectionToDoom = null, Action <Exception> onFailure = null) { return(CreateContinuationTask(task, () => onSuccess(arg1, arg2), connectionToDoom, onFailure)); }
internal Task ValidateAndReconnect(Action beforeDisconnect, int timeout) { Task runningReconnect = _currentReconnectionTask; // This loop in the end will return not completed reconnect task or null while (runningReconnect != null && runningReconnect.IsCompleted) { // clean current reconnect task (if it is the same one we checked Interlocked.CompareExchange <Task>(ref _currentReconnectionTask, null, runningReconnect); // make sure nobody started new task (if which case we did not clean it) runningReconnect = _currentReconnectionTask; } if (runningReconnect == null) { if (_connectRetryCount > 0) { SqlInternalConnectionTds tdsConn = GetOpenTdsConnection(); if (tdsConn._sessionRecoveryAcknowledged) { TdsParserStateObject stateObj = tdsConn.Parser._physicalStateObj; if (!stateObj.ValidateSNIConnection()) { if (tdsConn.Parser._sessionPool != null) { if (tdsConn.Parser._sessionPool.ActiveSessionsCount > 0) { // >1 MARS session if (beforeDisconnect != null) { beforeDisconnect(); } OnError(SQL.CR_UnrecoverableClient(ClientConnectionId), true, null); } } SessionData cData = tdsConn.CurrentSessionData; cData.AssertUnrecoverableStateCountIsCorrect(); if (cData._unrecoverableStatesCount == 0) { bool callDisconnect = false; lock (_reconnectLock) { runningReconnect = _currentReconnectionTask; // double check after obtaining the lock if (runningReconnect == null) { if (cData._unrecoverableStatesCount == 0) { // could change since the first check, but now is stable since connection is know to be broken _originalConnectionId = ClientConnectionId; _recoverySessionData = cData; if (beforeDisconnect != null) { beforeDisconnect(); } try { _supressStateChangeForReconnection = true; tdsConn.DoomThisConnection(); } catch (SqlException) { } runningReconnect = Task.Run(() => ReconnectAsync(timeout)); // if current reconnect is not null, somebody already started reconnection task - some kind of race condition Debug.Assert(_currentReconnectionTask == null, "Duplicate reconnection tasks detected"); _currentReconnectionTask = runningReconnect; } } else { callDisconnect = true; } } if (callDisconnect && beforeDisconnect != null) { beforeDisconnect(); } } else { if (beforeDisconnect != null) { beforeDisconnect(); } OnError(SQL.CR_UnrecoverableServer(ClientConnectionId), true, null); } } // ValidateSNIConnection } // sessionRecoverySupported } // connectRetryCount>0 } else { // runningReconnect = null if (beforeDisconnect != null) { beforeDisconnect(); } } return(runningReconnect); }
internal void Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, bool ignoreSniOpenTimeout, long timerExpire, bool encrypt, bool trustServerCert, bool integratedSecurity) { if (this._state == TdsParserState.Closed) { this._connHandler = connHandler; if (SNILoadHandle.SingletonInstance.SNIStatus != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); this._physicalStateObj.Dispose(); this.ThrowExceptionAndWarning(); } if (connHandler.ConnectionOptions.LocalDBInstance != null) { LocalDBAPI.CreateLocalDBInstance(connHandler.ConnectionOptions.LocalDBInstance); } if (integratedSecurity) { this.LoadSSPILibrary(); this._sniSpnBuffer = new byte[SNINativeMethodWrapper.SniMaxComposedSpnLength]; Bid.Trace("<sc.TdsParser.Connect|SEC> SSPI authentication\n"); } else { this._sniSpnBuffer = null; Bid.Trace("<sc.TdsParser.Connect|SEC> SQL authentication\n"); } byte[] instanceName = null; bool multiSubnetFailover = this._connHandler.ConnectionOptions.MultiSubnetFailover; this._physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, this._sniSpnBuffer, false, this._fAsync, multiSubnetFailover); if (this._physicalStateObj.Status != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); this._physicalStateObj.Dispose(); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); this.ThrowExceptionAndWarning(); } this._server = serverInfo.ResolvedServerName; if (connHandler.PoolGroupProviderInfo != null) { connHandler.PoolGroupProviderInfo.AliasCheck((serverInfo.PreRoutingServerName == null) ? serverInfo.ResolvedServerName : serverInfo.PreRoutingServerName); } this._state = TdsParserState.OpenNotLoggedIn; this._physicalStateObj.SniContext = SniContext.Snix_PreLoginBeforeSuccessfullWrite; this._physicalStateObj.TimeoutTime = timerExpire; bool marsCapable = false; this.SendPreLoginHandshake(instanceName, encrypt); this._physicalStateObj.SniContext = SniContext.Snix_PreLogin; switch (this.ConsumePreLoginHandshake(encrypt, trustServerCert, out marsCapable)) { case PreLoginHandshakeStatus.SphinxFailure: this._fMARS = false; this._physicalStateObj._sniPacket = null; this._physicalStateObj.SniContext = SniContext.Snix_Connect; this._physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, this._sniSpnBuffer, false, this._fAsync, multiSubnetFailover); if (this._physicalStateObj.Status != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); this.ThrowExceptionAndWarning(); } break; case PreLoginHandshakeStatus.InstanceFailure: this._physicalStateObj.Dispose(); this._physicalStateObj.SniContext = SniContext.Snix_Connect; this._physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, this._sniSpnBuffer, true, this._fAsync, multiSubnetFailover); if (this._physicalStateObj.Status != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); this.ThrowExceptionAndWarning(); } this.SendPreLoginHandshake(instanceName, encrypt); if (this.ConsumePreLoginHandshake(encrypt, trustServerCert, out marsCapable) == PreLoginHandshakeStatus.InstanceFailure) { Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); throw SQL.InstanceFailure(); } break; } if (this._fMARS && marsCapable) { this._sessionPool = new TdsParserSessionPool(this); } else { this._fMARS = false; } } }
internal void Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, bool ignoreSniOpenTimeout, long timerExpire, bool encrypt, bool trustServerCert, bool integratedSecurity, bool withFailover) { if (_state != TdsParserState.Closed) { Debug.Assert(false, "TdsParser.Connect called on non-closed connection!"); return; } _connHandler = connHandler; _loginWithFailover = withFailover; UInt32 sniStatus = SNILoadHandle.SingletonInstance.SNIStatus; if (sniStatus != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); _physicalStateObj.Dispose(); ThrowExceptionAndWarning(_physicalStateObj); Debug.Assert(false, "SNI returned status != success, but no error thrown?"); } if (integratedSecurity) { LoadSSPILibrary(); // now allocate proper length of buffer _sniSpnBuffer = new byte[SNINativeMethodWrapper.SniMaxComposedSpnLength]; } else { _sniSpnBuffer = null; } byte[] instanceName = null; Debug.Assert(_connHandler != null, "SqlConnectionInternalTds handler can not be null at this point."); _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.InitializeConnection); bool fParallel = _connHandler.ConnectionOptions.MultiSubnetFailover; _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, _sniSpnBuffer, false, true, fParallel); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); // Since connect failed, free the unmanaged connection memory. // HOWEVER - only free this after the netlib error was processed - if you // don't, the memory for the connection object might not be accurate and thus // a bad error could be returned (as it was when it was freed to early for me). _physicalStateObj.Dispose(); ThrowExceptionAndWarning(_physicalStateObj); Debug.Assert(false, "SNI returned status != success, but no error thrown?"); } _server = serverInfo.ResolvedServerName; if (null != connHandler.PoolGroupProviderInfo) { // If we are pooling, check to see if we were processing an // alias which has changed, which means we need to clean out // the pool. See Webdata 104293. // This should not apply to routing, as it is not an alias change, routed connection // should still use VNN of AlwaysOn cluster as server for pooling purposes. connHandler.PoolGroupProviderInfo.AliasCheck(serverInfo.PreRoutingServerName == null ? serverInfo.ResolvedServerName : serverInfo.PreRoutingServerName); } _state = TdsParserState.OpenNotLoggedIn; _physicalStateObj.SniContext = SniContext.Snix_PreLoginBeforeSuccessfullWrite; _physicalStateObj.TimeoutTime = timerExpire; bool marsCapable = false; _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.InitializeConnection); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.SendPreLoginHandshake); UInt32 result = SNINativeMethodWrapper.SniGetConnectionId(_physicalStateObj.Handle, ref _connHandler._clientConnectionId); Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionId"); SendPreLoginHandshake(instanceName, encrypt); _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.SendPreLoginHandshake); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.ConsumePreLoginHandshake); _physicalStateObj.SniContext = SniContext.Snix_PreLogin; PreLoginHandshakeStatus status = ConsumePreLoginHandshake(encrypt, trustServerCert, integratedSecurity, out marsCapable); if (status == PreLoginHandshakeStatus.InstanceFailure) { _physicalStateObj.Dispose(); // Close previous connection // On Instance failure re-connect and flush SNI named instance cache. _physicalStateObj.SniContext = SniContext.Snix_Connect; _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, _sniSpnBuffer, true, true, fParallel); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); ThrowExceptionAndWarning(_physicalStateObj); } UInt32 retCode = SNINativeMethodWrapper.SniGetConnectionId(_physicalStateObj.Handle, ref _connHandler._clientConnectionId); Debug.Assert(retCode == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionId"); SendPreLoginHandshake(instanceName, encrypt); status = ConsumePreLoginHandshake(encrypt, trustServerCert, integratedSecurity, out marsCapable); // Don't need to check for Sphinx failure, since we've already consumed // one pre-login packet and know we are connecting to Shiloh. if (status == PreLoginHandshakeStatus.InstanceFailure) { throw SQL.InstanceFailure(); } } if (_fMARS && marsCapable) { // if user explictly disables mars or mars not supported, don't create the session pool _sessionPool = new TdsParserSessionPool(this); } else { _fMARS = false; } return; }
override protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) { SqlConnectionString opt = (SqlConnectionString)options; SqlConnectionPoolKey key = (SqlConnectionPoolKey)poolKey; SqlInternalConnection result = null; SessionData recoverySessionData = null; SqlConnectionString userOpt = null; if (userOptions != null) { userOpt = (SqlConnectionString)userOptions; } else if (owningConnection != null) { userOpt = (SqlConnectionString)(((SqlConnection)owningConnection).UserConnectionOptions); } if (owningConnection != null) { recoverySessionData = ((SqlConnection)owningConnection)._recoverySessionData; } bool redirectedUserInstance = false; DbConnectionPoolIdentity identity = null; // Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security. // Used by notifications. if (opt.IntegratedSecurity) { if (pool != null) { identity = pool.Identity; } else { identity = DbConnectionPoolIdentity.GetCurrent(); } } // FOLLOWING IF BLOCK IS ENTIRELY FOR SSE USER INSTANCES // If "user instance=true" is in the connection string, we're using SSE user instances if (opt.UserInstance) { // opt.DataSource is used to create the SSE connection redirectedUserInstance = true; string instanceName; if ((null == pool) || (null != pool && pool.Count <= 0)) { // Non-pooled or pooled and no connections in the pool. SqlInternalConnectionTds sseConnection = null; try { // We throw an exception in case of a failure // NOTE: Cloning connection option opt to set 'UserInstance=True' and 'Enlist=False' // This first connection is established to SqlExpress to get the instance name // of the UserInstance. SqlConnectionString sseopt = new SqlConnectionString(opt, opt.DataSource, true /* user instance=true */); sseConnection = new SqlInternalConnectionTds(identity, sseopt, null, false); // NOTE: Retrieve <UserInstanceName> here. This user instance name will be used below to connect to the Sql Express User Instance. instanceName = sseConnection.InstanceName; if (!instanceName.StartsWith("\\\\.\\", StringComparison.Ordinal)) { throw SQL.NonLocalSSEInstance(); } if (null != pool) { // Pooled connection - cache result SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo; // No lock since we are already in creation mutex providerInfo.InstanceName = instanceName; } } finally { if (null != sseConnection) { sseConnection.Dispose(); } } } else { // Cached info from pool. SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo; // No lock since we are already in creation mutex instanceName = providerInfo.InstanceName; } // NOTE: Here connection option opt is cloned to set 'instanceName=<UserInstanceName>' that was // retrieved from the previous SSE connection. For this UserInstance connection 'Enlist=True'. // options immutable - stored in global hash - don't modify opt = new SqlConnectionString(opt, instanceName, false /* user instance=false */); poolGroupProviderInfo = null; // null so we do not pass to constructor below... } result = new SqlInternalConnectionTds(identity, opt, poolGroupProviderInfo, redirectedUserInstance, userOpt, recoverySessionData); return(result); }
internal static SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, SqlInternalConnectionTds internalConnection, Exception innerException = null) { Guid connectionId = (internalConnection == null) ? Guid.Empty : internalConnection._clientConnectionId; var exception = CreateException(errorCollection, serverVersion, connectionId, innerException); if (internalConnection != null) { if ((internalConnection.OriginalClientConnectionId != Guid.Empty) && (internalConnection.OriginalClientConnectionId != internalConnection.ClientConnectionId)) { exception.Data.Add(OriginalClientConnectionIdKey, internalConnection.OriginalClientConnectionId); } if (!string.IsNullOrEmpty(internalConnection.RoutingDestination)) { exception.Data.Add(RoutingDestinationKey, internalConnection.RoutingDestination); } } return(exception); }
internal Task ValidateAndReconnect(Action beforeDisconnect, int timeout) { Task runningReconnect = _currentReconnectionTask; // This loop in the end will return not completed reconnect task or null while (runningReconnect != null && runningReconnect.IsCompleted) { // clean current reconnect task (if it is the same one we checked Interlocked.CompareExchange <Task>(ref _currentReconnectionTask, null, runningReconnect); // make sure nobody started new task (if which case we did not clean it) runningReconnect = _currentReconnectionTask; } if (runningReconnect == null) { if (_connectRetryCount > 0) { SqlInternalConnectionTds tdsConn = GetOpenTdsConnection(); if (tdsConn._sessionRecoveryAcknowledged) { TdsParser tdsParser = tdsConn.Parser; if (!tdsParser._physicalStateObj.ValidateSNIConnection()) { if ((tdsParser._sessionPool != null) && (tdsParser._sessionPool.ActiveSessionsCount > 0)) { // >1 MARS session beforeDisconnect?.Invoke(); OnError(SQL.CR_UnrecoverableClient(ClientConnectionId), true, null); } SessionData cData = tdsConn.CurrentSessionData; cData.AssertUnrecoverableStateCountIsCorrect(); if (cData._unrecoverableStatesCount == 0) { TaskCompletionSource <object> reconnectCompletionSource = new TaskCompletionSource <object>(); runningReconnect = Interlocked.CompareExchange(ref _currentReconnectionTask, reconnectCompletionSource.Task, null); if (runningReconnect == null) { if (cData._unrecoverableStatesCount == 0) { // could change since the first check, but now is stable since connection is know to be broken _originalConnectionId = ClientConnectionId; _recoverySessionData = cData; beforeDisconnect?.Invoke(); try { _supressStateChangeForReconnection = true; tdsConn.DoomThisConnection(); } catch (SqlException) { } Task.Run(() => ReconnectAsync(timeout).ContinueWith(t => { if (t.IsFaulted) { reconnectCompletionSource.SetException(t.Exception); } else if (t.IsCanceled) { reconnectCompletionSource.SetCanceled(); } else { reconnectCompletionSource.SetResult(null); } })); runningReconnect = reconnectCompletionSource.Task; } } else { beforeDisconnect?.Invoke(); } } else { beforeDisconnect?.Invoke(); OnError(SQL.CR_UnrecoverableServer(ClientConnectionId), true, null); } } // ValidateSNIConnection } // sessionRecoverySupported } // connectRetryCount>0 } else { // runningReconnect = null beforeDisconnect?.Invoke(); } return(runningReconnect); }
override protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) { SqlConnectionString opt = (SqlConnectionString)options; SqlConnectionPoolKey key = (SqlConnectionPoolKey)poolKey; SqlInternalConnection result = null; SessionData recoverySessionData = null; SqlConnection sqlOwningConnection = owningConnection as SqlConnection; bool applyTransientFaultHandling = sqlOwningConnection != null ? sqlOwningConnection._applyTransientFaultHandling : false; SqlConnectionString userOpt = null; if (userOptions != null) { userOpt = (SqlConnectionString)userOptions; } else if (sqlOwningConnection != null) { userOpt = (SqlConnectionString)(sqlOwningConnection.UserConnectionOptions); } if (sqlOwningConnection != null) { recoverySessionData = sqlOwningConnection._recoverySessionData; } if (opt.ContextConnection) { result = GetContextConnection(opt, poolGroupProviderInfo); } else { bool redirectedUserInstance = false; DbConnectionPoolIdentity identity = null; // Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security. // Used by notifications. if (opt.IntegratedSecurity || opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated) { if (pool != null) { identity = pool.Identity; } else { identity = DbConnectionPoolIdentity.GetCurrent(); } } // FOLLOWING IF BLOCK IS ENTIRELY FOR SSE USER INSTANCES // If "user instance=true" is in the connection string, we're using SSE user instances if (opt.UserInstance) { // opt.DataSource is used to create the SSE connection redirectedUserInstance = true; string instanceName; if ((null == pool) || (null != pool && pool.Count <= 0)) // Non-pooled or pooled and no connections in the pool. { SqlInternalConnectionTds sseConnection = null; try { // What about a failure - throw? YES! // SqlConnectionString sseopt = new SqlConnectionString(opt, opt.DataSource, true /* user instance=true */, false /* set Enlist = false */); sseConnection = new SqlInternalConnectionTds(identity, sseopt, key.Credential, null, "", null, false, applyTransientFaultHandling: applyTransientFaultHandling); // NOTE: Retrieve <UserInstanceName> here. This user instance name will be used below to connect to the Sql Express User Instance. instanceName = sseConnection.InstanceName; if (!instanceName.StartsWith("\\\\.\\", StringComparison.Ordinal)) { throw SQL.NonLocalSSEInstance(); } if (null != pool) // Pooled connection - cache result { SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo; // No lock since we are already in creation mutex providerInfo.InstanceName = instanceName; } } finally { if (null != sseConnection) { sseConnection.Dispose(); } } } else // Cached info from pool. { SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo; // No lock since we are already in creation mutex instanceName = providerInfo.InstanceName; } // NOTE: Here connection option opt is cloned to set 'instanceName=<UserInstanceName>' that was // retrieved from the previous SSE connection. For this UserInstance connection 'Enlist=True'. // options immutable - stored in global hash - don't modify opt = new SqlConnectionString(opt, instanceName, false /* user instance=false */, null /* do not modify the Enlist value */); poolGroupProviderInfo = null; // null so we do not pass to constructor below... } result = new SqlInternalConnectionTds(identity, opt, key.Credential, poolGroupProviderInfo, "", null, redirectedUserInstance, userOpt, recoverySessionData, pool, key.AccessToken, applyTransientFaultHandling: applyTransientFaultHandling); } return(result); }
public static void ChangePassword(string connectionString, string newPassword) { IntPtr ptr; Bid.ScopeEnter(out ptr, "<sc.SqlConnection.ChangePassword|API>"); try { if (ADP.IsEmpty(connectionString)) { throw SQL.ChangePasswordArgumentMissing("connectionString"); } if (ADP.IsEmpty(newPassword)) { throw SQL.ChangePasswordArgumentMissing("newPassword"); } if (0x80 < newPassword.Length) { throw ADP.InvalidArgumentLength("newPassword", 0x80); } SqlConnectionString connectionOptions = SqlConnectionFactory.FindSqlConnectionOptions(connectionString); if (connectionOptions.IntegratedSecurity) { throw SQL.ChangePasswordConflictsWithSSPI(); } if (!ADP.IsEmpty(connectionOptions.AttachDBFilename)) { throw SQL.ChangePasswordUseOfUnallowedKey("attachdbfilename"); } if (connectionOptions.ContextConnection) { throw SQL.ChangePasswordUseOfUnallowedKey("context connection"); } connectionOptions.CreatePermissionSet().Demand(); using (SqlInternalConnectionTds tds = new SqlInternalConnectionTds(null, connectionOptions, null, newPassword, null, false)) { if (!tds.IsYukonOrNewer) { throw SQL.ChangePasswordRequiresYukon(); } } SqlConnectionFactory.SingletonInstance.ClearPool(connectionString); } finally { Bid.ScopeLeave(ref ptr); } }
static internal SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, SqlInternalConnectionTds internalConnection, Exception innerException = null) { throw new PlatformNotSupportedException(EXCEPTION_MESSAGE); }
internal static object GetNullSqlValue( SqlBuffer nullVal, SqlMetaDataPriv md, SqlCommandColumnEncryptionSetting columnEncryptionSetting, SqlInternalConnectionTds connection) { SqlDbType type = md.type; if (type == SqlDbType.VarBinary && // if its a varbinary md.isEncrypted &&// and encrypted ShouldHonorTceForRead(columnEncryptionSetting, connection)){ type = md.baseTI.type; // the use the actual (plaintext) type } switch (type) { case SqlDbType.Real: nullVal.SetToNullOfType(SqlBuffer.StorageType.Single); break; case SqlDbType.Float: nullVal.SetToNullOfType(SqlBuffer.StorageType.Double); break; case SqlDbType.Udt: case SqlDbType.Binary: case SqlDbType.VarBinary: case SqlDbType.Image: nullVal.SqlBinary = SqlBinary.Null; break; case SqlDbType.UniqueIdentifier: nullVal.SqlGuid = SqlGuid.Null; break; case SqlDbType.Bit: nullVal.SetToNullOfType(SqlBuffer.StorageType.Boolean); break; case SqlDbType.TinyInt: nullVal.SetToNullOfType(SqlBuffer.StorageType.Byte); break; case SqlDbType.SmallInt: nullVal.SetToNullOfType(SqlBuffer.StorageType.Int16); break; case SqlDbType.Int: nullVal.SetToNullOfType(SqlBuffer.StorageType.Int32); break; case SqlDbType.BigInt: nullVal.SetToNullOfType(SqlBuffer.StorageType.Int64); break; case SqlDbType.Char: case SqlDbType.VarChar: case SqlDbType.NChar: case SqlDbType.NVarChar: case SqlDbType.Text: case SqlDbType.NText: nullVal.SetToNullOfType(SqlBuffer.StorageType.String); break; case SqlDbType.Decimal: nullVal.SetToNullOfType(SqlBuffer.StorageType.Decimal); break; case SqlDbType.DateTime: case SqlDbType.SmallDateTime: nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTime); break; case SqlDbType.Money: case SqlDbType.SmallMoney: nullVal.SetToNullOfType(SqlBuffer.StorageType.Money); break; case SqlDbType.Variant: // DBNull.Value will have to work here nullVal.SetToNullOfType(SqlBuffer.StorageType.Empty); break; case SqlDbType.Xml: nullVal.SqlCachedBuffer = SqlCachedBuffer.Null; break; case SqlDbType.Date: nullVal.SetToNullOfType(SqlBuffer.StorageType.Date); break; case SqlDbType.Time: nullVal.SetToNullOfType(SqlBuffer.StorageType.Time); break; case SqlDbType.DateTime2: nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTime2); break; case SqlDbType.DateTimeOffset: nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTimeOffset); break; case SqlDbType.Timestamp: // Dev10 Bug #479607 - this should have been the same as SqlDbType.Binary, but it's a rejected breaking change // Dev10 Bug #752790 - don't assert when it does happen break; default: Debug.Assert(false, "unknown null sqlType!" + md.type.ToString()); break; } return nullVal; }
private void EnlistNonNull(Transaction tx) { Debug.Assert(null != tx, "null transaction?"); bool hasDelegatedTransaction = false; // Promotable transactions are only supported on Yukon // servers or newer. SqlDelegatedTransaction delegatedTransaction = new SqlDelegatedTransaction(this, tx); try { // NOTE: System.Transactions claims to resolve all // potential race conditions between multiple delegate // requests of the same transaction to different // connections in their code, such that only one // attempt to delegate will succeed. // NOTE: PromotableSinglePhaseEnlist will eventually // make a round trip to the server; doing this inside // a lock is not the best choice. We presume that you // aren't trying to enlist concurrently on two threads // and leave it at that -- We don't claim any thread // safety with regard to multiple concurrent requests // to enlist the same connection in different // transactions, which is good, because we don't have // it anyway. // PromotableSinglePhaseEnlist may not actually promote // the transaction when it is already delegated (this is // the way they resolve the race condition when two // threads attempt to delegate the same Lightweight // Transaction) In that case, we can safely ignore // our delegated transaction, and proceed to enlist // in the promoted one. // NOTE: Global Transactions is an Azure SQL DB only // feature where the Transaction Manager (TM) is not // MS-DTC. Sys.Tx added APIs to support Non MS-DTC // promoter types/TM in .NET 4.6.1. Following directions // from .NETFX shiproom, to avoid a "hard-dependency" // (compile time) on Sys.Tx, we use reflection to invoke // the new APIs. Further, the _isGlobalTransaction flag // indicates that this is an Azure SQL DB Transaction // that could be promoted to a Global Transaction (it's // always false for on-prem Sql Server). The Promote() // call in SqlDelegatedTransaction makes sure that the // right Sys.Tx.dll is loaded and that Global Transactions // are actually allowed for this Azure SQL DB. if (_isGlobalTransaction) { if (SysTxForGlobalTransactions.EnlistPromotableSinglePhase == null) { // This could be a local Azure SQL DB transaction. hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction); } else { hasDelegatedTransaction = (bool)SysTxForGlobalTransactions.EnlistPromotableSinglePhase.Invoke(tx, new object[] { delegatedTransaction, _globalTransactionTMID }); } } else { // This is an MS-DTC distributed transaction hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction); } if (hasDelegatedTransaction) { this.DelegatedTransaction = delegatedTransaction; } } catch (SqlException e) { // we do not want to eat the error if it is a fatal one if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) { throw; } // if the parser is null or its state is not openloggedin, the connection is no longer good. SqlInternalConnectionTds tdsConnection = this as SqlInternalConnectionTds; if (tdsConnection != null) { TdsParser parser = tdsConnection.Parser; if (parser == null || parser.State != TdsParserState.OpenLoggedIn) { throw; } } // In this case, SqlDelegatedTransaction.Initialize // failed and we don't necessarily want to reject // things -- there may have been a legitimate reason // for the failure. } if (!hasDelegatedTransaction) { byte[] cookie = null; if (_isGlobalTransaction) { if (SysTxForGlobalTransactions.GetPromotedToken == null) { throw SQL.UnsupportedSysTxForGlobalTransactions(); } cookie = (byte[])SysTxForGlobalTransactions.GetPromotedToken.Invoke(tx, null); } else { if (null == _whereAbouts) { byte[] dtcAddress = GetDTCAddress(); if (null == dtcAddress) { throw SQL.CannotGetDTCAddress(); } _whereAbouts = dtcAddress; } cookie = GetTransactionCookie(tx, _whereAbouts); } // send cookie to server to finish enlistment PropagateTransactionCookie(cookie); _isEnlistedInTransaction = true; } EnlistedTransaction = tx; // Tell the base class about our enlistment // If we're on a Yukon or newer server, and we we delegate the // transaction successfully, we will have done a begin transaction, // which produces a transaction id that we should execute all requests // on. The TdsParser or SmiEventSink will store this information as // the current transaction. // // Likewise, propagating a transaction to a Yukon or newer server will // produce a transaction id that The TdsParser or SmiEventSink will // store as the current transaction. // // In either case, when we're working with a Yukon or newer server // we better have a current transaction by now. Debug.Assert(null != CurrentTransaction, "delegated/enlisted transaction with null current transaction?"); }
static internal SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, SqlInternalConnectionTds internalConnection, Exception innerException = null) { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
// // MultiSubnetFailover // /// <summary> /// used to block two scenarios if MultiSubnetFailover is true: /// * server-provided failover partner - raising SqlException in this case /// * connection string with failover partner and MultiSubnetFailover=true - raising argument one in this case with the same message /// </summary> static internal Exception MultiSubnetFailoverWithFailoverPartner(bool serverProvidedFailoverPartner, SqlInternalConnectionTds internalConnection) { string msg = Res.GetString(Res.SQLMSF_FailoverPartnerNotSupported); if (serverProvidedFailoverPartner) { // Replacing InvalidOperation with SQL exception SqlErrorCollection errors = new SqlErrorCollection(); errors.Add(new SqlError(0, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, null, msg, "", 0)); SqlException exc = SqlException.CreateException(errors, null, internalConnection); exc._doNotReconnect = true; // disable open retry logic on this error return(exc); } else { return(ADP.Argument(msg)); } }
override protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) { SqlConnectionString opt = (SqlConnectionString)options; SqlConnectionPoolKey key = (SqlConnectionPoolKey) poolKey; SqlInternalConnection result = null; SessionData recoverySessionData = null; SqlConnectionString userOpt = null; if (userOptions != null) { userOpt = (SqlConnectionString)userOptions; } else if (owningConnection != null) { userOpt = (SqlConnectionString)(((SqlConnection)owningConnection).UserConnectionOptions); } if (owningConnection != null) { recoverySessionData = ((SqlConnection)owningConnection)._recoverySessionData; } if (opt.ContextConnection) { result = GetContextConnection(opt, poolGroupProviderInfo); } else { bool redirectedUserInstance = false; DbConnectionPoolIdentity identity = null; // Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security. // Used by notifications. if (opt.IntegratedSecurity) { if (pool != null) { identity = pool.Identity; } else { identity = DbConnectionPoolIdentity.GetCurrent(); } } // FOLLOWING IF BLOCK IS ENTIRELY FOR SSE USER INSTANCES // If "user instance=true" is in the connection string, we're using SSE user instances if (opt.UserInstance) { // opt.DataSource is used to create the SSE connection redirectedUserInstance = true; string instanceName; if ( (null == pool) || (null != pool && pool.Count <= 0) ) { // Non-pooled or pooled and no connections in the pool. SqlInternalConnectionTds sseConnection = null; try { // What about a failure - throw? YES! // SqlConnectionString sseopt = new SqlConnectionString(opt, opt.DataSource, true /* user instance=true */, false /* set Enlist = false */); sseConnection = new SqlInternalConnectionTds(identity, sseopt, key.Credential, null, "", null, false); // NOTE: Retrieve <UserInstanceName> here. This user instance name will be used below to connect to the Sql Express User Instance. instanceName = sseConnection.InstanceName; if (!instanceName.StartsWith("\\\\.\\", StringComparison.Ordinal)) { throw SQL.NonLocalSSEInstance(); } if (null != pool) { // Pooled connection - cache result SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo) pool.ProviderInfo; // No lock since we are already in creation mutex providerInfo.InstanceName = instanceName; } } finally { if (null != sseConnection) { sseConnection.Dispose(); } } } else { // Cached info from pool. SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo) pool.ProviderInfo; // No lock since we are already in creation mutex instanceName = providerInfo.InstanceName; } // NOTE: Here connection option opt is cloned to set 'instanceName=<UserInstanceName>' that was // retrieved from the previous SSE connection. For this UserInstance connection 'Enlist=True'. // options immutable - stored in global hash - don't modify opt = new SqlConnectionString(opt, instanceName, false /* user instance=false */, null /* do not modify the Enlist value */); poolGroupProviderInfo = null; // null so we do not pass to constructor below... } result = new SqlInternalConnectionTds(identity, opt, key.Credential, poolGroupProviderInfo, "", null, redirectedUserInstance, userOpt, recoverySessionData); } return result; }
private void EnlistNonNull(Transaction tx) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, transaction %d#.\n", base.ObjectID, tx.GetHashCode()); } bool flag = false; if (this.IsYukonOrNewer) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, attempting to delegate\n", base.ObjectID); } SqlDelegatedTransaction promotableSinglePhaseNotification = new SqlDelegatedTransaction(this, tx); try { if (tx.EnlistPromotableSinglePhase(promotableSinglePhaseNotification)) { flag = true; this.DelegatedTransaction = promotableSinglePhaseNotification; if (Bid.AdvancedOn) { long transactionId = 0L; int objectID = 0; if (this.CurrentTransaction != null) { transactionId = this.CurrentTransaction.TransactionId; objectID = this.CurrentTransaction.ObjectID; } Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegated to transaction %d# with transactionId=0x%I64x\n", base.ObjectID, objectID, transactionId); } } } catch (SqlException exception) { if (exception.Class >= 20) { throw; } SqlInternalConnectionTds tds = this as SqlInternalConnectionTds; if (tds != null) { TdsParser parser = tds.Parser; if ((parser == null) || (parser.State != TdsParserState.OpenLoggedIn)) { throw; } } ADP.TraceExceptionWithoutRethrow(exception); } } if (!flag) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegation not possible, enlisting.\n", base.ObjectID); } byte[] transactionCookie = null; if (this._whereAbouts == null) { byte[] dTCAddress = this.GetDTCAddress(); if (dTCAddress == null) { throw SQL.CannotGetDTCAddress(); } this._whereAbouts = dTCAddress; } transactionCookie = GetTransactionCookie(tx, this._whereAbouts); this.PropagateTransactionCookie(transactionCookie); this._isEnlistedInTransaction = true; if (Bid.AdvancedOn) { long num2 = 0L; int num = 0; if (this.CurrentTransaction != null) { num2 = this.CurrentTransaction.TransactionId; num = this.CurrentTransaction.ObjectID; } Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, enlisted with transaction %d# with transactionId=0x%I64x\n", base.ObjectID, num, num2); } } base.EnlistedTransaction = tx; }