internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction)
 {
     this._isolationLevel = iso;
     this._connection = con;
     if (internalTransaction == null)
     {
         this._internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this);
     }
     else
     {
         this._internalTransaction = internalTransaction;
         this._internalTransaction.InitParent(this);
     }
 }
Exemplo n.º 2
0
        internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con, 
                                IsolationLevel iso, SqlInternalTransaction internalTransaction) {
            SqlConnection.VerifyExecutePermission();

            _isolationLevel = iso;
            _connection = con;

            if (internalTransaction == null) {
                _internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this);
            }
            else {
                Debug.Assert(internalConnection.CurrentTransaction == internalTransaction, "Unexpected Parser.CurrentTransaction state!");
                _internalTransaction = internalTransaction;
                _internalTransaction.InitParent(this);
            }
        }
Exemplo n.º 3
0
        internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con,
                                IsolationLevel iso, SqlInternalTransaction internalTransaction)
        {
            _isolationLevel = iso;
            _connection     = con;

            if (internalTransaction == null)
            {
                _internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this);
            }
            else
            {
                Debug.Assert(internalConnection.CurrentTransaction == internalTransaction, "Unexpected Parser.CurrentTransaction state!");
                _internalTransaction = internalTransaction;
                _internalTransaction.InitParent(this);
            }
        }
Exemplo n.º 4
0
        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("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %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("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %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("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, no transaction.\n", base.ObjectID);
                }
            }
            else
            {
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, using current System.Transaction.\n", base.ObjectID);
                }
                base.Enlist(currentSystemTransaction);
            }
        }
        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;
            }
        }
Exemplo n.º 6
0
        internal override void ExecuteTransaction(SqlInternalConnection.TransactionRequest transactionRequest, string transactionName, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest)
        {
            if (Bid.AdvancedOn)
            {
                Bid.Trace("<sc.SqlInternalConnectionSmi.ExecuteTransaction|ADV> %d#, transactionRequest=%ls, transactionName='%ls', isolationLevel=%ls, internalTransaction=#%d transactionId=0x%I64x.\n", base.ObjectID, transactionRequest.ToString(), (transactionName != null) ? transactionName : "null", iso.ToString(), (internalTransaction != null) ? internalTransaction.ObjectID : 0, (internalTransaction != null) ? internalTransaction.TransactionId : 0L);
            }
            switch (transactionRequest)
            {
            case SqlInternalConnection.TransactionRequest.Begin:
                try
                {
                    this._pendingTransaction = internalTransaction;
                    this._smiConnection.BeginTransaction(transactionName, iso, this._smiEventSink);
                    goto Label_0121;
                }
                finally
                {
                    this._pendingTransaction = null;
                }
                break;

            case SqlInternalConnection.TransactionRequest.Promote:
                base.PromotedDTCToken = this._smiConnection.PromoteTransaction(this._currentTransaction.TransactionId, this._smiEventSink);
                goto Label_0121;

            case SqlInternalConnection.TransactionRequest.Commit:
                break;

            case SqlInternalConnection.TransactionRequest.Rollback:
            case SqlInternalConnection.TransactionRequest.IfRollback:
                this._smiConnection.RollbackTransaction(this._currentTransaction.TransactionId, transactionName, this._smiEventSink);
                goto Label_0121;

            case SqlInternalConnection.TransactionRequest.Save:
                this._smiConnection.CreateTransactionSavePoint(this._currentTransaction.TransactionId, transactionName, this._smiEventSink);
                goto Label_0121;

            default:
                goto Label_0121;
            }
            this._smiConnection.CommitTransaction(this._currentTransaction.TransactionId, this._smiEventSink);
Label_0121:
            this._smiEventSink.ProcessMessagesAndThrow();
        }
Exemplo n.º 7
0
        public void Initialize()
        {
            // if we get here, then we know for certain that we're the delegated
            // transaction.
            SqlInternalConnection connection      = _connection;
            SqlConnection         usersConnection = connection.Connection;

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                if (connection.IsEnlistedInTransaction)
                { // defect first
                    connection.EnlistNull();
                }

                _internalTransaction = new SqlInternalTransaction(connection, TransactionType.Delegated, null);

                connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Begin, null, _isolationLevel, _internalTransaction, true);

                // Handle case where ExecuteTran didn't produce a new transaction, but also didn't throw.
                if (null == connection.CurrentTransaction)
                {
                    connection.DoomThisConnection();
                    throw ADP.InternalError(ADP.InternalErrorCode.UnknownTransactionFailure);
                }

                _active = true;
            }
            catch (System.OutOfMemoryException e)
            {
                usersConnection.Abort(e);
                throw;
            }
            catch (System.StackOverflowException e)
            {
                usersConnection.Abort(e);
                throw;
            }
            catch (System.Threading.ThreadAbortException e)
            {
                usersConnection.Abort(e);
                throw;
            }
        }
Exemplo n.º 8
0
        public override void Rollback()
        {
            Exception e           = null;
            Guid      operationId = s_diagnosticListener.WriteTransactionRollbackBefore(_isolationLevel, _connection, null);

            if (IsYukonPartialZombie)
            {
                // Put something in the trace in case a customer has an issue
                _internalTransaction = null; // yukon zombification
            }
            else
            {
                ZombieCheck();

                SqlStatistics statistics = null;
                try
                {
                    statistics = SqlStatistics.StartTimer(Statistics);

                    _isFromAPI = true;

                    _internalTransaction.Rollback();
                }
                catch (Exception ex)
                {
                    e = ex;
                    throw;
                }
                finally
                {
                    if (e != null)
                    {
                        s_diagnosticListener.WriteTransactionRollbackError(operationId, _isolationLevel, _connection, null, e);
                    }
                    else
                    {
                        s_diagnosticListener.WriteTransactionRollbackAfter(operationId, _isolationLevel, _connection, null);
                    }
                    _isFromAPI = false;

                    SqlStatistics.StopTimer(statistics);
                }
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////
        // INTERNAL METHODS
        ////////////////////////////////////////////////////////////////////////////////////////

        internal void Zombie()
        {
            // SQLBUDT #402544 For Yukon, we have to defer "zombification" until
            //                 we get past the users' next rollback, else we'll
            //                 throw an exception there that is a breaking change.
            //                 Of course, if the connection is aready closed,
            //                 then we're free to zombify...
            SqlInternalConnection internalConnection = (_connection.InnerConnection as SqlInternalConnection);

            if (null != internalConnection && internalConnection.IsYukonOrNewer && !_isFromAPI)
            {
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlTransaction.Zombie|ADV> %d# yukon deferred zombie\n", ObjectID);
                }
            }
            else
            {
                _internalTransaction = null; // pre-yukon zombification
            }
        }
Exemplo n.º 10
0
        internal void AutomaticEnlistment()
        {
            Transaction currentTransaction   = ADP.GetCurrentTransaction();
            Transaction contextTransaction   = this._smiContext.ContextTransaction;
            long        contextTransactionId = this._smiContext.ContextTransactionId;

            if (Bid.AdvancedOn)
            {
                Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, contextTransactionId=0x%I64x, contextTransaction=%d#, currentSystemTransaction=%d#.\n", base.ObjectID, contextTransactionId, (null != contextTransaction) ? contextTransaction.GetHashCode() : 0, (null != currentTransaction) ? currentTransaction.GetHashCode() : 0);
            }
            if (0L != contextTransactionId)
            {
                if ((null != currentTransaction) && (contextTransaction != currentTransaction))
                {
                    throw SQL.NestedTransactionScopesNotSupported();
                }
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, using context transaction with transactionId=0x%I64x\n", base.ObjectID, contextTransactionId);
                }
                this._currentTransaction = new SqlInternalTransaction(this, TransactionType.Context, null, contextTransactionId);
                this.ContextTransaction  = contextTransaction;
            }
            else if (null == currentTransaction)
            {
                this._currentTransaction = null;
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, no transaction.\n", base.ObjectID);
                }
            }
            else
            {
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, using current System.Transaction.\n", base.ObjectID);
                }
                base.Enlist(currentTransaction);
            }
        }
 internal void AutomaticEnlistment()
 {
     Transaction currentTransaction = ADP.GetCurrentTransaction();
     Transaction contextTransaction = this._smiContext.ContextTransaction;
     long contextTransactionId = this._smiContext.ContextTransactionId;
     if (Bid.AdvancedOn)
     {
         Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, contextTransactionId=0x%I64x, contextTransaction=%d#, currentSystemTransaction=%d#.\n", base.ObjectID, contextTransactionId, (null != contextTransaction) ? contextTransaction.GetHashCode() : 0, (null != currentTransaction) ? currentTransaction.GetHashCode() : 0);
     }
     if (0L != contextTransactionId)
     {
         if ((null != currentTransaction) && (contextTransaction != currentTransaction))
         {
             throw SQL.NestedTransactionScopesNotSupported();
         }
         if (Bid.AdvancedOn)
         {
             Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, using context transaction with transactionId=0x%I64x\n", base.ObjectID, contextTransactionId);
         }
         this._currentTransaction = new SqlInternalTransaction(this, TransactionType.Context, null, contextTransactionId);
         this.ContextTransaction = contextTransaction;
     }
     else if (null == currentTransaction)
     {
         this._currentTransaction = null;
         if (Bid.AdvancedOn)
         {
             Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, no transaction.\n", base.ObjectID);
         }
     }
     else
     {
         if (Bid.AdvancedOn)
         {
             Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, using current System.Transaction.\n", base.ObjectID);
         }
         base.Enlist(currentTransaction);
     }
 }
        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.
        }
        public void Initialize()
        {
            SqlInternalConnection innerConnection = this._connection;
            SqlConnection         connection      = innerConnection.Connection;

            Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, delegating transaction.\n", this.ObjectID, innerConnection.ObjectID);
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                if (innerConnection.IsEnlistedInTransaction)
                {
                    Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, was enlisted, now defecting.\n", this.ObjectID, innerConnection.ObjectID);
                    innerConnection.EnlistNull();
                }
                this._internalTransaction = new SqlInternalTransaction(innerConnection, TransactionType.Delegated, null);
                innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Begin, null, this._isolationLevel, this._internalTransaction, true);
                if (innerConnection.CurrentTransaction == null)
                {
                    innerConnection.DoomThisConnection();
                    throw ADP.InternalError(ADP.InternalErrorCode.UnknownTransactionFailure);
                }
                this._active = true;
            }
            catch (OutOfMemoryException exception3)
            {
                connection.Abort(exception3);
                throw;
            }
            catch (StackOverflowException exception2)
            {
                connection.Abort(exception2);
                throw;
            }
            catch (ThreadAbortException exception)
            {
                connection.Abort(exception);
                throw;
            }
        }
 public void Initialize()
 {
     SqlInternalConnection innerConnection = this._connection;
     SqlConnection connection = innerConnection.Connection;
     Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, delegating transaction.\n", this.ObjectID, innerConnection.ObjectID);
     RuntimeHelpers.PrepareConstrainedRegions();
     try
     {
         if (innerConnection.IsEnlistedInTransaction)
         {
             Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, was enlisted, now defecting.\n", this.ObjectID, innerConnection.ObjectID);
             innerConnection.EnlistNull();
         }
         this._internalTransaction = new SqlInternalTransaction(innerConnection, TransactionType.Delegated, null);
         innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Begin, null, this._isolationLevel, this._internalTransaction, true);
         if (innerConnection.CurrentTransaction == null)
         {
             innerConnection.DoomThisConnection();
             throw ADP.InternalError(ADP.InternalErrorCode.UnknownTransactionFailure);
         }
         this._active = true;
     }
     catch (OutOfMemoryException exception3)
     {
         connection.Abort(exception3);
         throw;
     }
     catch (StackOverflowException exception2)
     {
         connection.Abort(exception2);
         throw;
     }
     catch (ThreadAbortException exception)
     {
         connection.Abort(exception);
         throw;
     }
 }
