Merge pull request #159 from pingcap/zimuxia/status-in-trans
Set ServerStatusInTrans flag
This commit is contained in:
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
2
tidb.go
2
tidb.go
@ -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)
|
||||
|
||||
36
tidb_test.go
36
tidb_test.go
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user