github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/txn_test.go (about)

     1  // Copyright 2021 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package frontend
    16  
    17  import (
    18  	"context"
    19  	"sync"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/fagongzi/goetty/v2/buf"
    24  	"github.com/golang/mock/gomock"
    25  	"github.com/smartystreets/goconvey/convey"
    26  
    27  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    28  	"github.com/matrixorigin/matrixone/pkg/defines"
    29  	mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test"
    30  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    31  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    32  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    33  	"github.com/matrixorigin/matrixone/pkg/txn/client"
    34  	"github.com/matrixorigin/matrixone/pkg/txn/clock"
    35  	"github.com/matrixorigin/matrixone/pkg/vm/engine"
    36  )
    37  
    38  var _ client.Workspace = (*testWorkspace)(nil)
    39  
    40  type testWorkspace struct {
    41  	start      bool
    42  	incr       bool
    43  	mu         sync.Mutex
    44  	stack      []uint64
    45  	stmtId     uint64
    46  	reportErr1 bool
    47  }
    48  
    49  func (txn *testWorkspace) UpdateSnapshotWriteOffset() {
    50  	//TODO implement me
    51  	panic("implement me")
    52  }
    53  
    54  func (txn *testWorkspace) GetSnapshotWriteOffset() int {
    55  	//TODO implement me
    56  	panic("implement me")
    57  }
    58  
    59  func newTestWorkspace() *testWorkspace {
    60  	return &testWorkspace{}
    61  }
    62  
    63  func (txn *testWorkspace) StartStatement() {
    64  	if txn.start {
    65  		panic("BUG: StartStatement called twice")
    66  	}
    67  	txn.start = true
    68  	txn.incr = false
    69  }
    70  
    71  func (txn *testWorkspace) EndStatement() {
    72  	if !txn.start {
    73  		panic("BUG: StartStatement not called")
    74  	}
    75  
    76  	txn.start = false
    77  	txn.incr = false
    78  }
    79  
    80  func (txn *testWorkspace) IncrStatementID(ctx context.Context, commit bool) error {
    81  	if !commit {
    82  		if !txn.start {
    83  			panic("BUG: StartStatement not called")
    84  		}
    85  		if txn.incr {
    86  			panic("BUG: IncrStatementID called twice")
    87  		}
    88  		txn.incr = true
    89  	}
    90  	txn.mu.Lock()
    91  	defer txn.mu.Unlock()
    92  	txn.stack = append(txn.stack, txn.stmtId)
    93  	txn.stmtId++
    94  	return nil
    95  }
    96  
    97  func (txn *testWorkspace) RollbackLastStatement(ctx context.Context) error {
    98  	txn.mu.Lock()
    99  	defer txn.mu.Unlock()
   100  	if txn.reportErr1 {
   101  		return moerr.NewInternalError(ctx, "rollback statement failed.")
   102  	}
   103  	if len(txn.stack) == 0 {
   104  		panic("BUG: unbalance happens")
   105  	}
   106  	txn.stmtId--
   107  	lastStmtId := txn.stack[len(txn.stack)-1]
   108  	if txn.stmtId != lastStmtId {
   109  		panic("BUG: wrong stmt id")
   110  	}
   111  	txn.stack = txn.stack[:len(txn.stack)-1]
   112  	txn.incr = false
   113  	return nil
   114  }
   115  
   116  func (t *testWorkspace) WriteOffset() uint64 {
   117  	//TODO implement me
   118  	panic("implement me")
   119  }
   120  
   121  func (t *testWorkspace) Adjust(writeOffset uint64) error {
   122  	//TODO implement me
   123  	panic("implement me")
   124  }
   125  
   126  func (t *testWorkspace) Commit(ctx context.Context) ([]txn.TxnRequest, error) {
   127  	//TODO implement me
   128  	panic("implement me")
   129  }
   130  
   131  func (t *testWorkspace) Rollback(ctx context.Context) error {
   132  	//TODO implement me
   133  	panic("implement me")
   134  }
   135  
   136  func (t *testWorkspace) IncrSQLCount() {
   137  	//TODO implement me
   138  	panic("implement me")
   139  }
   140  
   141  func (t *testWorkspace) GetSQLCount() uint64 {
   142  	//TODO implement me
   143  	panic("implement me")
   144  }
   145  
   146  func (t *testWorkspace) CloneSnapshotWS() client.Workspace {
   147  	//TODO implement me
   148  	panic("implement me")
   149  }
   150  
   151  func (t *testWorkspace) BindTxnOp(op client.TxnOperator) {
   152  	//TODO implement me
   153  	panic("implement me")
   154  }
   155  
   156  func TestWorkspace(t *testing.T) {
   157  	convey.Convey("no panic", t, func() {
   158  		convey.So(
   159  			func() {
   160  				wsp := newTestWorkspace()
   161  				wsp.StartStatement()
   162  				wsp.EndStatement()
   163  			},
   164  			convey.ShouldNotPanic,
   165  		)
   166  	})
   167  	convey.Convey("end panic", t, func() {
   168  		convey.So(
   169  			func() {
   170  				wsp := newTestWorkspace()
   171  				wsp.EndStatement()
   172  			},
   173  			convey.ShouldPanic,
   174  		)
   175  	})
   176  	convey.Convey("start panic 1", t, func() {
   177  		convey.So(
   178  			func() {
   179  				wsp := newTestWorkspace()
   180  				wsp.StartStatement()
   181  				wsp.StartStatement()
   182  			},
   183  			convey.ShouldPanic,
   184  		)
   185  	})
   186  	convey.Convey("incr panic 1", t, func() {
   187  		convey.So(
   188  			func() {
   189  				wsp := newTestWorkspace()
   190  				//no start
   191  				err := wsp.IncrStatementID(context.TODO(), false)
   192  				convey.So(err, convey.ShouldBeNil)
   193  			},
   194  			convey.ShouldPanic,
   195  		)
   196  	})
   197  	convey.Convey("incr panic 2", t, func() {
   198  		convey.So(
   199  			func() {
   200  				wsp := newTestWorkspace()
   201  				wsp.StartStatement()
   202  				err := wsp.IncrStatementID(context.TODO(), false)
   203  				convey.So(err, convey.ShouldBeNil)
   204  				//incr twice
   205  				err = wsp.IncrStatementID(context.TODO(), false)
   206  				convey.So(err, convey.ShouldBeNil)
   207  			},
   208  			convey.ShouldPanic,
   209  		)
   210  	})
   211  	convey.Convey("rollback last statement panic 1", t, func() {
   212  		convey.So(
   213  			func() {
   214  				wsp := newTestWorkspace()
   215  				wsp.StartStatement()
   216  				err := wsp.RollbackLastStatement(context.TODO())
   217  				convey.So(err, convey.ShouldBeNil)
   218  			},
   219  			convey.ShouldPanic,
   220  		)
   221  	})
   222  	convey.Convey("rollback last statement panic 2", t, func() {
   223  		convey.So(
   224  			func() {
   225  				wsp := newTestWorkspace()
   226  				wsp.StartStatement()
   227  				err := wsp.IncrStatementID(context.TODO(), false)
   228  				convey.So(err, convey.ShouldBeNil)
   229  				err = wsp.RollbackLastStatement(context.TODO())
   230  				convey.So(err, convey.ShouldBeNil)
   231  				err = wsp.RollbackLastStatement(context.TODO())
   232  				convey.So(err, convey.ShouldBeNil)
   233  			},
   234  			convey.ShouldPanic,
   235  		)
   236  	})
   237  }
   238  
   239  func newMockErrSession(t *testing.T, ctx context.Context, ctrl *gomock.Controller) *Session {
   240  	txnClient := mock_frontend.NewMockTxnClient(ctrl)
   241  	txnClient.EXPECT().New(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
   242  		func(ctx context.Context, commitTS timestamp.Timestamp, options ...TxnOption) (client.TxnOperator, error) {
   243  			txnOperator := mock_frontend.NewMockTxnOperator(ctrl)
   244  			txnOperator.EXPECT().Txn().Return(txn.TxnMeta{}).AnyTimes()
   245  			txnOperator.EXPECT().Rollback(gomock.Any()).Return(moerr.NewInternalError(ctx, "throw error")).AnyTimes()
   246  			txnOperator.EXPECT().Commit(gomock.Any()).Return(nil).AnyTimes()
   247  			wsp := newTestWorkspace()
   248  			txnOperator.EXPECT().GetWorkspace().Return(wsp).AnyTimes()
   249  			return txnOperator, nil
   250  		}).AnyTimes()
   251  	eng := mock_frontend.NewMockEngine(ctrl)
   252  	eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   253  	eng.EXPECT().Hints().Return(engine.Hints{
   254  		CommitOrRollbackTimeout: time.Second,
   255  	}).AnyTimes()
   256  
   257  	var gSys GlobalSystemVariables
   258  	InitGlobalSystemVariables(&gSys)
   259  
   260  	ses := newTestSession(t, ctrl)
   261  	getGlobalPu().TxnClient = txnClient
   262  	getGlobalPu().StorageEngine = eng
   263  	ses.txnHandler.storage = eng
   264  	var c clock.Clock
   265  	_ = ses.GetTxnHandler().CreateTempStorage(c)
   266  	return ses
   267  }
   268  
   269  func newMockErrSession2(t *testing.T, ctx context.Context, ctrl *gomock.Controller) *Session {
   270  	txnClient := mock_frontend.NewMockTxnClient(ctrl)
   271  	txnClient.EXPECT().New(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
   272  		func(ctx context.Context, commitTS timestamp.Timestamp, options ...TxnOption) (client.TxnOperator, error) {
   273  			txnOperator := mock_frontend.NewMockTxnOperator(ctrl)
   274  			txnOperator.EXPECT().Txn().Return(txn.TxnMeta{}).AnyTimes()
   275  			txnOperator.EXPECT().Rollback(gomock.Any()).Return(nil).AnyTimes()
   276  			txnOperator.EXPECT().Commit(gomock.Any()).Return(nil).AnyTimes()
   277  			wsp := newTestWorkspace()
   278  			wsp.reportErr1 = true
   279  			txnOperator.EXPECT().GetWorkspace().Return(wsp).AnyTimes()
   280  			return txnOperator, nil
   281  		}).AnyTimes()
   282  	eng := mock_frontend.NewMockEngine(ctrl)
   283  	eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   284  	eng.EXPECT().Hints().Return(engine.Hints{
   285  		CommitOrRollbackTimeout: time.Second,
   286  	}).AnyTimes()
   287  
   288  	var gSys GlobalSystemVariables
   289  	InitGlobalSystemVariables(&gSys)
   290  	ses := newTestSession(t, ctrl)
   291  	getGlobalPu().TxnClient = txnClient
   292  	getGlobalPu().StorageEngine = eng
   293  	ses.txnHandler.storage = eng
   294  
   295  	var c clock.Clock
   296  	_ = ses.GetTxnHandler().CreateTempStorage(c)
   297  	return ses
   298  }
   299  
   300  func Test_rollbackStatement(t *testing.T) {
   301  	convey.Convey("normal rollback", t, func() {
   302  		ctrl := gomock.NewController(t)
   303  		defer ctrl.Finish()
   304  
   305  		ctx := defines.AttachAccountId(context.TODO(), sysAccountID)
   306  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
   307  		txnClient.EXPECT().New(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
   308  			func(ctx context.Context, commitTS timestamp.Timestamp, options ...TxnOption) (client.TxnOperator, error) {
   309  				txnOperator := mock_frontend.NewMockTxnOperator(ctrl)
   310  				txnOperator.EXPECT().Txn().Return(txn.TxnMeta{}).AnyTimes()
   311  				txnOperator.EXPECT().Rollback(gomock.Any()).Return(nil).AnyTimes()
   312  				txnOperator.EXPECT().Commit(gomock.Any()).Return(nil).AnyTimes()
   313  				wsp := newTestWorkspace()
   314  				txnOperator.EXPECT().GetWorkspace().Return(wsp).AnyTimes()
   315  				return txnOperator, nil
   316  			}).AnyTimes()
   317  		eng := mock_frontend.NewMockEngine(ctrl)
   318  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   319  		eng.EXPECT().Hints().Return(engine.Hints{
   320  			CommitOrRollbackTimeout: time.Second,
   321  		}).AnyTimes()
   322  
   323  		ioses := mock_frontend.NewMockIOSession(ctrl)
   324  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
   325  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   326  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
   327  		ioses.EXPECT().Ref().AnyTimes()
   328  
   329  		var gSys GlobalSystemVariables
   330  		InitGlobalSystemVariables(&gSys)
   331  
   332  		ses := newTestSession(t, ctrl)
   333  		getGlobalPu().TxnClient = txnClient
   334  		ses.txnHandler.storage = eng
   335  
   336  		ec := newTestExecCtx(ctx, ctrl)
   337  		ec.ses = ses
   338  		//case1. autocommit && not_begin. Insert Stmt (need not to be committed in the active txn)
   339  		ec.txnOpt = FeTxnOption{
   340  			autoCommit: true,
   341  		}
   342  
   343  		err := ses.GetTxnHandler().Create(ec)
   344  		convey.So(err, convey.ShouldBeNil)
   345  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeFalse)
   346  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_AUTOCOMMIT), convey.ShouldBeTrue)
   347  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeTrue)
   348  		ec.stmt = &tree.Insert{}
   349  		err = ses.GetTxnHandler().Rollback(ec)
   350  		convey.So(err, convey.ShouldBeNil)
   351  		t2 := ses.txnHandler.GetTxn()
   352  		convey.So(t2, convey.ShouldBeNil)
   353  
   354  		//case2.1 autocommit && begin && CreateSequence (need to be committed in the active txn)
   355  		ec.txnOpt = FeTxnOption{
   356  			autoCommit: true,
   357  			byBegin:    true,
   358  		}
   359  		err = ses.GetTxnHandler().Create(ec)
   360  		convey.So(err, convey.ShouldBeNil)
   361  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeTrue)
   362  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_NOT_AUTOCOMMIT), convey.ShouldBeFalse)
   363  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeFalse)
   364  		convey.So(ses.GetTxnHandler().InActiveTxn() &&
   365  			NeedToBeCommittedInActiveTransaction(&tree.CreateSequence{}), convey.ShouldBeTrue)
   366  		ec.stmt = &tree.CreateSequence{}
   367  		err = ses.GetTxnHandler().Rollback(ec)
   368  		convey.So(err, convey.ShouldBeNil)
   369  		t2 = ses.txnHandler.GetTxn()
   370  		convey.So(t2, convey.ShouldBeNil)
   371  
   372  		//case2.2 not_autocommit && not_begin && CreateSequence (need to be committed in the active txn)
   373  		ec.txnOpt = FeTxnOption{
   374  			autoCommit: false,
   375  		}
   376  		err = ses.txnHandler.Create(ec)
   377  		convey.So(err, convey.ShouldBeNil)
   378  		err = ses.GetTxnHandler().SetAutocommit(ec, true, false)
   379  		convey.So(err, convey.ShouldBeNil)
   380  		_ = ses.txnHandler.GetTxn()
   381  		convey.So(err, convey.ShouldBeNil)
   382  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeFalse)
   383  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_NOT_AUTOCOMMIT), convey.ShouldBeTrue)
   384  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeFalse)
   385  		convey.So(ses.GetTxnHandler().InActiveTxn() &&
   386  			NeedToBeCommittedInActiveTransaction(&tree.CreateSequence{}), convey.ShouldBeTrue)
   387  		ec.stmt = &tree.CreateSequence{}
   388  		err = ses.GetTxnHandler().Rollback(ec)
   389  		convey.So(err, convey.ShouldBeNil)
   390  		t2 = ses.txnHandler.GetTxn()
   391  		convey.So(t2, convey.ShouldBeNil)
   392  
   393  		//case3.1 not_autocommit && not_begin && Insert Stmt (need not to be committed in the active txn)
   394  		ec.txnOpt = FeTxnOption{
   395  			autoCommit: false,
   396  		}
   397  		err = ses.txnHandler.Create(ec)
   398  		convey.So(err, convey.ShouldBeNil)
   399  		err = ses.GetTxnHandler().SetAutocommit(ec, true, false)
   400  		var txnOp TxnOperator
   401  		convey.So(err, convey.ShouldBeNil)
   402  		txnOp = ses.txnHandler.GetTxn()
   403  		convey.So(err, convey.ShouldBeNil)
   404  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeFalse)
   405  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_NOT_AUTOCOMMIT), convey.ShouldBeTrue)
   406  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeFalse)
   407  		convey.So(ses.GetTxnHandler().InActiveTxn() &&
   408  			NeedToBeCommittedInActiveTransaction(&tree.Insert{}), convey.ShouldBeFalse)
   409  		convey.So(txnOp != nil && !ses.IsDerivedStmt(), convey.ShouldBeTrue)
   410  		//called incrStatement
   411  		txnOp.GetWorkspace().StartStatement()
   412  		err = txnOp.GetWorkspace().IncrStatementID(ctx, false)
   413  		convey.So(err, convey.ShouldBeNil)
   414  		ec.stmt = &tree.Insert{}
   415  		err = ses.GetTxnHandler().Rollback(ec)
   416  		convey.So(err, convey.ShouldBeNil)
   417  		t2 = ses.txnHandler.GetTxn()
   418  		convey.So(t2, convey.ShouldNotBeNil)
   419  
   420  		//case3.2 not_autocommit && begin && Insert Stmt (need not to be committed in the active txn)
   421  		ec.txnOpt = FeTxnOption{
   422  			autoCommit: false,
   423  			byBegin:    true,
   424  		}
   425  		err = ses.txnHandler.Create(ec)
   426  		convey.So(err, convey.ShouldBeNil)
   427  		err = ses.GetTxnHandler().SetAutocommit(ec, true, false)
   428  		convey.So(err, convey.ShouldBeNil)
   429  		err = ses.GetTxnHandler().Create(ec)
   430  		convey.So(err, convey.ShouldBeNil)
   431  		txnOp = ses.GetTxnHandler().GetTxn()
   432  		convey.So(err, convey.ShouldBeNil)
   433  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeTrue)
   434  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_NOT_AUTOCOMMIT), convey.ShouldBeTrue)
   435  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeFalse)
   436  		convey.So(ses.GetTxnHandler().InActiveTxn() &&
   437  			NeedToBeCommittedInActiveTransaction(&tree.Insert{}), convey.ShouldBeFalse)
   438  		convey.So(txnOp != nil && !ses.IsDerivedStmt(), convey.ShouldBeTrue)
   439  		//called incrStatement
   440  		txnOp.GetWorkspace().StartStatement()
   441  		err = txnOp.GetWorkspace().IncrStatementID(ctx, false)
   442  		convey.So(err, convey.ShouldBeNil)
   443  		ec.stmt = &tree.Insert{}
   444  		err = ses.GetTxnHandler().Rollback(ec)
   445  		convey.So(err, convey.ShouldBeNil)
   446  		t2 = ses.txnHandler.GetTxn()
   447  		convey.So(t2, convey.ShouldNotBeNil)
   448  
   449  	})
   450  
   451  	convey.Convey("abnormal rollback", t, func() {
   452  		ctrl := gomock.NewController(t)
   453  		defer ctrl.Finish()
   454  
   455  		ctx := defines.AttachAccountId(context.TODO(), sysAccountID)
   456  		ses := newMockErrSession(t, ctx, ctrl)
   457  		ec := newTestExecCtx(ctx, ctrl)
   458  		ec.ses = ses
   459  		//case1. autocommit && not_begin. Insert Stmt (need not to be committed in the active txn)
   460  		ec.txnOpt = FeTxnOption{
   461  			autoCommit: true,
   462  		}
   463  		err := ses.GetTxnHandler().Create(ec)
   464  		convey.So(err, convey.ShouldBeNil)
   465  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeFalse)
   466  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_AUTOCOMMIT), convey.ShouldBeTrue)
   467  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeTrue)
   468  		ec.stmt = &tree.Insert{}
   469  		err = ses.GetTxnHandler().Rollback(ec)
   470  		convey.So(err, convey.ShouldNotBeNil)
   471  		t2 := ses.txnHandler.GetTxn()
   472  		convey.So(t2, convey.ShouldBeNil)
   473  	})
   474  }
   475  
   476  func Test_rollbackStatement2(t *testing.T) {
   477  	convey.Convey("abnormal rollback", t, func() {
   478  		ctrl := gomock.NewController(t)
   479  		defer ctrl.Finish()
   480  
   481  		ctx := defines.AttachAccountId(context.TODO(), sysAccountID)
   482  		ses := newMockErrSession(t, ctx, ctrl)
   483  		ec := newTestExecCtx(ctx, ctrl)
   484  		ec.ses = ses
   485  
   486  		//case1. autocommit && not_begin. Insert Stmt (need not to be committed in the active txn)
   487  		ec.txnOpt = FeTxnOption{
   488  			autoCommit: true,
   489  		}
   490  		err := ses.GetTxnHandler().Create(ec)
   491  		convey.So(err, convey.ShouldBeNil)
   492  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeFalse)
   493  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_AUTOCOMMIT), convey.ShouldBeTrue)
   494  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeTrue)
   495  		ec.stmt = &tree.Insert{}
   496  		err = ses.GetTxnHandler().Rollback(ec)
   497  		convey.So(err, convey.ShouldNotBeNil)
   498  		t2 := ses.txnHandler.GetTxn()
   499  		convey.So(t2, convey.ShouldBeNil)
   500  	})
   501  }
   502  
   503  func Test_rollbackStatement3(t *testing.T) {
   504  	convey.Convey("abnormal rollback", t, func() {
   505  		ctrl := gomock.NewController(t)
   506  		defer ctrl.Finish()
   507  
   508  		ctx := defines.AttachAccountId(context.TODO(), sysAccountID)
   509  		ses := newMockErrSession(t, ctx, ctrl)
   510  		ec := newTestExecCtx(ctx, ctrl)
   511  		ec.ses = ses
   512  
   513  		//case2.1 autocommit && begin && CreateSequence (need to be committed in the active txn)
   514  		ec.txnOpt = FeTxnOption{
   515  			autoCommit: true,
   516  			byBegin:    true,
   517  		}
   518  		err := ses.GetTxnHandler().Create(ec)
   519  		convey.So(err, convey.ShouldBeNil)
   520  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeTrue)
   521  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_NOT_AUTOCOMMIT), convey.ShouldBeFalse)
   522  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeFalse)
   523  		convey.So(ses.GetTxnHandler().InActiveTxn() &&
   524  			NeedToBeCommittedInActiveTransaction(&tree.CreateSequence{}), convey.ShouldBeTrue)
   525  		ec.stmt = &tree.CreateSequence{}
   526  		err = ses.GetTxnHandler().Rollback(ec)
   527  		convey.So(err, convey.ShouldNotBeNil)
   528  		t2 := ses.txnHandler.GetTxn()
   529  		convey.So(t2, convey.ShouldBeNil)
   530  	})
   531  }
   532  
   533  func Test_rollbackStatement4(t *testing.T) {
   534  	convey.Convey("abnormal rollback", t, func() {
   535  		ctrl := gomock.NewController(t)
   536  		defer ctrl.Finish()
   537  
   538  		ctx := defines.AttachAccountId(context.TODO(), sysAccountID)
   539  		ses := newMockErrSession(t, ctx, ctrl)
   540  		ec := newTestExecCtx(ctx, ctrl)
   541  		ec.ses = ses
   542  		//case2.2 not_autocommit && not_begin && CreateSequence (need to be committed in the active txn)
   543  		err := ses.GetTxnHandler().Create(ec)
   544  		convey.So(err, convey.ShouldBeNil)
   545  		err = ses.GetTxnHandler().SetAutocommit(ec, true, false)
   546  		convey.So(err, convey.ShouldBeNil)
   547  		_ = ses.txnHandler.GetTxn()
   548  		convey.So(err, convey.ShouldBeNil)
   549  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeFalse)
   550  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_NOT_AUTOCOMMIT), convey.ShouldBeTrue)
   551  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeFalse)
   552  		convey.So(ses.GetTxnHandler().InActiveTxn() &&
   553  			NeedToBeCommittedInActiveTransaction(&tree.CreateSequence{}), convey.ShouldBeTrue)
   554  		ec.stmt = &tree.CreateSequence{}
   555  		err = ses.GetTxnHandler().Rollback(ec)
   556  		convey.So(err, convey.ShouldNotBeNil)
   557  		t2 := ses.txnHandler.GetTxn()
   558  		convey.So(t2, convey.ShouldBeNil)
   559  	})
   560  }
   561  
   562  func Test_rollbackStatement5(t *testing.T) {
   563  	convey.Convey("abnormal rollback", t, func() {
   564  		ctrl := gomock.NewController(t)
   565  		defer ctrl.Finish()
   566  
   567  		ctx := defines.AttachAccountId(context.TODO(), sysAccountID)
   568  		ses := newMockErrSession2(t, ctx, ctrl)
   569  		var txnOp TxnOperator
   570  		ec := newTestExecCtx(ctx, ctrl)
   571  		ec.ses = ses
   572  		//case3.1 not_autocommit && not_begin && Insert Stmt (need not to be committed in the active txn)
   573  		err := ses.GetTxnHandler().Create(ec)
   574  		convey.So(err, convey.ShouldBeNil)
   575  		err = ses.GetTxnHandler().SetAutocommit(ec, true, false)
   576  		convey.So(err, convey.ShouldBeNil)
   577  		txnOp = ses.txnHandler.GetTxn()
   578  		convey.So(err, convey.ShouldBeNil)
   579  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeFalse)
   580  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_NOT_AUTOCOMMIT), convey.ShouldBeTrue)
   581  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeFalse)
   582  		convey.So(ses.GetTxnHandler().InActiveTxn() &&
   583  			NeedToBeCommittedInActiveTransaction(&tree.Insert{}), convey.ShouldBeFalse)
   584  		convey.So(txnOp != nil && !ses.IsDerivedStmt(), convey.ShouldBeTrue)
   585  		//called incrStatement
   586  		txnOp.GetWorkspace().StartStatement()
   587  		err = txnOp.GetWorkspace().IncrStatementID(ctx, false)
   588  		convey.So(err, convey.ShouldBeNil)
   589  		ec.stmt = &tree.Insert{}
   590  		err = ses.GetTxnHandler().Rollback(ec)
   591  		convey.So(err, convey.ShouldNotBeNil)
   592  		t2 := ses.txnHandler.GetTxn()
   593  		convey.So(t2, convey.ShouldBeNil)
   594  	})
   595  }
   596  
   597  func Test_rollbackStatement6(t *testing.T) {
   598  	convey.Convey("abnormal rollback", t, func() {
   599  		ctrl := gomock.NewController(t)
   600  		defer ctrl.Finish()
   601  
   602  		ctx := defines.AttachAccountId(context.TODO(), sysAccountID)
   603  		ses := newMockErrSession2(t, ctx, ctrl)
   604  		var txnOp TxnOperator
   605  		ec := newTestExecCtx(ctx, ctrl)
   606  		ec.ses = ses
   607  
   608  		//case3.2 not_autocommit && begin && Insert Stmt (need not to be committed in the active txn)
   609  		err := ses.GetTxnHandler().SetAutocommit(ec, true, false)
   610  		convey.So(err, convey.ShouldBeNil)
   611  		ec.txnOpt = FeTxnOption{
   612  			byBegin: true,
   613  		}
   614  		err = ses.GetTxnHandler().Create(ec)
   615  		convey.So(err, convey.ShouldBeNil)
   616  		txnOp = ses.GetTxnHandler().GetTxn()
   617  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeTrue)
   618  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_NOT_AUTOCOMMIT), convey.ShouldBeTrue)
   619  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeFalse)
   620  		convey.So(ses.GetTxnHandler().InActiveTxn() &&
   621  			NeedToBeCommittedInActiveTransaction(&tree.Insert{}), convey.ShouldBeFalse)
   622  		convey.So(txnOp != nil && !ses.IsDerivedStmt(), convey.ShouldBeTrue)
   623  		//called incrStatement
   624  		txnOp.GetWorkspace().StartStatement()
   625  		err = txnOp.GetWorkspace().IncrStatementID(ctx, false)
   626  		convey.So(err, convey.ShouldBeNil)
   627  		ec.stmt = &tree.Insert{}
   628  		err = ses.GetTxnHandler().Rollback(ec)
   629  		convey.So(err, convey.ShouldNotBeNil)
   630  		t2 := ses.txnHandler.GetTxn()
   631  		convey.So(t2, convey.ShouldBeNil)
   632  	})
   633  	convey.Convey("abnormal rollback -- rollback whole txn", t, func() {
   634  		ctrl := gomock.NewController(t)
   635  		defer ctrl.Finish()
   636  
   637  		ctx := defines.AttachAccountId(context.TODO(), sysAccountID)
   638  		ses := newMockErrSession(t, ctx, ctrl)
   639  		var txnOp TxnOperator
   640  		ec := newTestExecCtx(ctx, ctrl)
   641  		ec.ses = ses
   642  		//case3.2 not_autocommit && begin && Insert Stmt (need not to be committed in the active txn)
   643  		err := ses.GetTxnHandler().SetAutocommit(ec, true, false)
   644  		convey.So(err, convey.ShouldBeNil)
   645  		ec.txnOpt = FeTxnOption{
   646  			byBegin: true,
   647  		}
   648  		err = ses.GetTxnHandler().Create(ec)
   649  		convey.So(err, convey.ShouldBeNil)
   650  		txnOp = ses.GetTxnHandler().GetTxn()
   651  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_BEGIN), convey.ShouldBeTrue)
   652  		convey.So(ses.GetTxnHandler().OptionBitsIsSet(OPTION_NOT_AUTOCOMMIT), convey.ShouldBeTrue)
   653  		convey.So(!ses.GetTxnHandler().InMultiStmtTransactionMode(), convey.ShouldBeFalse)
   654  		convey.So(ses.GetTxnHandler().InActiveTxn() &&
   655  			NeedToBeCommittedInActiveTransaction(&tree.Insert{}), convey.ShouldBeFalse)
   656  		convey.So(txnOp != nil && !ses.IsDerivedStmt(), convey.ShouldBeTrue)
   657  		//called incrStatement
   658  		txnOp.GetWorkspace().StartStatement()
   659  		err = txnOp.GetWorkspace().IncrStatementID(ctx, false)
   660  		convey.So(err, convey.ShouldBeNil)
   661  		ec.stmt = &tree.Insert{}
   662  		ec.txnOpt.byRollback = isErrorRollbackWholeTxn(getRandomErrorRollbackWholeTxn())
   663  		err = ses.GetTxnHandler().Rollback(ec)
   664  		convey.So(err, convey.ShouldNotBeNil)
   665  		t2 := ses.txnHandler.GetTxn()
   666  		convey.So(t2, convey.ShouldBeNil)
   667  	})
   668  }