Exemplo n.º 15
0
 protected override void InternalDeactivate()
 {
     if (Bid.AdvancedOn)
     {
         Bid.Trace("<sc.SqlInternalConnectionSmi.Deactivate|ADV> %d#, Deactivating.\n", base.ObjectID);
     }
     if (!this.IsNonPoolableTransactionRoot)
     {
         base.Enlist(null);
     }
     if (this._currentTransaction != null)
     {
         if (this._currentTransaction.IsContext)
         {
             this._currentTransaction = null;
         }
         else if (this._currentTransaction.IsLocal)
         {
             this._currentTransaction.CloseFromConnection();
         }
     }
     this.ContextTransaction = null;
     this._isInUse           = 0;
 }
Exemplo n.º 16
0
        internal void ExecuteTransactionYukon(SqlInternalConnection.TransactionRequest transactionRequest, string transactionName, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest)
        {
            TdsEnums.TransactionManagerRequestType    begin         = TdsEnums.TransactionManagerRequestType.Begin;
            TdsEnums.TransactionManagerIsolationLevel readCommitted = TdsEnums.TransactionManagerIsolationLevel.ReadCommitted;
            switch (iso)
            {
            case System.Data.IsolationLevel.Unspecified:
                readCommitted = TdsEnums.TransactionManagerIsolationLevel.Unspecified;
                break;

            case System.Data.IsolationLevel.Chaos:
                throw SQL.NotSupportedIsolationLevel(iso);

            case System.Data.IsolationLevel.ReadUncommitted:
                readCommitted = TdsEnums.TransactionManagerIsolationLevel.ReadUncommitted;
                break;

            case System.Data.IsolationLevel.Serializable:
                readCommitted = TdsEnums.TransactionManagerIsolationLevel.Serializable;
                break;

            case System.Data.IsolationLevel.Snapshot:
                readCommitted = TdsEnums.TransactionManagerIsolationLevel.Snapshot;
                break;

            case System.Data.IsolationLevel.ReadCommitted:
                readCommitted = TdsEnums.TransactionManagerIsolationLevel.ReadCommitted;
                break;

            case System.Data.IsolationLevel.RepeatableRead:
                readCommitted = TdsEnums.TransactionManagerIsolationLevel.RepeatableRead;
                break;

            default:
                throw ADP.InvalidIsolationLevel(iso);
            }
            TdsParserStateObject session = this._parser._physicalStateObj;
            TdsParser            parser  = this._parser;
            bool flag      = false;
            bool lockTaken = false;

            try
            {
                switch (transactionRequest)
                {
                case SqlInternalConnection.TransactionRequest.Begin:
                    begin = TdsEnums.TransactionManagerRequestType.Begin;
                    break;

                case SqlInternalConnection.TransactionRequest.Promote:
                    begin = TdsEnums.TransactionManagerRequestType.Promote;
                    break;

                case SqlInternalConnection.TransactionRequest.Commit:
                    begin = TdsEnums.TransactionManagerRequestType.Commit;
                    break;

                case SqlInternalConnection.TransactionRequest.Rollback:
                case SqlInternalConnection.TransactionRequest.IfRollback:
                    begin = TdsEnums.TransactionManagerRequestType.Rollback;
                    break;

                case SqlInternalConnection.TransactionRequest.Save:
                    begin = TdsEnums.TransactionManagerRequestType.Save;
                    break;
                }
                if ((internalTransaction != null) && internalTransaction.IsDelegated)
                {
                    if (!this._parser.MARSOn)
                    {
                        if (internalTransaction.OpenResultsCount != 0)
                        {
                            throw SQL.CannotCompleteDelegatedTransactionWithOpenResults();
                        }
                        Monitor.Enter(session, ref lockTaken);
                        if (internalTransaction.OpenResultsCount != 0)
                        {
                            throw SQL.CannotCompleteDelegatedTransactionWithOpenResults();
                        }
                    }
                    else
                    {
                        session = this._parser.GetSession(this);
                        flag    = true;
                    }
                }
                this._parser.TdsExecuteTransactionManagerRequest(null, begin, transactionName, readCommitted, base.ConnectionOptions.ConnectTimeout, internalTransaction, session, isDelegateControlRequest);
            }
            finally
            {
                if (flag)
                {
                    parser.PutSession(session);
                }
                if (lockTaken)
                {
                    Monitor.Exit(session);
                }
            }
        }
Exemplo n.º 17
0
        // Write mars header data, not including the mars header length
        private void WriteMarsHeaderData(TdsParserStateObject stateObj, SqlInternalTransaction transaction)
        {
            // Function to send over additional payload header data for Yukon and beyond only.

            // These are not necessary - can have local started in distributed.
            // Debug.Assert(!(null != sqlTransaction && null != distributedTransaction), "Error to have local (api started) and distributed transaction at the same time!");
            // Debug.Assert(!(null != _userStartedLocalTransaction && null != distributedTransaction), "Error to have local (started outside of the api) and distributed transaction at the same time!");

            // We may need to update the mars header length if mars header is changed in the future

            WriteShort(TdsEnums.HEADERTYPE_MARS, stateObj);

            if (null != transaction && SqlInternalTransaction.NullTransactionId != transaction.TransactionId)
            {
                WriteLong(transaction.TransactionId, stateObj);
                WriteInt(stateObj.IncrementAndObtainOpenResultCount(transaction), stateObj);
            }
            else
            {
                WriteLong(SqlInternalTransaction.NullTransactionId, stateObj);
                WriteInt(stateObj.IncrementAndObtainOpenResultCount(null), stateObj);
            }
        }
Exemplo n.º 18
0
 abstract internal void ExecuteTransaction(TransactionRequest transactionRequest, string name, IsolationLevel iso, SqlInternalTransaction internalTransaction);
Exemplo n.º 19
0
        ////////////////////////////////////////////////////////////////////////////////////////
        // INTERNAL METHODS
        ////////////////////////////////////////////////////////////////////////////////////////

        internal void Zombie() {
            // SQLBUDT #402544 For Yukon, we have to defer "zombification" until
            //                 we get past the users' next rollback, else we'll
            //                 throw an exception there that is a breaking change.
            //                 Of course, if the connection is aready closed, 
            //                 then we're free to zombify...
            SqlInternalConnection internalConnection = (_connection.InnerConnection as SqlInternalConnection);
            if (null != internalConnection && internalConnection.IsYukonOrNewer && !_isFromAPI) {
                if (Bid.AdvancedOn) {
                    Bid.Trace("<sc.SqlTransaction.Zombie|ADV> %d# yukon deferred zombie\n", ObjectID);
                }
            }
            else {
                _internalTransaction = null; // pre-yukon zombification
            }
            
        }
