Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Data / System / Data / SqlClient / SqlInternalConnectionSmi.cs / 4 / SqlInternalConnectionSmi.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //----------------------------------------------------------------------------- namespace System.Data.SqlClient { using Microsoft.SqlServer.Server; using System.Data; using System.Data.Common; using System.Diagnostics; using SysTx = System.Transactions; sealed internal class SqlInternalConnectionSmi : SqlInternalConnection { private SmiContext _smiContext; private SmiConnection _smiConnection; private SmiEventSink_Default _smiEventSink; private int _isInUse; // 1 = Connected to open outer connection, 0 = not connected private SqlInternalTransaction _pendingTransaction; // transaction awaiting event signalling that it is active private SqlInternalTransaction _currentTransaction; // currently active non-context transaction. sealed private class EventSink : SmiEventSink_Default { SqlInternalConnectionSmi _connection; override internal string ServerVersion { get { return SmiContextFactory.Instance.ServerVersion; } } override protected void DispatchMessages(bool ignoreNonFatalMessages) { // Override this on the Connection event sink, since we can deal // with info messages here. SqlException exception = ProcessMessages(false, ignoreNonFatalMessages); if (null != exception) { if (_connection.Connection.FireInfoMessageEventOnUserErrors) { _connection.Connection.OnInfoMessage(new SqlInfoMessageEventArgs(exception)); } else { _connection.OnError(exception, false); // we can't really ever break the direct connection, can we? } } } internal EventSink(SqlInternalConnectionSmi connection) { Debug.Assert(null != connection, "null connection?"); _connection = connection; } internal override void DefaultDatabaseChanged( string databaseName ) { if (Bid.AdvancedOn) { Bid.Trace("%d#, databaseName='%ls'.\n", _connection.ObjectID, databaseName); } _connection.CurrentDatabase = databaseName; } internal override void TransactionCommitted( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEnded(transactionId, TransactionState.Committed); } internal override void TransactionDefected( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEnded(transactionId, TransactionState.Unknown); } internal override void TransactionEnlisted( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionStarted(transactionId, true); // distributed; } internal override void TransactionEnded( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEndedByServer(transactionId); } internal override void TransactionRolledBack( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionEnded(transactionId, TransactionState.Aborted); } internal override void TransactionStarted( long transactionId ) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionId=0x%I64x.\n", _connection.ObjectID, transactionId); } _connection.TransactionStarted(transactionId, false); // not distributed; } } internal SqlInternalConnectionSmi(SqlConnectionString connectionOptions, SmiContext smiContext) : base(connectionOptions) { Debug.Assert(null != smiContext, "null smiContext?"); _smiContext = smiContext; _smiContext.OutOfScope += new EventHandler(OnOutOfScope); _smiConnection = _smiContext.ContextConnection; Debug.Assert(null != _smiConnection, "null SmiContext.ContextConnection?"); _smiEventSink = new EventSink(this); if (Bid.AdvancedOn) { Bid.Trace(" %d#, constructed new SMI internal connection\n", ObjectID); } } internal SmiContext InternalContext { get { return _smiContext; } } internal SmiConnection SmiConnection { get { return _smiConnection; } } internal SmiEventSink CurrentEventSink { get { return _smiEventSink; } } override internal SqlInternalTransaction CurrentTransaction { get { return _currentTransaction; } } override internal bool IsLockedForBulkCopy { get { return false; // no bulk copy in the Direct connection case. } } override internal bool IsShiloh { get { return false; // Can't be direct connecting to Shiloh. } } #if WINFSFunctionality override internal bool IsWinFS { get { return false; // } } #endif override internal bool IsYukonOrNewer { get { return true; // Must be direct connecting to Yukon or newer. } } override internal bool IsKatmaiOrNewer { get { return SmiContextFactory.Instance.NegotiatedSmiVersion >= SmiContextFactory.KatmaiVersion; } } override internal SqlInternalTransaction PendingTransaction { get { return CurrentTransaction; // there are no differences between pending and current in proc. } } override public string ServerVersion { get { return SmiContextFactory.Instance.ServerVersion; } } override protected void Activate(SysTx.Transaction transaction) { Debug.Assert(false, "Activating an internal SMI connection?"); // we should never be activating, because that would indicate we're being pooled. } internal void Activate() { int wasInUse = System.Threading.Interlocked.Exchange(ref _isInUse, 1); if (0 != wasInUse) { throw SQL.ContextConnectionIsInUse(); } CurrentDatabase = _smiConnection.GetCurrentDatabase(_smiEventSink); _smiEventSink.ProcessMessagesAndThrow(); } override internal void AddPreparedCommand(SqlCommand cmd) { // this is currently a NOOP in the Smi case, as there is no real use // for prepared commands } internal void AutomaticEnlistment() { SysTx.Transaction currentSystemTransaction = ADP.GetCurrentTransaction(); // NOTE: Must be first to ensure _smiContext.ContextTransaction is set! SysTx.Transaction contextTransaction = _smiContext.ContextTransaction; // returns the transaction that was handed to SysTx that wraps the ContextTransactionId. long contextTransactionId = _smiContext.ContextTransactionId; if (Bid.AdvancedOn) { Bid.Trace(" %d#, contextTransactionId=0x%I64x, contextTransaction=%d#, currentSystemTransaction=%d#.\n", base.ObjectID, contextTransactionId, (null != contextTransaction) ? contextTransaction.GetHashCode() : 0, (null != currentSystemTransaction) ? currentSystemTransaction.GetHashCode() : 0); } if (SqlInternalTransaction.NullTransactionId != contextTransactionId) { if (null != currentSystemTransaction && contextTransaction != currentSystemTransaction) { throw SQL.NestedTransactionScopesNotSupported(); // can't use TransactionScope(RequiresNew) inside a Sql Transaction. } if (Bid.AdvancedOn) { Bid.Trace(" %d#, using context transaction with transactionId=0x%I64x\n", base.ObjectID, contextTransactionId); } _currentTransaction = new SqlInternalTransaction(this, TransactionType.Context, null, contextTransactionId); ContextTransaction = contextTransaction; } else if (null == currentSystemTransaction) { _currentTransaction = null; // there really isn't a transaction. if (Bid.AdvancedOn) { Bid.Trace(" %d#, no transaction.\n", base.ObjectID); } } else { if (Bid.AdvancedOn) { Bid.Trace(" %d#, using current System.Transaction.\n", base.ObjectID); } base.Enlist(currentSystemTransaction); } } override internal void ClearPreparedCommands() { // this is currently a NOOP in the Smi case, as there is no real use // for prepared commands } override protected void ChangeDatabaseInternal(string database) { _smiConnection.SetCurrentDatabase(database, _smiEventSink); _smiEventSink.ProcessMessagesAndThrow(); } override protected void InternalDeactivate() { if (Bid.AdvancedOn) { Bid.Trace(" %d#, Deactivating.\n", base.ObjectID); } // When we put this to bed, we should not hold on to the transaction // or any activity (commit/rollback) may cause it to hang. if (!IsNonPoolableTransactionRoot) { base.Enlist(null); } if (null != _currentTransaction) { if (_currentTransaction.IsContext) { _currentTransaction = null; } else if (_currentTransaction.IsLocal) { _currentTransaction.CloseFromConnection(); } } ContextTransaction = null; _isInUse = 0; // don't need compare-exchange. } override internal void DelegatedTransactionEnded() { base.DelegatedTransactionEnded(); if (Bid.AdvancedOn) { Bid.Trace(" %d#, cleaning up after Delegated Transaction Completion\n", base.ObjectID); } _currentTransaction = null; // clean up our current transaction too } override internal void DisconnectTransaction(SqlInternalTransaction internalTransaction) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, Disconnecting Transaction %d#.\n", base.ObjectID, internalTransaction.ObjectID); } Debug.Assert(_currentTransaction != null && _currentTransaction == internalTransaction, "disconnecting different transaction"); if (_currentTransaction != null && _currentTransaction == internalTransaction) { _currentTransaction = null; } } override public void Dispose() { _smiContext.OutOfScope -= new EventHandler(OnOutOfScope); base.Dispose(); } override internal void ExecuteTransaction(TransactionRequest transactionRequest, string transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest) { if (Bid.AdvancedOn) { Bid.Trace(" %d#, transactionRequest=%s, transactionName='%ls', isolationLevel=%s, internalTransaction=#%d transactionId=0x%I64x.\n", base.ObjectID, transactionRequest.ToString(), (null != transactionName) ? transactionName : "null", iso.ToString(), (null != internalTransaction) ? internalTransaction.ObjectID : 0, (null != internalTransaction) ? internalTransaction.TransactionId : SqlInternalTransaction.NullTransactionId ); } switch (transactionRequest) { case TransactionRequest.Begin: _pendingTransaction = internalTransaction; // store this for the time being. _smiConnection.BeginTransaction(transactionName, iso, _smiEventSink); Debug.Assert(_smiEventSink.HasMessages || null != _currentTransaction, "begin transaction without TransactionStarted event?"); break; case TransactionRequest.Commit: Debug.Assert(null != _currentTransaction, "commit transaction without TransactionStarted event?"); _smiConnection.CommitTransaction(_currentTransaction.TransactionId, _smiEventSink); break; case TransactionRequest.Promote: Debug.Assert(null != _currentTransaction, "promote transaction without TransactionStarted event?"); PromotedDTCToken = _smiConnection.PromoteTransaction(_currentTransaction.TransactionId, _smiEventSink); break; case TransactionRequest.Rollback: case TransactionRequest.IfRollback: Debug.Assert(null != _currentTransaction, "rollback/ifrollback transaction without TransactionStarted event?"); _smiConnection.RollbackTransaction(_currentTransaction.TransactionId, transactionName, _smiEventSink); break; case TransactionRequest.Save: Debug.Assert(null != _currentTransaction, "save transaction without TransactionStarted event?"); _smiConnection.CreateTransactionSavePoint(_currentTransaction.TransactionId, transactionName, _smiEventSink); break; default: Debug.Assert (false, "unhandled case for TransactionRequest"); break; } _smiEventSink.ProcessMessagesAndThrow(); } override protected byte[] GetDTCAddress() { byte[] whereAbouts = _smiConnection.GetDTCAddress(_smiEventSink); // might want to store this on the SmiLink because it doesn't change, but we want to be compatible with TDS which doesn't have a link yet. _smiEventSink.ProcessMessagesAndThrow(); if (Bid.AdvancedOn) { if (null != whereAbouts) { Bid.TraceBin(" whereAbouts", whereAbouts, (UInt16)whereAbouts.Length); } else { Bid.Trace(" whereAbouts=null\n"); } } return whereAbouts; } private void OnOutOfScope(object s, EventArgs e) { // Called whenever the context goes out of scope, we need to make // sure that we close the connection, or the next person that uses // the context may appear to have the connection in use. if (Bid.AdvancedOn) { Bid.Trace(" %d# context is out of scope\n", base.ObjectID); } // DelegatedTransaction = null; // we don't want to hold this over to the next usage; it will automatically be reused as the context transaction... DbConnection owningObject = (DbConnection)Owner; try { if (null != owningObject && 1 == _isInUse) { // owningObject.Close(); } } finally { // Now make sure this object is not left in an in-use state // this is safe, because no user code should be accessing the connection by this time ContextTransaction = null; _isInUse = 0; } } override protected void PropagateTransactionCookie(byte[] transactionCookie) { if (Bid.AdvancedOn) { if (null != transactionCookie) { Bid.TraceBin(" transactionCookie", transactionCookie, (UInt16)transactionCookie.Length); } else { Bid.Trace(" null\n"); } } // Propagate the transaction cookie to the server _smiConnection.EnlistTransaction(transactionCookie, _smiEventSink); _smiEventSink.ProcessMessagesAndThrow(); } private void TransactionEndedByServer(long transactionId) { // Some extra steps required when the server initiates the ending of a transaction unilaterally // as opposed to the client initiating it. // Basically, we have to make the delegated transaction (if there is one) aware of the situation. SqlDelegatedTransaction delegatedTransaction = DelegatedTransaction; if (null != delegatedTransaction) { delegatedTransaction.Transaction.Rollback(); // just to make sure... DelegatedTransaction = null; // He's dead, Jim. } // Now handle the standard transaction-ended stuff. // TransactionEnded(transactionId, TransactionState.Unknown); } private void TransactionEnded(long transactionId, TransactionState transactionState) { // When we get notification of a completed transaction // we null out the current transaction. if (null != _currentTransaction) { #if DEBUG // Check null for case where Begin and Rollback obtained in the same message. if (0 != _currentTransaction.TransactionId) { Debug.Assert(_currentTransaction.TransactionId == transactionId, "transaction id's are not equal!"); } #endif _currentTransaction.Completed(transactionState); _currentTransaction = null; } } private void TransactionStarted(long transactionId, bool isDistributed) { // When we get notification from the server of a new // transaction, we move any pending transaction over to // the current transaction, then we store the token in it. // if there isn't a pending transaction, then it's either // a TSQL transaction or a distributed transaction. Debug.Assert(null == _currentTransaction, "non-null current transaction with an env change"); _currentTransaction = _pendingTransaction; _pendingTransaction = null; if (null != _currentTransaction) { _currentTransaction.TransactionId = transactionId; // this is defined as a ULongLong in the server and in the TDS Spec. } else { TransactionType transactionType = (isDistributed) ? TransactionType.Distributed : TransactionType.LocalFromTSQL; _currentTransaction = new SqlInternalTransaction(this, transactionType, null, transactionId); } _currentTransaction.Activate(); // } override internal void RemovePreparedCommand(SqlCommand cmd) { // this is currently a NOOP in the Smi case, as there is no real use // for prepared commands } override internal void ValidateConnectionForExecute(SqlCommand command) { SqlDataReader reader = FindLiveReader(null); if (null != reader) { // if MARS is on, then a datareader associated with the command exists // or if MARS is off, then a datareader exists throw ADP.OpenReaderExists(); // MDAC 66411 } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MenuItemCollection.cs
- FormViewCommandEventArgs.cs
- SamlAssertionKeyIdentifierClause.cs
- PointIndependentAnimationStorage.cs
- ValueTable.cs
- EmbeddedObject.cs
- MouseWheelEventArgs.cs
- PropertyEntry.cs
- ColumnMapCopier.cs
- ClaimTypeElementCollection.cs
- BitHelper.cs
- UpWmlMobileTextWriter.cs
- AssemblyAttributes.cs
- ContainerVisual.cs
- EventBindingService.cs
- DataColumnPropertyDescriptor.cs
- SafeNativeMethods.cs
- TextTreeTextBlock.cs
- SettingsPropertyNotFoundException.cs
- PeerChannelListener.cs
- PathData.cs
- Floater.cs
- ConfigsHelper.cs
- WebPartZoneCollection.cs
- FullTextBreakpoint.cs
- ExpressionBuilder.cs
- RegexCaptureCollection.cs
- SchemaSetCompiler.cs
- IntegrationExceptionEventArgs.cs
- AdPostCacheSubstitution.cs
- Resources.Designer.cs
- ClientUIRequest.cs
- ContentWrapperAttribute.cs
- Label.cs
- __TransparentProxy.cs
- XpsColorContext.cs
- MouseBinding.cs
- QueryParameter.cs
- RectangleConverter.cs
- TreeNodeStyle.cs
- ScriptModule.cs
- RawTextInputReport.cs
- WebAdminConfigurationHelper.cs
- Rotation3DAnimationUsingKeyFrames.cs
- SmiMetaDataProperty.cs
- NullableDoubleSumAggregationOperator.cs
- PersonalizableAttribute.cs
- ScopedMessagePartSpecification.cs
- FormatSettings.cs
- WpfSharedXamlSchemaContext.cs
- AuthorizationRuleCollection.cs
- ChannelServices.cs
- _ReceiveMessageOverlappedAsyncResult.cs
- HwndSource.cs
- DbReferenceCollection.cs
- TcpServerChannel.cs
- Crc32.cs
- StylusDevice.cs
- PrintPageEvent.cs
- InstanceOwner.cs
- IpcManager.cs
- documentation.cs
- ScriptMethodAttribute.cs
- SerialErrors.cs
- ForwardPositionQuery.cs
- BigInt.cs
- ClientRoleProvider.cs
- xamlnodes.cs
- EventLogPermissionAttribute.cs
- ResponseBodyWriter.cs
- UnmanagedMemoryStreamWrapper.cs
- SettingsPropertyWrongTypeException.cs
- _AutoWebProxyScriptHelper.cs
- Logging.cs
- Converter.cs
- TextStore.cs
- SecurityPermission.cs
- JsonServiceDocumentSerializer.cs
- SelectionEditor.cs
- HtmlForm.cs
- DLinqAssociationProvider.cs
- SqlProcedureAttribute.cs
- RowToParametersTransformer.cs
- PackagingUtilities.cs
- ComponentEditorForm.cs
- XmlFormatReaderGenerator.cs
- ExpressionsCollectionEditor.cs
- SerializationSectionGroup.cs
- PlanCompiler.cs
- ReliabilityContractAttribute.cs
- Calendar.cs
- ToolboxComponentsCreatingEventArgs.cs
- NumericUpDownAccelerationCollection.cs
- GlyphRunDrawing.cs
- EntityCommandDefinition.cs
- SimpleParser.cs
- RoleService.cs
- StatusBarPanel.cs
- XsdDuration.cs
- CatalogUtil.cs