Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / SqlClient / SqlInternalConnectionSmi.cs / 1305376 / 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) { // SQLBUVSTS 225982, query for connection once to avoid race condition between GC (that may collect the connection) and the user thread SqlConnection connection = _connection.Connection; if (null != connection && connection.FireInfoMessageEventOnUserErrors) { 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. } } 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; } } /// /// Get boolean that specifies whether an enlisted transaction can be unbound from /// the connection when that transaction completes. /// ////// True if the connection string property "TransactionBinding" is set to TransactionBindingEnum.ImplicitUnbind; /// otherwise, false. /// protected override bool UnbindOnTransactionCompletion { get { return ConnectionOptions.TransactionBinding == SqlConnectionString.TransactionBindingEnum.ImplicitUnbind; } } // Workaround to access context transaction without rewriting connection pool & internalconnections properly. // Context transactions SHOULD be considered enlisted. // This works for now only because we can't unenlist from the context transaction // DON'T START USING THIS ANYWHERE EXCEPT IN InternalTransaction and in InternalConnectionSmi!!! private SysTx.Transaction ContextTransaction { get; set; } private SysTx.Transaction InternalEnlistedTransaction { get { // Workaround to access context transaction without rewriting connection pool & internalconnections properly. // This SHOULD be a simple wrapper around EnlistedTransaction. // This works for now only because we can't unenlist from the context transaction SysTx.Transaction tx = EnlistedTransaction; if (null == tx) { tx = ContextTransaction; } return tx; } } 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); } // VSTS 215465/15029: allow _currentTransaction to be null - it can be cleared before by server's callback 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=%ls, transactionName='%ls', isolationLevel=%ls, 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: try { _pendingTransaction = internalTransaction; // store this for the time being. _smiConnection.BeginTransaction(transactionName, iso, _smiEventSink); } finally { _pendingTransaction = null; } 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; } internal void GetCurrentTransactionPair(out long transactionId, out SysTx.Transaction transaction) { // SQLBU 214740: Transaction state could change between obtaining tranid and transaction // due to background SqlDelegatedTransaction processing. Lock the connection to prevent that. lock (this) { transactionId = (null != CurrentTransaction) ? CurrentTransaction.TransactionId : 0; transaction = null; if (0 != transactionId) { transaction = InternalEnlistedTransaction; } } } 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) { // SQLBU 369953 // for various reasons, the owning object may no longer be connection to this // so call close on the owner, rather than trying to bypass to use internal close logic. 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(); // SQLBUDT #376531 -- ensure this is activated to prevent asserts later. } 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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ToolStripCollectionEditor.cs
- __Error.cs
- CodeStatementCollection.cs
- GeometryModel3D.cs
- SequentialUshortCollection.cs
- WebBrowserHelper.cs
- DocumentSchemaValidator.cs
- ValueQuery.cs
- CodeTypeDeclarationCollection.cs
- Sequence.cs
- LogLogRecord.cs
- XpsInterleavingPolicy.cs
- ChoiceConverter.cs
- Util.cs
- ProjectedSlot.cs
- ContextProperty.cs
- configsystem.cs
- GridViewColumnCollectionChangedEventArgs.cs
- EmbeddedMailObject.cs
- WebPartConnectionsDisconnectVerb.cs
- ToolboxDataAttribute.cs
- InvalidateEvent.cs
- TextWriterTraceListener.cs
- WhileDesigner.xaml.cs
- TypeElementCollection.cs
- OlePropertyStructs.cs
- HtmlControlDesigner.cs
- CalendarTable.cs
- BufferedReadStream.cs
- OperationCanceledException.cs
- DelegateBodyWriter.cs
- DataControlPagerLinkButton.cs
- CaseCqlBlock.cs
- SemanticKeyElement.cs
- CharAnimationBase.cs
- ExpressionReplacer.cs
- DataServiceQueryContinuation.cs
- FrugalList.cs
- WindowsTreeView.cs
- CompilerGlobalScopeAttribute.cs
- DefaultMemberAttribute.cs
- WebDisplayNameAttribute.cs
- InvalidPipelineStoreException.cs
- RewritingSimplifier.cs
- CompositeScriptReferenceEventArgs.cs
- Array.cs
- PropertyGridEditorPart.cs
- WaitForChangedResult.cs
- UnsafeNativeMethods.cs
- FormsAuthenticationCredentials.cs
- CalendarButton.cs
- RIPEMD160Managed.cs
- HttpModulesSection.cs
- OleDbPropertySetGuid.cs
- DES.cs
- SortFieldComparer.cs
- LinearKeyFrames.cs
- DiscreteKeyFrames.cs
- FileSystemWatcher.cs
- ObjectCacheSettings.cs
- MessageLoggingFilterTraceRecord.cs
- CalendarDesigner.cs
- CalendarItem.cs
- SafeRightsManagementHandle.cs
- MLangCodePageEncoding.cs
- SamlSerializer.cs
- RefreshEventArgs.cs
- SkewTransform.cs
- XPathException.cs
- UpDownBase.cs
- PointAnimationBase.cs
- MimeTypeMapper.cs
- WorkflowOperationContext.cs
- UdpDuplexChannel.cs
- IISUnsafeMethods.cs
- ConfigurationStrings.cs
- MdImport.cs
- StopStoryboard.cs
- SparseMemoryStream.cs
- MemberDomainMap.cs
- WindowsSecurityTokenAuthenticator.cs
- DataStreams.cs
- _DomainName.cs
- HtmlEncodedRawTextWriter.cs
- ButtonFieldBase.cs
- OlePropertyStructs.cs
- HtmlInputPassword.cs
- MSAAWinEventWrap.cs
- PartitionResolver.cs
- TransformValueSerializer.cs
- DeclarativeCatalogPart.cs
- VisualStyleRenderer.cs
- SourceFilter.cs
- ClientSponsor.cs
- BreadCrumbTextConverter.cs
- ZipIOExtraFieldZip64Element.cs
- EntityReference.cs
- XmlAnyElementAttributes.cs
- _AcceptOverlappedAsyncResult.cs
- DataServiceBuildProvider.cs