Exemplo n.º 20
0
        // Main parse loop for the top-level tds tokens, calls back into the I*Handler interfaces
        internal bool TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, out bool dataReady)
        {
            Debug.Assert((SniContext.Undefined != stateObj.SniContext) &&       // SniContext must not be Undefined
                ((stateObj._attentionSent) || ((SniContext.Snix_Execute != stateObj.SniContext) && (SniContext.Snix_SendRows != stateObj.SniContext))),  // SniContext should not be Execute or SendRows unless attention was sent (and, therefore, we are looking for an ACK)
                        String.Format("Unexpected SniContext on call to TryRun; SniContext={0}", stateObj.SniContext));

            if (TdsParserState.Broken == State || TdsParserState.Closed == State)
            {
                dataReady = true;
                return true; // Just in case this is called in a loop, expecting data to be returned.
            }

            dataReady = false;

            do
            {
                // If there is data ready, but we didn't exit the loop, then something is wrong
                Debug.Assert(!dataReady, "dataReady not expected - did we forget to skip the row?");

                if (stateObj._internalTimeout)
                {
                    runBehavior = RunBehavior.Attention;
                }

                if (TdsParserState.Broken == State || TdsParserState.Closed == State)
                    break; // jump out of the loop if the state is already broken or closed.

                if (!stateObj._accumulateInfoEvents && (stateObj._pendingInfoEvents != null))
                {
                    if (RunBehavior.Clean != (RunBehavior.Clean & runBehavior))
                    {
                        SqlConnection connection = null;
                        if (_connHandler != null)
                            connection = _connHandler.Connection; // SqlInternalConnection holds the user connection object as a weak ref
                        // We are omitting checks for error.Class in the code below (see processing of INFO) since we know (and assert) that error class
                        // error.Class < TdsEnums.MIN_ERROR_CLASS for info message. 
                        // Also we know that TdsEnums.MIN_ERROR_CLASS<TdsEnums.MAX_USER_CORRECTABLE_ERROR_CLASS
                        if ((connection != null) && connection.FireInfoMessageEventOnUserErrors)
                        {
                            foreach (SqlError error in stateObj._pendingInfoEvents)
                                FireInfoMessageEvent(connection, stateObj, error);
                        }
                        else
                            foreach (SqlError error in stateObj._pendingInfoEvents)
                                stateObj.AddWarning(error);
                    }
                    stateObj._pendingInfoEvents = null;
                }

                byte token;
                if (!stateObj.TryReadByte(out token))
                {
                    return false;
                }

                if (!IsValidTdsToken(token))
                {
                    Debug.Assert(false, String.Format((IFormatProvider)null, "unexpected token; token = {0,-2:X2}", token));
                    _state = TdsParserState.Broken;
                    _connHandler.BreakConnection();
                    throw SQL.ParsingError();
                }

                int tokenLength;
                if (!TryGetTokenLength(token, stateObj, out tokenLength))
                {
                    return false;
                }

                switch (token)
                {
                    case TdsEnums.SQLERROR:
                    case TdsEnums.SQLINFO:
                        {
                            if (token == TdsEnums.SQLERROR)
                            {
                                stateObj._errorTokenReceived = true; // Keep track of the fact error token was received - for Done processing.
                            }

                            SqlError error;
                            if (!TryProcessError(token, stateObj, out error))
                            {
                                return false;
                            }

                            if (token == TdsEnums.SQLINFO && stateObj._accumulateInfoEvents)
                            {
                                Debug.Assert(error.Class < TdsEnums.MIN_ERROR_CLASS, "INFO with class > TdsEnums.MIN_ERROR_CLASS");

                                if (stateObj._pendingInfoEvents == null)
                                    stateObj._pendingInfoEvents = new List<SqlError>();
                                stateObj._pendingInfoEvents.Add(error);
                                stateObj._syncOverAsync = true;
                                break;
                            }

                            if (RunBehavior.Clean != (RunBehavior.Clean & runBehavior))
                            {
                                // If FireInfoMessageEventOnUserErrors is true, we have to fire event without waiting.
                                // Otherwise we can go ahead and add it to errors/warnings collection.
                                SqlConnection connection = null;
                                if (_connHandler != null)
                                    connection = _connHandler.Connection; // SqlInternalConnection holds the user connection object as a weak ref

                                if ((connection != null) &&
                                    (connection.FireInfoMessageEventOnUserErrors == true) &&
                                    (error.Class <= TdsEnums.MAX_USER_CORRECTABLE_ERROR_CLASS))
                                {
                                    // Fire SqlInfoMessage here
                                    FireInfoMessageEvent(connection, stateObj, error);
                                }
                                else
                                {
                                    // insert error/info into the appropriate exception - warning if info, exception if error
                                    if (error.Class < TdsEnums.MIN_ERROR_CLASS)
                                    {
                                        stateObj.AddWarning(error);
                                    }
                                    else if (error.Class < TdsEnums.FATAL_ERROR_CLASS)
                                    {
                                        // Continue results processing for all non-fatal errors (<20)

                                        stateObj.AddError(error);

                                        // Add it to collection - but do NOT change run behavior UNLESS
                                        // we are in an ExecuteReader call - at which time we will be throwing
                                        // anyways so we need to consume all errors.  This is not the case
                                        // if we have already given out a reader.  If we have already given out
                                        // a reader we need to throw the error but not halt further processing.  We used to
                                        // halt processing.

                                        if (null != dataStream)
                                        {
                                            if (!dataStream.IsInitialized)
                                            {
                                                runBehavior = RunBehavior.UntilDone;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        stateObj.AddError(error);

                                        // Else we have a fatal error and we need to change the behavior
                                        // since we want the complete error information in the exception.
                                        // Besides - no further results will be received.
                                        runBehavior = RunBehavior.UntilDone;
                                    }
                                }
                            }
                            else if (error.Class >= TdsEnums.FATAL_ERROR_CLASS)
                            {
                                stateObj.AddError(error);
                            }
                            break;
                        }

                    case TdsEnums.SQLCOLINFO:
                        {
                            if (null != dataStream)
                            {
                                _SqlMetaDataSet metaDataSet;
                                if (!TryProcessColInfo(dataStream.MetaData, dataStream, stateObj, out metaDataSet))
                                {
                                    return false;
                                }
                                if (!dataStream.TrySetMetaData(metaDataSet, false))
                                {
                                    return false;
                                }
                                dataStream.BrowseModeInfoConsumed = true;
                            }
                            else
                            { // no dataStream
                                if (!stateObj.TrySkipBytes(tokenLength))
                                {
                                    return false;
                                }
                            }
                            break;
                        }

                    case TdsEnums.SQLDONE:
                    case TdsEnums.SQLDONEPROC:
                    case TdsEnums.SQLDONEINPROC:
                        {
                            // RunBehavior can be modified
                            if (!TryProcessDone(cmdHandler, dataStream, ref runBehavior, stateObj))
                            {
                                return false;
                            }
                            if ((token == TdsEnums.SQLDONEPROC) && (cmdHandler != null))
                            {
                                cmdHandler.OnDoneProc();
                            }

                            break;
                        }

                    case TdsEnums.SQLORDER:
                        {
                            // don't do anything with the order token so read off the pipe
                            if (!stateObj.TrySkipBytes(tokenLength))
                            {
                                return false;
                            }
                            break;
                        }

                    case TdsEnums.SQLALTMETADATA:
                        {
                            stateObj.CloneCleanupAltMetaDataSetArray();

                            if (stateObj._cleanupAltMetaDataSetArray == null)
                            {
                                // create object on demand (lazy creation)
                                stateObj._cleanupAltMetaDataSetArray = new _SqlMetaDataSetCollection();
                            }

                            _SqlMetaDataSet cleanupAltMetaDataSet;
                            if (!TryProcessAltMetaData(tokenLength, stateObj, out cleanupAltMetaDataSet))
                            {
                                return false;
                            }

                            stateObj._cleanupAltMetaDataSetArray.SetAltMetaData(cleanupAltMetaDataSet);
                            if (null != dataStream)
                            {
                                byte metadataConsumedByte;
                                if (!stateObj.TryPeekByte(out metadataConsumedByte))
                                {
                                    return false;
                                }
                                if (!dataStream.TrySetAltMetaDataSet(cleanupAltMetaDataSet, (TdsEnums.SQLALTMETADATA != metadataConsumedByte)))
                                {
                                    return false;
                                }
                            }

                            break;
                        }

                    case TdsEnums.SQLALTROW:
                        {
                            if (!stateObj.TryStartNewRow(isNullCompressed: false))
                            { // altrows are not currently null compressed
                                return false;
                            }

                            // read will call run until dataReady. Must not read any data if returnimmetiately set
                            if (RunBehavior.ReturnImmediately != (RunBehavior.ReturnImmediately & runBehavior))
                            {
                                ushort altRowId;
                                if (!stateObj.TryReadUInt16(out altRowId))
                                { // get altRowId
                                    return false;
                                }

                                if (!TrySkipRow(stateObj._cleanupAltMetaDataSetArray.GetAltMetaData(altRowId), stateObj))
                                { // skip altRow
                                    return false;
                                }
                            }
                            else
                            {
                                dataReady = true;
                            }

                            break;
                        }

                    case TdsEnums.SQLENVCHANGE:
                        {
                            // ENVCHANGE must be processed synchronously (since it can modify the state of many objects)
                            stateObj._syncOverAsync = true;

                            SqlEnvChange[] env;
                            if (!TryProcessEnvChange(tokenLength, stateObj, out env))
                            {
                                return false;
                            }

                            for (int ii = 0; ii < env.Length; ii++)
                            {
                                if (env[ii] != null && !this.Connection.IgnoreEnvChange)
                                {
                                    switch (env[ii].type)
                                    {
                                        case TdsEnums.ENV_BEGINTRAN:
                                            // 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 = env[ii].newLongValue;   // this is defined as a ULongLong in the server and in the TDS Spec.
                                            }
                                            else
                                            {
                                                TransactionType transactionType = TransactionType.LocalFromTSQL;
                                                _currentTransaction = new SqlInternalTransaction(_connHandler, transactionType, null, env[ii].newLongValue);
                                            }
                                            if (null != _statistics && !_statisticsIsInTransaction)
                                            {
                                                _statistics.SafeIncrement(ref _statistics._transactions);
                                            }
                                            _statisticsIsInTransaction = true;
                                            break;
                                        case TdsEnums.ENV_COMMITTRAN:
                                            // SQLHOT 483
                                            //  Must clear the retain id if the server-side transaction ends by anything other
                                            //  than rollback.
                                            goto case TdsEnums.ENV_ROLLBACKTRAN;
                                        case TdsEnums.ENV_ROLLBACKTRAN:
                                            // 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 (SqlInternalTransaction.NullTransactionId != _currentTransaction.TransactionId)
                                                {
                                                    Debug.Assert(_currentTransaction.TransactionId != env[ii].newLongValue, "transaction id's are not equal!");
                                                }
#endif

                                                if (TdsEnums.ENV_COMMITTRAN == env[ii].type)
                                                {
                                                    _currentTransaction.Completed(TransactionState.Committed);
                                                }
                                                else if (TdsEnums.ENV_ROLLBACKTRAN == env[ii].type)
                                                {
                                                    //  Hold onto transaction id if distributed tran is rolled back.  This must
                                                    //  be sent to the server on subsequent executions even though the transaction
                                                    //  is considered to be rolled back.
                                                    _currentTransaction.Completed(TransactionState.Aborted);
                                                }
                                                else
                                                {
                                                    _currentTransaction.Completed(TransactionState.Unknown);
                                                }
                                                _currentTransaction = null;
                                            }
                                            _statisticsIsInTransaction = false;
                                            break;
                                        case TdsEnums.ENV_ENLISTDTC:
                                        case TdsEnums.ENV_DEFECTDTC:
                                        case TdsEnums.ENV_TRANSACTIONENDED:
                                            Debug.Assert(false, "Should have thrown if DTC token encountered");
                                            break;
                                        default:
                                            _connHandler.OnEnvChange(env[ii]);
                                            break;
                                    }
                                }
                            }
                            break;
                        }
                    case TdsEnums.SQLLOGINACK:
                        {
                            SqlLoginAck ack;
                            if (!TryProcessLoginAck(stateObj, out ack))
                            {
                                return false;
                            }

                            _connHandler.OnLoginAck(ack);
                            break;
                        }
                    case TdsEnums.SQLFEATUREEXTACK:
                        {
                            if (!TryProcessFeatureExtAck(stateObj))
                            {
                                return false;
                            }
                            break;
                        }
                    case TdsEnums.SQLSESSIONSTATE:
                        {
                            if (!TryProcessSessionState(stateObj, tokenLength, _connHandler._currentSessionData))
                            {
                                return false;
                            }
                            break;
                        }
                    case TdsEnums.SQLCOLMETADATA:
                        {
                            if (tokenLength != TdsEnums.VARNULL)
                            {
                                _SqlMetaDataSet metadata;
                                if (!TryProcessMetaData(tokenLength, stateObj, out metadata))
                                {
                                    return false;
                                }
                                stateObj._cleanupMetaData = metadata;
                            }
                            else
                            {
                                if (cmdHandler != null)
                                {
                                    stateObj._cleanupMetaData = cmdHandler.MetaData;
                                }
                            }

                            if (null != dataStream)
                            {
                                byte peekedToken;
                                if (!stateObj.TryPeekByte(out peekedToken))
                                { // temporarily cache next byte
                                    return false;
                                }

                                if (!dataStream.TrySetMetaData(stateObj._cleanupMetaData, (TdsEnums.SQLTABNAME == peekedToken || TdsEnums.SQLCOLINFO == peekedToken)))
                                {
                                    return false;
                                }
                            }
                            else if (null != bulkCopyHandler)
                            {
                                bulkCopyHandler.SetMetaData(stateObj._cleanupMetaData);
                            }
                            break;
                        }
                    case TdsEnums.SQLROW:
                    case TdsEnums.SQLNBCROW:
                        {
                            Debug.Assert(stateObj._cleanupMetaData != null, "Reading a row, but the metadata is null");

                            if (token == TdsEnums.SQLNBCROW)
                            {
                                if (!stateObj.TryStartNewRow(isNullCompressed: true, nullBitmapColumnsCount: stateObj._cleanupMetaData.Length))
                                {
                                    return false;
                                }
                            }
                            else
                            {
                                if (!stateObj.TryStartNewRow(isNullCompressed: false))
                                {
                                    return false;
                                }
                            }

                            if (null != bulkCopyHandler)
                            {
                                if (!TryProcessRow(stateObj._cleanupMetaData, bulkCopyHandler.CreateRowBuffer(), bulkCopyHandler.CreateIndexMap(), stateObj))
                                {
                                    return false;
                                }
                            }
                            else if (RunBehavior.ReturnImmediately != (RunBehavior.ReturnImmediately & runBehavior))
                            {
                                if (!TrySkipRow(stateObj._cleanupMetaData, stateObj))
                                { // skip rows
                                    return false;
                                }
                            }
                            else
                            {
                                dataReady = true;
                            }

                            if (_statistics != null)
                            {
                                _statistics.WaitForDoneAfterRow = true;
                            }
                            break;
                        }
                    case TdsEnums.SQLRETURNSTATUS:
                        int status;
                        if (!stateObj.TryReadInt32(out status))
                        {
                            return false;
                        }
                        if (cmdHandler != null)
                        {
                            cmdHandler.OnReturnStatus(status);
                        }
                        break;
                    case TdsEnums.SQLRETURNVALUE:
                        {
                            SqlReturnValue returnValue;
                            if (!TryProcessReturnValue(tokenLength, stateObj, out returnValue))
                            {
                                return false;
                            }
                            if (cmdHandler != null)
                            {
                                cmdHandler.OnReturnValue(returnValue);
                            }
                            break;
                        }
                    case TdsEnums.SQLSSPI:
                        {
                            // token length is length of SSPI data - call ProcessSSPI with it

                            Debug.Assert(stateObj._syncOverAsync, "ProcessSSPI does not support retry, do not attempt asynchronously");
                            stateObj._syncOverAsync = true;

                            ProcessSSPI(tokenLength);
                            break;
                        }
                    case TdsEnums.SQLTABNAME:
                        {
                            {
                                if (!stateObj.TrySkipBytes(tokenLength))
                                {
                                    return false;
                                }
                            }
                            break;
                        }

                    default:
                        Debug.Assert(false, "Unhandled token:  " + token.ToString(CultureInfo.InvariantCulture));
                        break;
                }

                Debug.Assert(stateObj._pendingData || !dataReady, "dataReady is set, but there is no pending data");
            }

            // Loop while data pending & runbehavior not return immediately, OR
            // if in attention case, loop while no more pending data & attention has not yet been
            // received.
            while ((stateObj._pendingData &&
                    (RunBehavior.ReturnImmediately != (RunBehavior.ReturnImmediately & runBehavior))) ||
                (!stateObj._pendingData && stateObj._attentionSent && !stateObj._attentionReceived));

#if DEBUG
            if ((stateObj._pendingData) && (!dataReady))
            {
                byte token;
                if (!stateObj.TryPeekByte(out token))
                {
                    return false;
                }
                Debug.Assert(IsValidTdsToken(token), string.Format("DataReady is false, but next token is not valid: {0,-2:X2}", token));
            }
#endif

            if (!stateObj._pendingData)
            {
                if (null != CurrentTransaction)
                {
                    CurrentTransaction.Activate();
                }
            }

            // if we recieved an attention (but this thread didn't send it) then
            // we throw an Operation Cancelled error
            if (stateObj._attentionReceived)
            {
                // Dev11 #344723: SqlClient stress hang System_Data!Tcp::ReadSync via a call to SqlDataReader::Close
                // Spin until SendAttention has cleared _attentionSending, this prevents a race condition between receiving the attention ACK and setting _attentionSent
                SpinWait.SpinUntil(() => !stateObj._attentionSending);

                Debug.Assert(stateObj._attentionSent, "Attention ACK has been received without attention sent");
                if (stateObj._attentionSent)
                {
                    // Reset attention state.
                    stateObj._attentionSent = false;
                    stateObj._attentionReceived = false;

                    if (RunBehavior.Clean != (RunBehavior.Clean & runBehavior) && !stateObj._internalTimeout)
                    {
                        // Add attention error to collection - if not RunBehavior.Clean!
                        stateObj.AddError(new SqlError(0, 0, TdsEnums.MIN_ERROR_CLASS, _server, SQLMessage.OperationCancelled(), "", 0));
                    }
                }
            }

            if (stateObj.HasErrorOrWarning)
            {
                ThrowExceptionAndWarning(stateObj);
            }
            return true;
        }
