Merge pull request #159 from pingcap/zimuxia/status-in-trans

Set ServerStatusInTrans flag
This commit is contained in:
goroutine
2015-09-16 19:48:36 +08:00
6 changed files with 56 additions and 11 deletions

View File

@ -137,6 +137,7 @@ func (s *session) FinishTxn(rollback bool) error {
}
defer func() {
s.txn = nil
variable.GetSessionVars(s).SetStatusInTrans(false)
}()
if rollback {
@ -345,6 +346,7 @@ func (s *session) GetTxn(forceNew bool) (kv.Transaction, error) {
}
if forceNew {
err = s.txn.Commit()
variable.GetSessionVars(s).SetStatusInTrans(false)
if err != nil {
return nil, err
}

View File

@ -38,9 +38,6 @@ type SessionVars struct {
// Client Capability
ClientCapability uint32 // Client capability
// Disable autocommit
DisableAutocommit bool
// Found rows
FoundRows uint64
}
@ -102,19 +99,29 @@ func (s *SessionVars) SetStatus(status uint16) {
s.Status = status
}
// SetStatusInTrans sets the status flags about ServerStatusInTrans.
func (s *SessionVars) SetStatusInTrans(isInTrans bool) {
if isInTrans {
s.Status |= mysql.ServerStatusInTrans
return
}
s.Status &= (^mysql.ServerStatusInTrans)
}
// GetNextPreparedStmtID generates and return the next session scope prepared statement id
func (s *SessionVars) GetNextPreparedStmtID() uint32 {
s.preparedStmtID++
return s.preparedStmtID
}
// IsAutocommit checks if it is in autocommit enviroment
func IsAutocommit(ctx context.Context) bool {
// ShouldAutocommit checks if it is in autocommit enviroment
func ShouldAutocommit(ctx context.Context) bool {
// With START TRANSACTION, autocommit remains disabled until you end
// the transaction with COMMIT or ROLLBACK.
if GetSessionVars(ctx).Status&mysql.ServerStatusAutocommit > 0 &&
!GetSessionVars(ctx).DisableAutocommit {
GetSessionVars(ctx).Status&mysql.ServerStatusInTrans == 0 {
return true
}
return false
}

View File

@ -147,7 +147,7 @@ func (s *SelectStmt) Plan(ctx context.Context) (plan.Plan, error) {
}
}
lock := s.Lock
if variable.IsAutocommit(ctx) {
if variable.ShouldAutocommit(ctx) {
// Locking of rows for update using SELECT FOR UPDATE only applies when autocommit
// is disabled (either by beginning transaction with START TRANSACTION or by setting
// autocommit to 0. If autocommit is enabled, the rows matching the specification are not locked.

View File

@ -63,7 +63,7 @@ func (s *BeginStmt) Exec(ctx context.Context) (_ rset.Recordset, err error) {
// With START TRANSACTION, autocommit remains disabled until you end
// the transaction with COMMIT or ROLLBACK. The autocommit mode then
// reverts to its previous state.
variable.GetSessionVars(ctx).DisableAutocommit = true
variable.GetSessionVars(ctx).SetStatusInTrans(true)
return
}
@ -96,7 +96,7 @@ func (s *CommitStmt) SetText(text string) {
// Exec implements the stmt.Statement Exec interface.
func (s *CommitStmt) Exec(ctx context.Context) (_ rset.Recordset, err error) {
err = ctx.FinishTxn(false)
variable.GetSessionVars(ctx).DisableAutocommit = false
variable.GetSessionVars(ctx).SetStatusInTrans(false)
return
}
@ -129,6 +129,6 @@ func (s *RollbackStmt) SetText(text string) {
// Exec implements the stmt.Statement Exec interface.
func (s *RollbackStmt) Exec(ctx context.Context) (_ rset.Recordset, err error) {
err = ctx.FinishTxn(true)
variable.GetSessionVars(ctx).DisableAutocommit = false
variable.GetSessionVars(ctx).SetStatusInTrans(false)
return
}

View File

@ -161,7 +161,7 @@ func runStmt(ctx context.Context, s stmt.Statement, args ...interface{}) (rset.R
stmt.ClearExecArgs(ctx)
}
// MySQL DDL should be auto-commit
if err == nil && (s.IsDDL() || variable.IsAutocommit(ctx)) {
if err == nil && (s.IsDDL() || variable.ShouldAutocommit(ctx)) {
err = ctx.FinishTxn(false)
}
return rs, errors.Trace(err)

View File

@ -28,6 +28,7 @@ import (
"github.com/pingcap/tidb/kv"
mysql "github.com/pingcap/tidb/mysqldef"
"github.com/pingcap/tidb/rset"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/util/errors2"
)
@ -462,6 +463,41 @@ func (s *testSessionSuite) TestAutoincrementID(c *C) {
mustExecSQL(c, se, s.dropDBSQL)
}
func checkInTrans(c *C, se Session, stmt string, expect uint16) {
mustExecSQL(c, se, stmt)
if expect == 0 {
c.Assert(se.(*session).txn, IsNil)
} else {
c.Assert(se.(*session).txn, NotNil)
}
ret := variable.GetSessionVars(se.(*session)).Status & mysql.ServerStatusInTrans
c.Assert(ret, Equals, expect)
}
// See: https://dev.mysql.com/doc/internals/en/status-flags.html
func (s *testSessionSuite) TestInTrans(c *C) {
store := newStore(c, s.dbName)
se := newSession(c, store, s.dbName)
checkInTrans(c, se, "drop table if exists t;", 0)
checkInTrans(c, se, "create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)", 0)
checkInTrans(c, se, "insert t values ()", 0)
checkInTrans(c, se, "begin", 1)
checkInTrans(c, se, "insert t values ()", 1)
checkInTrans(c, se, "drop table if exists t;", 0)
checkInTrans(c, se, "create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)", 0)
checkInTrans(c, se, "insert t values ()", 0)
checkInTrans(c, se, "commit", 0)
checkInTrans(c, se, "insert t values ()", 0)
checkInTrans(c, se, "drop table if exists t;", 0)
checkInTrans(c, se, "create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)", 0)
checkInTrans(c, se, "begin", 1)
checkInTrans(c, se, "insert t values ()", 1)
checkInTrans(c, se, "rollback", 0)
mustExecSQL(c, se, s.dropDBSQL)
}
// See: http://dev.mysql.com/doc/refman/5.7/en/commit.html
func (s *testSessionSuite) TestRowLock(c *C) {
store := newStore(c, s.dbName)