Exemplo n.º 21
0
        internal void ExecuteTransactionYukon(
                    TransactionRequest transactionRequest,
                    string transactionName,
                    IsolationLevel iso,
                    SqlInternalTransaction internalTransaction
        )
        {
            TdsEnums.TransactionManagerRequestType requestType = TdsEnums.TransactionManagerRequestType.Begin;
            TdsEnums.TransactionManagerIsolationLevel isoLevel = TdsEnums.TransactionManagerIsolationLevel.ReadCommitted;

            switch (iso)
            {
                case IsolationLevel.Unspecified:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.Unspecified;
                    break;
                case IsolationLevel.ReadCommitted:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.ReadCommitted;
                    break;
                case IsolationLevel.ReadUncommitted:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.ReadUncommitted;
                    break;
                case IsolationLevel.RepeatableRead:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.RepeatableRead;
                    break;
                case IsolationLevel.Serializable:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.Serializable;
                    break;
                case IsolationLevel.Snapshot:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.Snapshot;
                    break;
                case IsolationLevel.Chaos:
                    throw SQL.NotSupportedIsolationLevel(iso);
                default:
                    throw ADP.InvalidIsolationLevel(iso);
            }

            TdsParserStateObject stateObj = _parser._physicalStateObj;
            TdsParser parser = _parser;
            bool mustPutSession = false;
            bool releaseConnectionLock = false;

            Debug.Assert(!ThreadHasParserLockForClose || _parserLock.ThreadMayHaveLock(), "Thread claims to have parser lock, but lock is not taken");
            if (!ThreadHasParserLockForClose)
            {
                _parserLock.Wait(canReleaseFromAnyThread: false);
                ThreadHasParserLockForClose = true;   // In case of error, let the connection know that we already own the parser lock
                releaseConnectionLock = true;
            }
            try
            {
                switch (transactionRequest)
                {
                    case TransactionRequest.Begin:
                        requestType = TdsEnums.TransactionManagerRequestType.Begin;
                        break;
                    case TransactionRequest.Commit:
                        requestType = TdsEnums.TransactionManagerRequestType.Commit;
                        break;
                    case TransactionRequest.IfRollback:
                    // Map IfRollback to Rollback since with Yukon and beyond we should never need
                    // the if since the server will inform us when transactions have completed
                    // as a result of an error on the server.
                    case TransactionRequest.Rollback:
                        requestType = TdsEnums.TransactionManagerRequestType.Rollback;
                        break;
                    case TransactionRequest.Save:
                        requestType = TdsEnums.TransactionManagerRequestType.Save;
                        break;
                    default:
                        Debug.Assert(false, "Unknown transaction type");
                        break;
                }

                // only restore if connection lock has been taken within the function
                if (internalTransaction != null && internalTransaction.RestoreBrokenConnection && releaseConnectionLock)
                {
                    Task reconnectTask = internalTransaction.Parent.Connection.ValidateAndReconnect(() =>
                    {
                        ThreadHasParserLockForClose = false;
                        _parserLock.Release();
                        releaseConnectionLock = false;
                    }, 0);
                    if (reconnectTask != null)
                    {
                        AsyncHelper.WaitForCompletion(reconnectTask, 0); // there is no specific timeout for BeginTransaction, uses ConnectTimeout
                        internalTransaction.ConnectionHasBeenRestored = true;
                        return;
                    }
                }




                //  _parser may be nulled out during TdsExecuteTrannsactionManagerRequest.
                //  Only use local variable after this call.
                _parser.TdsExecuteTransactionManagerRequest(null, requestType, transactionName, isoLevel,
                    ConnectionOptions.ConnectTimeout, internalTransaction, stateObj
                    );
            }
            finally
            {
                if (mustPutSession)
                {
                    parser.PutSession(stateObj);
                }

                if (releaseConnectionLock)
                {
                    ThreadHasParserLockForClose = false;
                    _parserLock.Release();
                }
            }
        }
Exemplo n.º 22
0
        internal Int32 IncrementAndObtainOpenResultCount(SqlInternalTransaction transaction)
        {
            _hasOpenResult = true;

            if (transaction == null)
            {
                // If we are not passed a transaction, we are not executing under a transaction
                // and thus we should increment the global connection result count.
                return _parser.IncrementNonTransactedOpenResultCount();
            }
            else
            {
                // If we are passed a transaction, we are executing under a transaction
                // and thus we should increment the transaction's result count.
                _executedUnderTransaction = transaction;
                return transaction.IncrementAndObtainOpenResultCount();
            }
        }
        override internal void ExecuteTransaction(
            TransactionRequest transactionRequest,
            string transactionName,
            IsolationLevel iso,
            SqlInternalTransaction internalTransaction,
            bool isDelegateControlRequest)
        {
            if (Bid.AdvancedOn)
            {
                Bid.Trace("<sc.SqlInternalConnectionSmi.ExecuteTransaction|ADV> %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();
        }
Exemplo n.º 24
0
 abstract internal void ExecuteTransaction(TransactionRequest transactionRequest, string name, IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest);
 private void ZombieCheck()
 {
     if (this.IsZombied)
     {
         if (this.IsYukonPartialZombie)
         {
             this._internalTransaction = null;
         }
         throw ADP.TransactionZombied(this);
     }
 }
Exemplo n.º 26
0
        public void Initialize() {
            // if we get here, then we know for certain that we're the delegated
            // transaction.
            SqlInternalConnection connection = _connection;
            SqlConnection usersConnection = connection.Connection;

            Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, delegating transaction.\n", ObjectID, connection.ObjectID);
            
            RuntimeHelpers.PrepareConstrainedRegions();
            try {
#if DEBUG
                TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();

                RuntimeHelpers.PrepareConstrainedRegions();
                try {
                    tdsReliabilitySection.Start();
#else
                {
#endif //DEBUG
                    if (connection.IsEnlistedInTransaction) { // defect first
                        Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, was enlisted, now defecting.\n", ObjectID, connection.ObjectID);
                        connection.EnlistNull();
                    }

                    _internalTransaction = new SqlInternalTransaction(connection, TransactionType.Delegated, null);

                    connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Begin, null, _isolationLevel, _internalTransaction, true);

                    // Handle case where ExecuteTran didn't produce a new transaction, but also didn't throw.
                    if (null == connection.CurrentTransaction)
                    {
                        connection.DoomThisConnection();
                        throw ADP.InternalError(ADP.InternalErrorCode.UnknownTransactionFailure);
                    }

                    _active = true;
                }
#if DEBUG
                finally {
                    tdsReliabilitySection.Stop();
                }
#endif //DEBUG
            }
            catch (System.OutOfMemoryException e) {
                usersConnection.Abort(e);
                throw;
            }
            catch (System.StackOverflowException e) {
                usersConnection.Abort(e);
                throw;
            }
            catch (System.Threading.ThreadAbortException e)  {
                usersConnection.Abort(e);
                throw;
            }
        }
 internal void Zombie()
 {
     SqlInternalConnection innerConnection = this._connection.InnerConnection as SqlInternalConnection;
     if (((innerConnection != null) && innerConnection.IsYukonOrNewer) && !this._isFromAPI)
     {
         if (Bid.AdvancedOn)
         {
             Bid.Trace("<sc.SqlTransaction.Zombie|ADV> %d# yukon deferred zombie\n", this.ObjectID);
         }
     }
     else
     {
         this._internalTransaction = null;
     }
 }
Exemplo n.º 28
0
        override public void Rollback()
        {
            Exception e = null;
            Guid operationId = s_diagnosticListener.WriteTransactionRollbackBefore(_isolationLevel, _connection, null);

            if (IsYukonPartialZombie)
            {
                // Put something in the trace in case a customer has an issue
                _internalTransaction = null; // yukon zombification
            }
            else
            {
                ZombieCheck();

                SqlStatistics statistics = null;
                try
                {
                    statistics = SqlStatistics.StartTimer(Statistics);

                    _isFromAPI = true;

                    _internalTransaction.Rollback();
                }
                catch (Exception ex)
                {
                    e = ex;
                    throw;
                }
                finally
                {
                    if (e != null)
                    {
                        s_diagnosticListener.WriteTransactionRollbackError(operationId, _isolationLevel, _connection, null, e);
                    }
                    else
                    {
                        s_diagnosticListener.WriteTransactionRollbackAfter(operationId, _isolationLevel, _connection, null);
                    }
                    _isFromAPI = false;

                    SqlStatistics.StopTimer(statistics);
                }
            }
        }
 public override void Rollback()
 {
     if (this.IsYukonPartialZombie)
     {
         if (Bid.AdvancedOn)
         {
             Bid.Trace("<sc.SqlTransaction.Rollback|ADV> %d# partial zombie no rollback required\n", this.ObjectID);
         }
         this._internalTransaction = null;
     }
     else
     {
         IntPtr ptr;
         this.ZombieCheck();
         SqlStatistics statistics = null;
         Bid.ScopeEnter(out ptr, "<sc.SqlTransaction.Rollback|API> %d#", this.ObjectID);
         SNIHandle target = null;
         RuntimeHelpers.PrepareConstrainedRegions();
         try
         {
             target = SqlInternalConnection.GetBestEffortCleanupTarget(this._connection);
             statistics = SqlStatistics.StartTimer(this.Statistics);
             this._isFromAPI = true;
             this._internalTransaction.Rollback();
         }
         catch (OutOfMemoryException exception3)
         {
             this._connection.Abort(exception3);
             throw;
         }
         catch (StackOverflowException exception2)
         {
             this._connection.Abort(exception2);
             throw;
         }
         catch (ThreadAbortException exception)
         {
             this._connection.Abort(exception);
             SqlInternalConnection.BestEffortCleanup(target);
             throw;
         }
         finally
         {
             this._isFromAPI = false;
             SqlStatistics.StopTimer(statistics);
             Bid.ScopeLeave(ref ptr);
         }
     }
 }
 internal void DecrementOpenResultCount()
 {
     if (this._executedUnderTransaction == null)
     {
         this._parser.DecrementNonTransactedOpenResultCount();
     }
     else
     {
         this._executedUnderTransaction.DecrementAndObtainOpenResultCount();
         this._executedUnderTransaction = null;
     }
     this._hasOpenResult = false;
 }
Exemplo n.º 31
0
        override public void Rollback() {
            if (IsYukonPartialZombie) {
                // Put something in the trace in case a customer has an issue
                if (Bid.AdvancedOn) {
                    Bid.Trace("<sc.SqlTransaction.Rollback|ADV> %d# partial zombie no rollback required\n", ObjectID);
                }
                _internalTransaction = null; // yukon zombification
            }
            else {
                ZombieCheck();

                SqlStatistics statistics = null;
                IntPtr hscp;
                Bid.ScopeEnter(out hscp, "<sc.SqlTransaction.Rollback|API> %d#", ObjectID);
                Bid.CorrelationTrace("<sc.SqlTransaction.Rollback|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);

                TdsParser bestEffortCleanupTarget = null;
                RuntimeHelpers.PrepareConstrainedRegions();
                try {
#if DEBUG
                    TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();

                    RuntimeHelpers.PrepareConstrainedRegions();
                    try {
                        tdsReliabilitySection.Start();
#else
                    {
#endif //DEBUG
                        bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection);
                        statistics = SqlStatistics.StartTimer(Statistics);

                        _isFromAPI = true;
                        
                        _internalTransaction.Rollback();
                    }
#if DEBUG
                    finally {
                        tdsReliabilitySection.Stop();
                    }
#endif //DEBUG
                }
                catch (System.OutOfMemoryException e) {
                    _connection.Abort(e);
                    throw;
                }
                catch (System.StackOverflowException e) {
                    _connection.Abort(e);
                    throw;
                }
                catch (System.Threading.ThreadAbortException e)  {
                    _connection.Abort(e);
                    SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
                    throw;
                }
                finally {
                    _isFromAPI = false;
                    
                    SqlStatistics.StopTimer(statistics);
                    Bid.ScopeLeave(ref hscp);
                }
            }
        }
 internal int IncrementAndObtainOpenResultCount(SqlInternalTransaction transaction)
 {
     this._hasOpenResult = true;
     if (transaction == null)
     {
         return this._parser.IncrementNonTransactedOpenResultCount();
     }
     this._executedUnderTransaction = transaction;
     return transaction.IncrementAndObtainOpenResultCount();
 }
        ////////////////////////////////////////////////////////////////////////////////////////
        // LOCAL TRANSACTION METHODS
        ////////////////////////////////////////////////////////////////////////////////////////

        override internal void DisconnectTransaction(SqlInternalTransaction internalTransaction) {
            TdsParser parser = Parser;

            if (null != parser) {
                parser.DisconnectTransaction(internalTransaction);
            }
        }
Exemplo n.º 34
0
 internal void DecrementOpenResultCount()
 {
     if (_executedUnderTransaction == null)
     {
         // If we were not executed under a transaction - decrement the global count
         // on the parser.
         _parser.DecrementNonTransactedOpenResultCount();
     }
     else
     {
         // If we were executed under a transaction - decrement the count on the transaction.
         _executedUnderTransaction.DecrementAndObtainOpenResultCount();
         _executedUnderTransaction = null;
     }
     _hasOpenResult = false;
 }
        // This function will not handle idle connection resiliency, as older servers will not support it
        internal void ExecuteTransactionPreYukon(
                    TransactionRequest      transactionRequest, 
                    string                  transactionName, 
                    IsolationLevel          iso, 
                    SqlInternalTransaction  internalTransaction) {
            StringBuilder sqlBatch = new StringBuilder();

            switch (iso) {
                case IsolationLevel.Unspecified:
                    break;
                case IsolationLevel.ReadCommitted:
                    sqlBatch.Append(TdsEnums.TRANS_READ_COMMITTED);
                    sqlBatch.Append(";");
                    break;
                case IsolationLevel.ReadUncommitted:
                    sqlBatch.Append(TdsEnums.TRANS_READ_UNCOMMITTED);
                    sqlBatch.Append(";");
                    break;
                case IsolationLevel.RepeatableRead:
                    sqlBatch.Append(TdsEnums.TRANS_REPEATABLE_READ);
                    sqlBatch.Append(";");
                    break;
                case IsolationLevel.Serializable:
                    sqlBatch.Append(TdsEnums.TRANS_SERIALIZABLE);
                    sqlBatch.Append(";");
                    break;
                case IsolationLevel.Snapshot:
                    throw SQL.SnapshotNotSupported(IsolationLevel.Snapshot);

                case IsolationLevel.Chaos:
                    throw SQL.NotSupportedIsolationLevel(iso);

                default:
                    throw ADP.InvalidIsolationLevel(iso);
            }

            if (!ADP.IsEmpty(transactionName)) {
                transactionName = " " + SqlConnection.FixupDatabaseTransactionName(transactionName);
            }
                
            switch (transactionRequest) {
                case TransactionRequest.Begin:
                    sqlBatch.Append(TdsEnums.TRANS_BEGIN);
                    sqlBatch.Append(transactionName);
                    break;
                case TransactionRequest.Promote:
                    Debug.Assert(false, "Promote called with transaction name or on pre-Yukon!");
                    break;
                case TransactionRequest.Commit:
                    sqlBatch.Append(TdsEnums.TRANS_COMMIT);
                    sqlBatch.Append(transactionName);
                    break;
                case TransactionRequest.Rollback:
                    sqlBatch.Append(TdsEnums.TRANS_ROLLBACK);
                    sqlBatch.Append(transactionName);
                    break;
                case TransactionRequest.IfRollback:
                    sqlBatch.Append(TdsEnums.TRANS_IF_ROLLBACK);
                    sqlBatch.Append(transactionName);
                    break;
                case TransactionRequest.Save:
                    sqlBatch.Append(TdsEnums.TRANS_SAVE);
                    sqlBatch.Append(transactionName);
                    break;
                default:
                    Debug.Assert(false, "Unknown transaction type");
                    break;
            }

            Threading.Tasks.Task executeTask = _parser.TdsExecuteSQLBatch(sqlBatch.ToString(), ConnectionOptions.ConnectTimeout, null, _parser._physicalStateObj, sync: true);
            Debug.Assert(executeTask == null, "Shouldn't get a task when doing sync writes");            
            _parser.Run(RunBehavior.UntilDone, null, null, null, _parser._physicalStateObj);

            // Prior to Yukon, we didn't have any transaction tokens to manage,
            // or any feedback to know when one was created, so we just presume
            // that successful execution of the request caused the transaction
            // to be created, and we set that on the parser.
            if (TransactionRequest.Begin == transactionRequest) {
                Debug.Assert(null != internalTransaction, "Begin Transaction request without internal transaction");
                _parser.CurrentTransaction = internalTransaction;
            }
        }
Exemplo n.º 36
0
        ////////////////////////////////////////////////////////////////////////////////////////
        // INTERNAL METHODS
        ////////////////////////////////////////////////////////////////////////////////////////

        internal void Zombie()
        {
            // For Yukon, we have to defer "zombification" until
            //                 we get past the users' next rollback, else we'll
            //                 throw an exception there that is a breaking change.
            //                 Of course, if the connection is already closed, 
            //                 then we're free to zombify...
            SqlInternalConnection internalConnection = (_connection.InnerConnection as SqlInternalConnection);
            if (internalConnection == null || _isFromAPI)
            {
                _internalTransaction = null; // pre-yukon zombification
            }
        }
 internal abstract void ExecuteTransaction(TransactionRequest transactionRequest, string name, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest);
        internal void ExecuteTransactionYukon(
                    TransactionRequest      transactionRequest, 
                    string                  transactionName, 
                    IsolationLevel          iso, 
                    SqlInternalTransaction  internalTransaction, 
                    bool                    isDelegateControlRequest) {
            TdsEnums.TransactionManagerRequestType    requestType = TdsEnums.TransactionManagerRequestType.Begin;
            TdsEnums.TransactionManagerIsolationLevel isoLevel    = TdsEnums.TransactionManagerIsolationLevel.ReadCommitted;

            switch (iso) {
                case IsolationLevel.Unspecified:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.Unspecified;
                    break;
                case IsolationLevel.ReadCommitted:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.ReadCommitted;
                    break;
                case IsolationLevel.ReadUncommitted:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.ReadUncommitted;
                    break;
                case IsolationLevel.RepeatableRead:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.RepeatableRead;
                    break;
                case IsolationLevel.Serializable:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.Serializable;
                    break;
                case IsolationLevel.Snapshot:
                    isoLevel = TdsEnums.TransactionManagerIsolationLevel.Snapshot;
                    break;
                case IsolationLevel.Chaos:
                    throw SQL.NotSupportedIsolationLevel(iso);
                default:
                    throw ADP.InvalidIsolationLevel(iso);
            }

            TdsParserStateObject stateObj = _parser._physicalStateObj;
            TdsParser parser = _parser;
            bool mustPutSession = false;
            bool releaseConnectionLock = false;

            Debug.Assert(!ThreadHasParserLockForClose || _parserLock.ThreadMayHaveLock(), "Thread claims to have parser lock, but lock is not taken");           
            if (!ThreadHasParserLockForClose) {
                _parserLock.Wait(canReleaseFromAnyThread:false);
                ThreadHasParserLockForClose = true;   // In case of error, let the connection know that we already own the parser lock
                releaseConnectionLock = true;
            }
            try {
                switch (transactionRequest) {
                    case TransactionRequest.Begin:
                        requestType = TdsEnums.TransactionManagerRequestType.Begin;
                        break;
                    case TransactionRequest.Promote:
                        requestType = TdsEnums.TransactionManagerRequestType.Promote;
                        break;
                    case TransactionRequest.Commit:
                        requestType = TdsEnums.TransactionManagerRequestType.Commit;
                        break;
                    case TransactionRequest.IfRollback:
                        // Map IfRollback to Rollback since with Yukon and beyond we should never need
                        // the if since the server will inform us when transactions have completed
                        // as a result of an error on the server.
                    case TransactionRequest.Rollback:
                        requestType = TdsEnums.TransactionManagerRequestType.Rollback;
                        break;
                    case TransactionRequest.Save:
                        requestType = TdsEnums.TransactionManagerRequestType.Save;
                        break;
                    default:
                        Debug.Assert(false, "Unknown transaction type");
                        break;
                }

                // only restore if connection lock has been taken within the function
                if (internalTransaction != null && internalTransaction.RestoreBrokenConnection && releaseConnectionLock) {
                    Task reconnectTask = internalTransaction.Parent.Connection.ValidateAndReconnect(() => {                      
                        ThreadHasParserLockForClose = false;
                        _parserLock.Release();
                        releaseConnectionLock = false;
                    }, 0);
                    if (reconnectTask != null) {
                        AsyncHelper.WaitForCompletion(reconnectTask, 0); // there is no specific timeout for BeginTransaction, uses ConnectTimeout
                        internalTransaction.ConnectionHasBeenRestored = true;
                        return;
                    }
                }
                    


                // SQLBUDT #20010853 - Promote, Commit and Rollback requests for
                // delegated transactions often happen while there is an open result
                // set, so we need to handle them by using a different MARS session, 
                // otherwise we'll write on the physical state objects while someone
                // else is using it.  When we don't have MARS enabled, we need to 
                // lock the physical state object to syncronize it's use at least 
                // until we increment the open results count.  Once it's been 
                // incremented the delegated transaction requests will fail, so they
                // won't stomp on anything.
                // 
                // We need to keep this lock through the duration of the TM reqeuest
                // so that we won't hijack a different request's data stream and a
                // different request won't hijack ours, so we have a lock here on 
                // an object that the ExecTMReq will also lock, but since we're on
                // the same thread, the lock is a no-op.

                if (null != internalTransaction && internalTransaction.IsDelegated) {
                    if (_parser.MARSOn) {
                        stateObj = _parser.GetSession(this);
                        mustPutSession = true;
                    }
                    else if (internalTransaction.OpenResultsCount != 0) {
                        throw SQL.CannotCompleteDelegatedTransactionWithOpenResults(this);
                    }
                }               

                // SQLBU #406778 - _parser may be nulled out during TdsExecuteTrannsactionManagerRequest.
                //  Only use local variable after this call.
                _parser.TdsExecuteTransactionManagerRequest(null, requestType, transactionName, isoLevel,
                    ConnectionOptions.ConnectTimeout, internalTransaction, stateObj, isDelegateControlRequest);
            }   
            finally {
                if (mustPutSession) {
                    parser.PutSession(stateObj);
                }

                if (releaseConnectionLock) {
                    ThreadHasParserLockForClose = false;
                    _parserLock.Release();
                }
            }
        }
        override public void Rollback()
        {
            if (IsYukonPartialZombie)
            {
                // Put something in the trace in case a customer has an issue
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlTransaction.Rollback|ADV> %d# partial zombie no rollback required\n", ObjectID);
                }
                _internalTransaction = null; // yukon zombification
            }
            else
            {
                ZombieCheck();

                SqlStatistics statistics = null;
                IntPtr        hscp;
                Bid.ScopeEnter(out hscp, "<sc.SqlTransaction.Rollback|API> %d#", ObjectID);
                Bid.CorrelationTrace("<sc.SqlTransaction.Rollback|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);

                TdsParser bestEffortCleanupTarget = null;
                RuntimeHelpers.PrepareConstrainedRegions();
                try {
#if DEBUG
                    TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();

                    RuntimeHelpers.PrepareConstrainedRegions();
                    try {
                        tdsReliabilitySection.Start();
#else
                    {
#endif //DEBUG
                        bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection);
                        statistics = SqlStatistics.StartTimer(Statistics);

                        _isFromAPI = true;

                        _internalTransaction.Rollback();
                    }
#if DEBUG
                    finally {
                        tdsReliabilitySection.Stop();
                    }
#endif //DEBUG
                }
                catch (System.OutOfMemoryException e) {
                    _connection.Abort(e);
                    throw;
                }
                catch (System.StackOverflowException e) {
                    _connection.Abort(e);
                    throw;
                }
                catch (System.Threading.ThreadAbortException e)  {
                    _connection.Abort(e);
                    SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
                    throw;
                }
                finally {
                    _isFromAPI = false;

                    SqlStatistics.StopTimer(statistics);
                    Bid.ScopeLeave(ref hscp);
                }
            }
        }
        override internal void ExecuteTransaction(TransactionRequest transactionRequest, string name, IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest) {
            if (IsConnectionDoomed) {  // doomed means we can't do anything else...
                if (transactionRequest == TransactionRequest.Rollback
                 || transactionRequest == TransactionRequest.IfRollback) {
                    return;
                }
                throw SQL.ConnectionDoomed();
            }

            if (transactionRequest == TransactionRequest.Commit
             || transactionRequest == TransactionRequest.Rollback
             || transactionRequest == TransactionRequest.IfRollback) {
                if (!Parser.MARSOn && Parser._physicalStateObj.BcpLock) {
                    throw SQL.ConnectionLockedForBcpEvent();
                }
            }

            string transactionName = (null == name) ? String.Empty : name;

            if (!_parser.IsYukonOrNewer) {
                ExecuteTransactionPreYukon(transactionRequest, transactionName, iso, internalTransaction);
            }
            else {
                ExecuteTransactionYukon(transactionRequest, transactionName, iso, internalTransaction, isDelegateControlRequest);
            }
        }
Exemplo n.º 41
0
 abstract internal void ExecuteTransaction(TransactionRequest transactionRequest, string name, IsolationLevel iso, SqlInternalTransaction internalTransaction);
Exemplo n.º 42
0
        internal void DisconnectTransaction(SqlInternalTransaction internalTransaction)
        {
            Debug.Assert(_currentTransaction != null && _currentTransaction == internalTransaction, "disconnecting different transaction");

            if (_currentTransaction != null && _currentTransaction == internalTransaction)
            {
                _currentTransaction = null;
            }
        }
Exemplo n.º 43
0
 internal override void ExecuteTransaction(SqlInternalConnection.TransactionRequest transactionRequest, string name, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest)
 {
     if (base.IsConnectionDoomed)
     {
         if ((transactionRequest != SqlInternalConnection.TransactionRequest.Rollback) && (transactionRequest != SqlInternalConnection.TransactionRequest.IfRollback))
         {
             throw SQL.ConnectionDoomed();
         }
     }
     else
     {
         if ((((transactionRequest == SqlInternalConnection.TransactionRequest.Commit) || (transactionRequest == SqlInternalConnection.TransactionRequest.Rollback)) || (transactionRequest == SqlInternalConnection.TransactionRequest.IfRollback)) && (!this.Parser.MARSOn && this.Parser._physicalStateObj.BcpLock))
         {
             throw SQL.ConnectionLockedForBcpEvent();
         }
         string transactionName = (name == null) ? string.Empty : name;
         if (!this._parser.IsYukonOrNewer)
         {
             this.ExecuteTransactionPreYukon(transactionRequest, transactionName, iso, internalTransaction);
         }
         else
         {
             this.ExecuteTransactionYukon(transactionRequest, transactionName, iso, internalTransaction, isDelegateControlRequest);
         }
     }
 }
Exemplo n.º 44
0
        internal SqlDataReader TdsExecuteTransactionManagerRequest(
                    byte[] buffer,
                    TdsEnums.TransactionManagerRequestType request,
                    string transactionName,
                    TdsEnums.TransactionManagerIsolationLevel isoLevel,
                    int timeout,
                    SqlInternalTransaction transaction,
                    TdsParserStateObject stateObj
        )
        {
            Debug.Assert(this == stateObj.Parser, "different parsers");

            if (TdsParserState.Broken == State || TdsParserState.Closed == State)
            {
                return null;
            }

            // Promote, Commit and Rollback requests for
            // delegated transactions often happen while there is an open result
            // set, so we need to handle them by using a different MARS session, 
            // otherwise we'll write on the physical state objects while someone
            // else is using it.  When we don't have MARS enabled, we need to 
            // lock the physical state object to syncronize it's use at least 
            // until we increment the open results count.  Once it's been 
            // incremented the delegated transaction requests will fail, so they
            // won't stomp on anything.


            Debug.Assert(!_connHandler.ThreadHasParserLockForClose || _connHandler._parserLock.ThreadMayHaveLock(), "Thread claims to have parser lock, but lock is not taken");
            bool callerHasConnectionLock = _connHandler.ThreadHasParserLockForClose;   // If the thread already claims to have the parser lock, then we will let the caller handle releasing it
            if (!callerHasConnectionLock)
            {
                _connHandler._parserLock.Wait(canReleaseFromAnyThread: false);
                _connHandler.ThreadHasParserLockForClose = true;
            }
            // Capture _asyncWrite (after taking lock) to restore it afterwards
            bool hadAsyncWrites = _asyncWrite;
            try
            {
                // Temprarily disable async writes
                _asyncWrite = false;


                stateObj._outputMessageType = TdsEnums.MT_TRANS;       // set message type
                stateObj.SetTimeoutSeconds(timeout);

                stateObj.SniContext = SniContext.Snix_Execute;

                const int marsHeaderSize = 18; // 4 + 2 + 8 + 4
                const int totalHeaderLength = 22; // 4 + 4 + 2 + 8 + 4
                Debug.Assert(stateObj._outBytesUsed == stateObj._outputHeaderLen, "Output bytes written before total header length");
                // Write total header length
                WriteInt(totalHeaderLength, stateObj);
                // Write mars header length
                WriteInt(marsHeaderSize, stateObj);
                WriteMarsHeaderData(stateObj, _currentTransaction);

                WriteShort((short)request, stateObj); // write TransactionManager Request type

                bool returnReader = false;

                switch (request)
                {
                    case TdsEnums.TransactionManagerRequestType.Begin:
                        Debug.Assert(null != transaction, "Should have specified an internalTransaction when doing a BeginTransaction request!");

                        // Only assign the passed in transaction if it is not equal to the current transaction.
                        // And, if it is not equal, the current actually should be null.  Anything else
                        // is a unexpected state.  The concern here is mainly for the mixed use of 
                        // T-SQL and API transactions. 

                        // Expected states:
                        // 1) _pendingTransaction = null, _currentTransaction = null, non null transaction
                        // passed in on BeginTransaction API call.
                        // 2) _currentTransaction != null, _pendingTransaction = null, non null transaction
                        // passed in but equivalent to _currentTransaction.

                        // #1 will occur on standard BeginTransactionAPI call.  #2 should only occur if
                        // t-sql transaction started followed by a call to SqlConnection.BeginTransaction.
                        // Any other state is unknown.
                        if (_currentTransaction != transaction)
                        {
                            Debug.Assert(_currentTransaction == null || true == _fResetConnection, "We should not have a current Tx at this point");
                            PendingTransaction = transaction;
                        }

                        stateObj.WriteByte((byte)isoLevel);

                        stateObj.WriteByte((byte)(transactionName.Length * 2)); // Write number of bytes (unicode string).
                        WriteString(transactionName, stateObj);
                        break;
                    case TdsEnums.TransactionManagerRequestType.Commit:

                        Debug.Assert(transactionName.Length == 0, "Should not have a transaction name on Commit");
                        stateObj.WriteByte((byte)0); // No xact name

                        stateObj.WriteByte(0);  // No flags

                        Debug.Assert(isoLevel == TdsEnums.TransactionManagerIsolationLevel.Unspecified, "Should not have isolation level other than unspecified on Commit!");
                        // WriteByte((byte) 0, stateObj); // IsolationLevel
                        // WriteByte((byte) 0, stateObj); // No begin xact name
                        break;
                    case TdsEnums.TransactionManagerRequestType.Rollback:

                        stateObj.WriteByte((byte)(transactionName.Length * 2)); // Write number of bytes (unicode string).
                        WriteString(transactionName, stateObj);

                        stateObj.WriteByte(0);  // No flags

                        Debug.Assert(isoLevel == TdsEnums.TransactionManagerIsolationLevel.Unspecified, "Should not have isolation level other than unspecified on Commit!");
                        // WriteByte((byte) 0, stateObj); // IsolationLevel
                        // WriteByte((byte) 0, stateObj); // No begin xact name
                        break;
                    case TdsEnums.TransactionManagerRequestType.Save:

                        stateObj.WriteByte((byte)(transactionName.Length * 2)); // Write number of bytes (unicode string).
                        WriteString(transactionName, stateObj);
                        break;
                    default:
                        Debug.Assert(false, "Unexpected TransactionManagerRequest");
                        break;
                }

                Task writeTask = stateObj.WritePacket(TdsEnums.HARDFLUSH);
                Debug.Assert(writeTask == null, "Writes should not pend when writing sync");
                stateObj._pendingData = true;
                stateObj._messageStatus = 0;

                SqlDataReader dtcReader = null;
                stateObj.SniContext = SniContext.Snix_Read;
                if (returnReader)
                {
                    dtcReader = new SqlDataReader(null, CommandBehavior.Default);
                    Debug.Assert(this == stateObj.Parser, "different parser");
#if DEBUG
                    // Remove the current owner of stateObj - otherwise we will hit asserts
                    stateObj.Owner = null;
#endif
                    dtcReader.Bind(stateObj);

                    // force consumption of metadata
                    _SqlMetaDataSet metaData = dtcReader.MetaData;
                }
                else
                {
                    Run(RunBehavior.UntilDone, null, null, null, stateObj);
                }


                return dtcReader;
            }
            catch (Exception e)
            {
                if (!ADP.IsCatchableExceptionType(e))
                {
                    throw;
                }

                FailureCleanup(stateObj, e);

                throw;
            }
            finally
            {
                // SQLHotfix 50000518
                // make sure we don't leave temporary fields set when leaving this function
                _pendingTransaction = null;

                _asyncWrite = hadAsyncWrites;

                if (!callerHasConnectionLock)
                {
                    _connHandler.ThreadHasParserLockForClose = false;
                    _connHandler._parserLock.Release();
                }
            }
        }
Exemplo n.º 45
0
        internal void ExecuteTransactionPreYukon(SqlInternalConnection.TransactionRequest transactionRequest, string transactionName, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction)
        {
            StringBuilder builder = new StringBuilder();

            switch (iso)
            {
            case System.Data.IsolationLevel.Unspecified:
                break;

            case System.Data.IsolationLevel.Chaos:
                throw SQL.NotSupportedIsolationLevel(iso);

            case System.Data.IsolationLevel.ReadUncommitted:
                builder.Append("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
                builder.Append(";");
                break;

            case System.Data.IsolationLevel.Serializable:
                builder.Append("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
                builder.Append(";");
                break;

            case System.Data.IsolationLevel.Snapshot:
                throw SQL.SnapshotNotSupported(System.Data.IsolationLevel.Snapshot);

            case System.Data.IsolationLevel.ReadCommitted:
                builder.Append("SET TRANSACTION ISOLATION LEVEL READ COMMITTED");
                builder.Append(";");
                break;

            case System.Data.IsolationLevel.RepeatableRead:
                builder.Append("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
                builder.Append(";");
                break;

            default:
                throw ADP.InvalidIsolationLevel(iso);
            }
            if (!ADP.IsEmpty(transactionName))
            {
                transactionName = " " + SqlConnection.FixupDatabaseTransactionName(transactionName);
            }
            switch (transactionRequest)
            {
            case SqlInternalConnection.TransactionRequest.Begin:
                builder.Append("BEGIN TRANSACTION");
                builder.Append(transactionName);
                break;

            case SqlInternalConnection.TransactionRequest.Commit:
                builder.Append("COMMIT TRANSACTION");
                builder.Append(transactionName);
                break;

            case SqlInternalConnection.TransactionRequest.Rollback:
                builder.Append("ROLLBACK TRANSACTION");
                builder.Append(transactionName);
                break;

            case SqlInternalConnection.TransactionRequest.IfRollback:
                builder.Append("IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION");
                builder.Append(transactionName);
                break;

            case SqlInternalConnection.TransactionRequest.Save:
                builder.Append("SAVE TRANSACTION");
                builder.Append(transactionName);
                break;
            }
            this._parser.TdsExecuteSQLBatch(builder.ToString(), base.ConnectionOptions.ConnectTimeout, null, this._parser._physicalStateObj);
            this._parser.Run(RunBehavior.UntilDone, null, null, null, this._parser._physicalStateObj);
            if (transactionRequest == SqlInternalConnection.TransactionRequest.Begin)
            {
                this._parser.CurrentTransaction = internalTransaction;
            }
        }
Exemplo n.º 46
0
 abstract internal void DisconnectTransaction(SqlInternalTransaction internalTransaction);
Exemplo n.º 47
0
 internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction)
 {
     this._isolationLevel = iso;
     this._connection     = con;
     if (internalTransaction == null)
     {
         this._internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this);
     }
     else
     {
         this._internalTransaction = internalTransaction;
         this._internalTransaction.InitParent(this);
     }
 }
Exemplo n.º 48
0
        override public void Rollback()
        {
            if (IsYukonPartialZombie)
            {
                // Put something in the trace in case a customer has an issue
                _internalTransaction = null; // yukon zombification
            }
            else
            {
                ZombieCheck();

                SqlStatistics statistics = null;
                try
                {
                    statistics = SqlStatistics.StartTimer(Statistics);

                    _isFromAPI = true;

                    _internalTransaction.Rollback();
                }
                finally
                {
                    _isFromAPI = false;

                    SqlStatistics.StopTimer(statistics);
                }
            }
        }
Exemplo n.º 49
0
 abstract internal void DisconnectTransaction(SqlInternalTransaction internalTransaction);
Exemplo n.º 50
0
        ////////////////////////////////////////////////////////////////////////////////////////
        // PRIVATE METHODS
        ////////////////////////////////////////////////////////////////////////////////////////

        private void ZombieCheck()
        {
            // If this transaction has been completed, throw exception since it is unusable.
            if (IsZombied)
            {
                if (IsYukonPartialZombie)
                {
                    _internalTransaction = null; // yukon zombification
                }

                throw ADP.TransactionZombied(this);
            }
        }
 internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con,
                         IsolationLevel iso, SqlInternalTransaction internalTransaction)
 => throw new PlatformNotSupportedException(EXCEPTION_MESSAGE);