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

     1  // Copyright 2022 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  	"fmt"
    20  	"io"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/catalog"
    25  
    26  	"github.com/fagongzi/goetty/v2"
    27  	"github.com/fagongzi/goetty/v2/buf"
    28  	"github.com/golang/mock/gomock"
    29  	"github.com/google/uuid"
    30  	"github.com/prashantv/gostub"
    31  	"github.com/smartystreets/goconvey/convey"
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  
    35  	"github.com/matrixorigin/matrixone/pkg/clusterservice"
    36  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    37  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    38  	"github.com/matrixorigin/matrixone/pkg/config"
    39  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    40  	"github.com/matrixorigin/matrixone/pkg/container/nulls"
    41  	"github.com/matrixorigin/matrixone/pkg/container/types"
    42  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    43  	"github.com/matrixorigin/matrixone/pkg/defines"
    44  	"github.com/matrixorigin/matrixone/pkg/frontend/constant"
    45  	mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test"
    46  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    47  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    48  	"github.com/matrixorigin/matrixone/pkg/sql/parsers"
    49  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
    50  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql"
    51  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    52  	"github.com/matrixorigin/matrixone/pkg/sql/plan"
    53  	"github.com/matrixorigin/matrixone/pkg/sql/plan/explain"
    54  	"github.com/matrixorigin/matrixone/pkg/testutil"
    55  	"github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace"
    56  	"github.com/matrixorigin/matrixone/pkg/vm/engine"
    57  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    58  )
    59  
    60  func init() {
    61  	motrace.Init(context.Background(), motrace.EnableTracer(false))
    62  	motrace.DisableLogErrorReport(true)
    63  }
    64  
    65  func mockRecordStatement(ctx context.Context) (context.Context, *gostub.Stubs) {
    66  	stm := &motrace.StatementInfo{}
    67  	ctx = motrace.ContextWithStatement(ctx, stm)
    68  	stubs := gostub.Stub(&RecordStatement, func(context.Context, *Session, *process.Process, ComputationWrapper, time.Time, string, string, bool) (context.Context, error) {
    69  		return ctx, nil
    70  	})
    71  	return ctx, stubs
    72  }
    73  
    74  func Test_mce(t *testing.T) {
    75  	ctx := defines.AttachAccountId(context.TODO(), sysAccountID)
    76  	convey.Convey("boot mce succ", t, func() {
    77  		ctrl := gomock.NewController(t)
    78  		defer ctrl.Finish()
    79  
    80  		ctx, rsStubs := mockRecordStatement(ctx)
    81  		defer rsStubs.Reset()
    82  
    83  		srStub := gostub.Stub(&parsers.HandleSqlForRecord, func(sql string) []string {
    84  			return make([]string, 7)
    85  		})
    86  		defer srStub.Reset()
    87  
    88  		eng := mock_frontend.NewMockEngine(ctrl)
    89  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
    90  		eng.EXPECT().Hints().Return(engine.Hints{
    91  			CommitOrRollbackTimeout: time.Second,
    92  		}).AnyTimes()
    93  		txnOperator := mock_frontend.NewMockTxnOperator(ctrl)
    94  		txnOperator.EXPECT().Txn().Return(txn.TxnMeta{}).AnyTimes()
    95  		eng.EXPECT().Database(ctx, gomock.Any(), txnOperator).Return(nil, nil).AnyTimes()
    96  
    97  		txnOperator.EXPECT().Commit(gomock.Any()).Return(nil).AnyTimes()
    98  		txnOperator.EXPECT().Rollback(gomock.Any()).Return(nil).AnyTimes()
    99  		txnOperator.EXPECT().GetWorkspace().Return(newTestWorkspace()).AnyTimes()
   100  
   101  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
   102  		txnClient.EXPECT().New(gomock.Any(), gomock.Any(), gomock.Any()).Return(txnOperator, nil).AnyTimes()
   103  
   104  		ioses := mock_frontend.NewMockIOSession(ctrl)
   105  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
   106  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   107  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
   108  		ioses.EXPECT().Ref().AnyTimes()
   109  		ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
   110  		use_t := mock_frontend.NewMockComputationWrapper(ctrl)
   111  		use_t.EXPECT().GetUUID().Return(make([]byte, 16)).AnyTimes()
   112  		use_t.EXPECT().Clear().AnyTimes()
   113  		stmts, err := parsers.Parse(ctx, dialect.MYSQL, "use T", 1, 0)
   114  		if err != nil {
   115  			t.Error(err)
   116  		}
   117  		use_t.EXPECT().GetAst().Return(stmts[0]).AnyTimes()
   118  		use_t.EXPECT().RecordExecPlan(ctx).Return(nil).AnyTimes()
   119  
   120  		runner := mock_frontend.NewMockComputationRunner(ctrl)
   121  		runner.EXPECT().Run(gomock.Any()).Return(nil, nil).AnyTimes()
   122  
   123  		create_1 := mock_frontend.NewMockComputationWrapper(ctrl)
   124  		stmts, err = parsers.Parse(ctx, dialect.MYSQL, "create table A(a varchar(100),b int,c float)", 1, 0)
   125  		if err != nil {
   126  			t.Error(err)
   127  		}
   128  		create_1.EXPECT().GetAst().Return(stmts[0]).AnyTimes()
   129  		create_1.EXPECT().GetUUID().Return(make([]byte, 16)).AnyTimes()
   130  		create_1.EXPECT().Compile(gomock.Any(), gomock.Any()).Return(runner, nil).AnyTimes()
   131  		create_1.EXPECT().Run(gomock.Any()).Return(nil, nil).AnyTimes()
   132  		create_1.EXPECT().GetLoadTag().Return(false).AnyTimes()
   133  		create_1.EXPECT().RecordExecPlan(ctx).Return(nil).AnyTimes()
   134  		create_1.EXPECT().Clear().AnyTimes()
   135  		create_1.EXPECT().Free().AnyTimes()
   136  		create_1.EXPECT().Plan().Return(nil).AnyTimes()
   137  
   138  		select_1 := mock_frontend.NewMockComputationWrapper(ctrl)
   139  		stmts, err = parsers.Parse(ctx, dialect.MYSQL, "select a,b,c from A", 1, 0)
   140  		if err != nil {
   141  			t.Error(err)
   142  		}
   143  		select_1.EXPECT().GetAst().Return(stmts[0]).AnyTimes()
   144  		select_1.EXPECT().GetUUID().Return(make([]byte, 16)).AnyTimes()
   145  		select_1.EXPECT().Compile(gomock.Any(), gomock.Any()).Return(runner, nil).AnyTimes()
   146  		select_1.EXPECT().Run(gomock.Any()).Return(nil, nil).AnyTimes()
   147  		select_1.EXPECT().GetLoadTag().Return(false).AnyTimes()
   148  		select_1.EXPECT().RecordExecPlan(ctx).Return(nil).AnyTimes()
   149  		select_1.EXPECT().Clear().AnyTimes()
   150  		select_1.EXPECT().Free().AnyTimes()
   151  		select_1.EXPECT().Plan().Return(nil).AnyTimes()
   152  
   153  		cola := &MysqlColumn{}
   154  		cola.SetName("a")
   155  		cola.SetColumnType(defines.MYSQL_TYPE_VARCHAR)
   156  		colb := &MysqlColumn{}
   157  		colb.SetName("b")
   158  		colb.SetColumnType(defines.MYSQL_TYPE_LONG)
   159  		colc := &MysqlColumn{}
   160  		colc.SetName("c")
   161  		colc.SetColumnType(defines.MYSQL_TYPE_FLOAT)
   162  		cols := []interface{}{
   163  			cola,
   164  			colb,
   165  			colc,
   166  		}
   167  		select_1.EXPECT().GetColumns(gomock.Any()).Return(cols, nil).AnyTimes()
   168  
   169  		cws := []ComputationWrapper{
   170  			//use_t,
   171  			create_1,
   172  			select_1,
   173  		}
   174  
   175  		var self_handle_sql = []string{
   176  			"SELECT DATABASE()",
   177  			"SELECT @@max_allowed_packet",
   178  			"SELECT @@version_comment",
   179  			"SELECT @@tx_isolation",
   180  			"set @@tx_isolation=`READ-COMMITTED`",
   181  			//TODO:fix it after parser is ready
   182  			//"set a = b",
   183  			//"drop database T",
   184  		}
   185  
   186  		sql1Col := &MysqlColumn{}
   187  		sql1Col.SetName("DATABASE()")
   188  		sql1Col.SetColumnType(defines.MYSQL_TYPE_VARCHAR)
   189  
   190  		sql2Col := &MysqlColumn{}
   191  		sql2Col.SetName("@@max_allowed_packet")
   192  		sql2Col.SetColumnType(defines.MYSQL_TYPE_LONGLONG)
   193  
   194  		sql3Col := &MysqlColumn{}
   195  		sql3Col.SetName("@@version_comment")
   196  		sql3Col.SetColumnType(defines.MYSQL_TYPE_VARCHAR)
   197  
   198  		sql4Col := &MysqlColumn{}
   199  		sql4Col.SetName("@@tx_isolation")
   200  		sql4Col.SetColumnType(defines.MYSQL_TYPE_VARCHAR)
   201  
   202  		var self_handle_sql_columns = [][]interface{}{
   203  			{
   204  				sql1Col,
   205  			},
   206  			{
   207  				sql2Col,
   208  			},
   209  			{
   210  				sql3Col,
   211  			},
   212  			{
   213  				sql4Col,
   214  			},
   215  			{},
   216  			{},
   217  		}
   218  
   219  		for i := 0; i < len(self_handle_sql); i++ {
   220  			select_2 := mock_frontend.NewMockComputationWrapper(ctrl)
   221  			stmts, err = parsers.Parse(ctx, dialect.MYSQL, self_handle_sql[i], 1, 0)
   222  			convey.So(err, convey.ShouldBeNil)
   223  			select_2.EXPECT().GetAst().Return(stmts[0]).AnyTimes()
   224  			select_2.EXPECT().GetUUID().Return(make([]byte, 16)).AnyTimes()
   225  			select_2.EXPECT().Compile(gomock.Any(), gomock.Any()).Return(runner, nil).AnyTimes()
   226  			select_2.EXPECT().Run(gomock.Any()).Return(nil, nil).AnyTimes()
   227  			select_2.EXPECT().GetLoadTag().Return(false).AnyTimes()
   228  			select_2.EXPECT().GetColumns(gomock.Any()).Return(self_handle_sql_columns[i], nil).AnyTimes()
   229  			select_2.EXPECT().RecordExecPlan(ctx).Return(nil).AnyTimes()
   230  			select_2.EXPECT().Clear().AnyTimes()
   231  			select_2.EXPECT().Free().AnyTimes()
   232  			select_2.EXPECT().Plan().Return(nil).AnyTimes()
   233  			cws = append(cws, select_2)
   234  		}
   235  
   236  		stubs := gostub.StubFunc(&GetComputationWrapper, cws, nil)
   237  		defer stubs.Reset()
   238  
   239  		pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
   240  		convey.So(err, convey.ShouldBeNil)
   241  		setGlobalPu(pu)
   242  		pu.SV.SkipCheckPrivilege = true
   243  
   244  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   245  
   246  		var gSys GlobalSystemVariables
   247  		InitGlobalSystemVariables(&gSys)
   248  
   249  		ses := NewSession(ctx, proto, nil, &gSys, true, nil)
   250  		proto.SetSession(ses)
   251  
   252  		ctx = context.WithValue(ctx, config.ParameterUnitKey, pu)
   253  
   254  		// A mock autoincrcache manager.
   255  		req := &Request{
   256  			cmd:  COM_QUERY,
   257  			data: []byte("test anywhere"),
   258  		}
   259  
   260  		ec := newTestExecCtx(ctx, ctrl)
   261  
   262  		resp, err := ExecRequest(ses, ec, req)
   263  		convey.So(err, convey.ShouldBeNil)
   264  		convey.So(resp, convey.ShouldBeNil)
   265  
   266  		req = &Request{
   267  			cmd:  COM_INIT_DB,
   268  			data: []byte("test anywhere"),
   269  		}
   270  
   271  		_, err = ExecRequest(ses, ec, req)
   272  		convey.So(err, convey.ShouldBeNil)
   273  
   274  		req = &Request{
   275  			cmd:  COM_PING,
   276  			data: []byte("test anywhere"),
   277  		}
   278  
   279  		resp, err = ExecRequest(ses, ec, req)
   280  		convey.So(err, convey.ShouldBeNil)
   281  		convey.So(resp.category, convey.ShouldEqual, OkResponse)
   282  
   283  		req = &Request{
   284  			cmd:  COM_QUIT,
   285  			data: []byte("test anywhere"),
   286  		}
   287  
   288  		resp, err = ExecRequest(ses, ec, req)
   289  		convey.So(err, convey.ShouldBeError)
   290  		convey.So(resp, convey.ShouldBeNil)
   291  
   292  	})
   293  }
   294  
   295  func Test_mce_selfhandle(t *testing.T) {
   296  	ctx := defines.AttachAccountId(context.TODO(), catalog.System_Account)
   297  	convey.Convey("handleChangeDB", t, func() {
   298  		ctrl := gomock.NewController(t)
   299  		defer ctrl.Finish()
   300  
   301  		eng := mock_frontend.NewMockEngine(ctrl)
   302  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   303  		eng.EXPECT().Hints().Return(engine.Hints{
   304  			CommitOrRollbackTimeout: time.Second,
   305  		}).AnyTimes()
   306  		cnt := 0
   307  		mockDbMeta := mock_frontend.NewMockDatabase(ctrl)
   308  		mockDbMeta.EXPECT().IsSubscription(gomock.Any()).Return(false).AnyTimes()
   309  		eng.EXPECT().Database(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
   310  			func(ctx2 context.Context, db string, dump interface{}) (engine.Database, error) {
   311  				cnt++
   312  				if cnt == 1 {
   313  					return mockDbMeta, nil
   314  				}
   315  				return nil, moerr.NewInternalError(ctx2, "fake error")
   316  			},
   317  		).AnyTimes()
   318  
   319  		txnOperator := mock_frontend.NewMockTxnOperator(ctrl)
   320  		txnOperator.EXPECT().Txn().Return(txn.TxnMeta{}).AnyTimes()
   321  		txnOperator.EXPECT().Commit(ctx).Return(nil).AnyTimes()
   322  		txnOperator.EXPECT().Rollback(ctx).Return(nil).AnyTimes()
   323  		txnOperator.EXPECT().GetWorkspace().Return(newTestWorkspace()).AnyTimes()
   324  
   325  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
   326  		txnClient.EXPECT().New(gomock.Any(), gomock.Any(), gomock.Any()).Return(txnOperator, nil).AnyTimes()
   327  
   328  		ioses := mock_frontend.NewMockIOSession(ctrl)
   329  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   330  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
   331  		ioses.EXPECT().Ref().AnyTimes()
   332  		ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
   333  		pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
   334  		if err != nil {
   335  			t.Error(err)
   336  		}
   337  		setGlobalPu(pu)
   338  
   339  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   340  
   341  		var gSys GlobalSystemVariables
   342  		InitGlobalSystemVariables(&gSys)
   343  		ses := NewSession(ctx, proto, nil, &gSys, true, nil)
   344  		ec := newTestExecCtx(ctx, ctrl)
   345  
   346  		err = handleChangeDB(ses, ec, "T")
   347  		convey.So(err, convey.ShouldBeNil)
   348  		convey.So(ses.GetDatabaseName(), convey.ShouldEqual, "T")
   349  
   350  		err = handleChangeDB(ses, ec, "T")
   351  		convey.So(err, convey.ShouldBeError)
   352  	})
   353  
   354  	convey.Convey("handleSelectDatabase/handleMaxAllowedPacket/handleVersionComment/handleCmdFieldList/handleSetVar", t, func() {
   355  		ctrl := gomock.NewController(t)
   356  		defer ctrl.Finish()
   357  
   358  		ctx, rsStubs := mockRecordStatement(ctx)
   359  		defer rsStubs.Reset()
   360  
   361  		eng := mock_frontend.NewMockEngine(ctrl)
   362  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   363  		eng.EXPECT().Database(ctx, gomock.Any(), nil).Return(nil, nil).AnyTimes()
   364  		eng.EXPECT().Hints().Return(engine.Hints{CommitOrRollbackTimeout: time.Second * 10}).AnyTimes()
   365  
   366  		txnOperator := mock_frontend.NewMockTxnOperator(ctrl)
   367  		txnOperator.EXPECT().Txn().Return(txn.TxnMeta{}).AnyTimes()
   368  		txnOperator.EXPECT().Commit(gomock.Any()).Return(nil).AnyTimes()
   369  		txnOperator.EXPECT().Rollback(gomock.Any()).Return(nil).AnyTimes()
   370  		txnOperator.EXPECT().GetWorkspace().Return(newTestWorkspace()).AnyTimes()
   371  
   372  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
   373  		txnClient.EXPECT().New(gomock.Any(), gomock.Any(), gomock.Any()).Return(txnOperator, nil).AnyTimes()
   374  
   375  		ioses := mock_frontend.NewMockIOSession(ctrl)
   376  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
   377  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   378  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
   379  		ioses.EXPECT().Ref().AnyTimes()
   380  		ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
   381  		pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
   382  		if err != nil {
   383  			t.Error(err)
   384  		}
   385  		setGlobalPu(pu)
   386  
   387  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   388  
   389  		var gSys GlobalSystemVariables
   390  		InitGlobalSystemVariables(&gSys)
   391  
   392  		ses := NewSession(ctx, proto, nil, &gSys, true, nil)
   393  
   394  		ses.mrs = &MysqlResultSet{}
   395  		proto.SetSession(ses)
   396  
   397  		ses.mrs = &MysqlResultSet{}
   398  		queryData := []byte("A")
   399  		queryData = append(queryData, 0)
   400  		query := string(queryData)
   401  		cflStmt, err := parseCmdFieldList(ctx, makeCmdFieldListSql(query))
   402  		convey.So(err, convey.ShouldBeNil)
   403  		ec := newTestExecCtx(ctx, ctrl)
   404  
   405  		err = handleCmdFieldList(ses, ec, cflStmt)
   406  		convey.So(err, convey.ShouldBeError)
   407  
   408  		ses.SetMysqlResultSet(&MysqlResultSet{})
   409  		ses.SetDatabaseName("T")
   410  		//mce.tableInfos = make(map[string][]ColumnInfo)
   411  		//mce.tableInfos["A"] = []ColumnInfo{&engineColumnInfo{
   412  		//	name: "a",
   413  		//	typ:  types.T_varchar.ToType(),
   414  		//}}
   415  
   416  		err = handleCmdFieldList(ses, ec, cflStmt)
   417  		convey.So(err, convey.ShouldBeNil)
   418  
   419  		err = handleCmdFieldList(ses, ec, cflStmt)
   420  		convey.So(err, convey.ShouldBeNil)
   421  
   422  		set := "set @@tx_isolation=`READ-COMMITTED`"
   423  		setVar, err := parsers.ParseOne(ctx, dialect.MYSQL, set, 1, 0)
   424  		convey.So(err, convey.ShouldBeNil)
   425  
   426  		err = handleSetVar(ses, ec, setVar.(*tree.SetVar), "")
   427  		convey.So(err, convey.ShouldBeNil)
   428  
   429  		req := &Request{
   430  			cmd:  COM_FIELD_LIST,
   431  			data: []byte{'A', 0},
   432  		}
   433  
   434  		resp, err := ExecRequest(ses, ec, req)
   435  		convey.So(err, convey.ShouldBeNil)
   436  		convey.So(resp, convey.ShouldBeNil)
   437  	})
   438  }
   439  
   440  func Test_getDataFromPipeline(t *testing.T) {
   441  	ctx := context.TODO()
   442  	convey.Convey("getDataFromPipeline", t, func() {
   443  		ctrl := gomock.NewController(t)
   444  		defer ctrl.Finish()
   445  
   446  		eng := mock_frontend.NewMockEngine(ctrl)
   447  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   448  		eng.EXPECT().Database(ctx, gomock.Any(), nil).Return(nil, nil).AnyTimes()
   449  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
   450  
   451  		ioses := mock_frontend.NewMockIOSession(ctrl)
   452  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
   453  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   454  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
   455  		ioses.EXPECT().Ref().AnyTimes()
   456  		ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
   457  		pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
   458  		if err != nil {
   459  			t.Error(err)
   460  		}
   461  		setGlobalPu(pu)
   462  
   463  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   464  
   465  		var gSys GlobalSystemVariables
   466  		InitGlobalSystemVariables(&gSys)
   467  
   468  		ses := NewSession(ctx, proto, nil, &gSys, true, nil)
   469  
   470  		ses.mrs = &MysqlResultSet{}
   471  		proto.ses = ses
   472  
   473  		genBatch := func() *batch.Batch {
   474  			return allocTestBatch(
   475  				[]string{
   476  					"a", "b", "c", "d", "e", "f",
   477  					"g", "h", "i", "j", "k", "l",
   478  					"m", "n",
   479  				},
   480  				[]types.Type{
   481  					types.T_int8.ToType(),
   482  					types.T_uint8.ToType(),
   483  					types.T_int16.ToType(),
   484  					types.T_uint16.ToType(),
   485  					types.T_int32.ToType(),
   486  					types.T_uint32.ToType(),
   487  					types.T_int64.ToType(),
   488  					types.T_uint64.ToType(),
   489  					types.T_float32.ToType(),
   490  					types.T_float64.ToType(),
   491  					types.T_char.ToType(),
   492  					types.T_varchar.ToType(),
   493  					types.T_date.ToType(),
   494  					types.T_time.ToType(),
   495  					types.T_datetime.ToType(),
   496  					types.T_json.ToType(),
   497  				},
   498  				3)
   499  		}
   500  
   501  		batchCase1 := genBatch()
   502  		ec := newTestExecCtx(ctx, ctrl)
   503  
   504  		err = getDataFromPipeline(ses, ec, batchCase1)
   505  		convey.So(err, convey.ShouldBeNil)
   506  
   507  		batchCase2 := func() *batch.Batch {
   508  			bat := genBatch()
   509  			for i := 0; i < len(bat.Attrs); i++ {
   510  				for j := 0; j < bat.Vecs[0].Length(); j++ {
   511  					nulls.Add(bat.Vecs[i].GetNulls(), uint64(j))
   512  				}
   513  			}
   514  			return bat
   515  		}()
   516  
   517  		err = getDataFromPipeline(ses, ec, batchCase2)
   518  		convey.So(err, convey.ShouldBeNil)
   519  	})
   520  
   521  	convey.Convey("getDataFromPipeline fail", t, func() {
   522  		ctrl := gomock.NewController(t)
   523  		defer ctrl.Finish()
   524  
   525  		eng := mock_frontend.NewMockEngine(ctrl)
   526  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   527  		ioses := mock_frontend.NewMockIOSession(ctrl)
   528  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
   529  
   530  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
   531  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
   532  		ioses.EXPECT().Ref().AnyTimes()
   533  		ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
   534  		pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
   535  		if err != nil {
   536  			t.Error(err)
   537  		}
   538  		setGlobalPu(pu)
   539  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   540  		var gSys GlobalSystemVariables
   541  		InitGlobalSystemVariables(&gSys)
   542  
   543  		ses := NewSession(ctx, proto, nil, &gSys, true, nil)
   544  
   545  		ses.mrs = &MysqlResultSet{}
   546  		proto.ses = ses
   547  		ec := newTestExecCtx(ctx, ctrl)
   548  
   549  		convey.So(getDataFromPipeline(ses, ec, nil), convey.ShouldBeNil)
   550  
   551  		genBatch := func() *batch.Batch {
   552  			return allocTestBatch(
   553  				[]string{
   554  					"a", "b", "c", "d", "e", "f",
   555  					"g", "h", "i", "j", "k", "l",
   556  					"m", "n",
   557  				},
   558  				[]types.Type{
   559  					types.T_int8.ToType(),
   560  					types.T_uint8.ToType(),
   561  					types.T_int16.ToType(),
   562  					types.T_uint16.ToType(),
   563  					types.T_int32.ToType(),
   564  					types.T_uint32.ToType(),
   565  					types.T_int64.ToType(),
   566  					types.T_uint64.ToType(),
   567  					types.T_float32.ToType(),
   568  					types.T_float64.ToType(),
   569  					types.T_char.ToType(),
   570  					types.T_varchar.ToType(),
   571  					types.T_date.ToType(),
   572  					types.T_time.ToType(),
   573  					types.T_datetime.ToType(),
   574  					types.T_json.ToType(),
   575  				},
   576  				3)
   577  		}
   578  		batchCase2 := func() *batch.Batch {
   579  			bat := genBatch()
   580  
   581  			for i := 0; i < len(bat.Attrs); i++ {
   582  				for j := 0; j < 1; j++ {
   583  					nulls.Add(bat.Vecs[i].GetNulls(), uint64(j))
   584  				}
   585  			}
   586  			return bat
   587  		}()
   588  
   589  		err = getDataFromPipeline(ses, ec, batchCase2)
   590  		convey.So(err, convey.ShouldBeNil)
   591  
   592  		batchCase2.Vecs = append(batchCase2.Vecs, vector.NewVec(types.T_any.ToType()))
   593  		err = getDataFromPipeline(ses, ec, batchCase2)
   594  		convey.So(err, convey.ShouldNotBeNil)
   595  
   596  	})
   597  }
   598  
   599  func Test_typeconvert(t *testing.T) {
   600  	ctx := context.TODO()
   601  	convey.Convey("convertEngineTypeToMysqlType", t, func() {
   602  		input := []types.T{
   603  			types.T_int8,
   604  			types.T_uint8,
   605  			types.T_int16,
   606  			types.T_uint16,
   607  			types.T_int32,
   608  			types.T_uint32,
   609  			types.T_int64,
   610  			types.T_uint64,
   611  			types.T_float32,
   612  			types.T_float64,
   613  			types.T_char,
   614  			types.T_varchar,
   615  			types.T_date,
   616  			types.T_time,
   617  			types.T_datetime,
   618  			types.T_json,
   619  			types.T_array_float32,
   620  			types.T_array_float64,
   621  			types.T_bit,
   622  		}
   623  
   624  		type kase struct {
   625  			tp     defines.MysqlType
   626  			signed bool
   627  		}
   628  		output := []kase{
   629  			{tp: defines.MYSQL_TYPE_TINY, signed: true},
   630  			{tp: defines.MYSQL_TYPE_TINY},
   631  			{tp: defines.MYSQL_TYPE_SHORT, signed: true},
   632  			{tp: defines.MYSQL_TYPE_SHORT},
   633  			{tp: defines.MYSQL_TYPE_LONG, signed: true},
   634  			{tp: defines.MYSQL_TYPE_LONG},
   635  			{tp: defines.MYSQL_TYPE_LONGLONG, signed: true},
   636  			{tp: defines.MYSQL_TYPE_LONGLONG},
   637  			{tp: defines.MYSQL_TYPE_FLOAT, signed: true},
   638  			{tp: defines.MYSQL_TYPE_DOUBLE, signed: true},
   639  			{tp: defines.MYSQL_TYPE_STRING, signed: true},
   640  			{tp: defines.MYSQL_TYPE_VAR_STRING, signed: true},
   641  			{tp: defines.MYSQL_TYPE_DATE, signed: true},
   642  			{tp: defines.MYSQL_TYPE_TIME, signed: true},
   643  			{tp: defines.MYSQL_TYPE_DATETIME, signed: true},
   644  			{tp: defines.MYSQL_TYPE_JSON, signed: true},
   645  			{tp: defines.MYSQL_TYPE_VARCHAR, signed: true},
   646  			{tp: defines.MYSQL_TYPE_VARCHAR, signed: true},
   647  			{tp: defines.MYSQL_TYPE_BIT},
   648  		}
   649  
   650  		convey.So(len(input), convey.ShouldEqual, len(output))
   651  
   652  		for i := 0; i < len(input); i++ {
   653  			col := &MysqlColumn{}
   654  			err := convertEngineTypeToMysqlType(ctx, input[i], col)
   655  			convey.So(err, convey.ShouldBeNil)
   656  			convey.So(col.columnType, convey.ShouldEqual, output[i].tp)
   657  			convey.So(col.IsSigned() && output[i].signed ||
   658  				!col.IsSigned() && !output[i].signed, convey.ShouldBeTrue)
   659  		}
   660  	})
   661  }
   662  
   663  func allocTestBatch(attrName []string, tt []types.Type, batchSize int) *batch.Batch {
   664  	batchData := batch.New(true, attrName)
   665  
   666  	//alloc space for vector
   667  	for i := 0; i < len(attrName); i++ {
   668  		vec := vector.NewVec(tt[i])
   669  		if err := vec.PreExtend(batchSize, testutil.TestUtilMp); err != nil {
   670  			panic(err)
   671  		}
   672  		vec.SetLength(batchSize)
   673  		batchData.Vecs[i] = vec
   674  	}
   675  
   676  	batchData.SetRowCount(batchSize)
   677  	return batchData
   678  }
   679  
   680  func Test_mysqlerror(t *testing.T) {
   681  	convey.Convey("mysql error", t, func() {
   682  		err := moerr.NewBadDB(context.TODO(), "T")
   683  		convey.So(err.MySQLCode(), convey.ShouldEqual, moerr.ER_BAD_DB_ERROR)
   684  	})
   685  }
   686  
   687  func Test_handleShowVariables(t *testing.T) {
   688  	ctx := defines.AttachAccountId(context.TODO(), 0)
   689  	convey.Convey("handleShowVariables succ", t, func() {
   690  		ctrl := gomock.NewController(t)
   691  		defer ctrl.Finish()
   692  
   693  		eng := mock_frontend.NewMockEngine(ctrl)
   694  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   695  		eng.EXPECT().Database(gomock.Any(), gomock.Any(), nil).Return(nil, nil).AnyTimes()
   696  
   697  		txnOperator := mock_frontend.NewMockTxnOperator(ctrl)
   698  		txnOperator.EXPECT().Commit(gomock.Any()).Return(nil).AnyTimes()
   699  		txnOperator.EXPECT().Rollback(gomock.Any()).Return(nil).AnyTimes()
   700  
   701  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
   702  		txnClient.EXPECT().New(gomock.Any(), gomock.Any()).Return(txnOperator, nil).AnyTimes()
   703  
   704  		ioses := mock_frontend.NewMockIOSession(ctrl)
   705  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
   706  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   707  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
   708  		ioses.EXPECT().Ref().AnyTimes()
   709  		ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
   710  		pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
   711  		if err != nil {
   712  			t.Error(err)
   713  		}
   714  		setGlobalPu(pu)
   715  
   716  		pu.StorageEngine = eng
   717  		pu.TxnClient = txnClient
   718  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   719  		var gSys GlobalSystemVariables
   720  		InitGlobalSystemVariables(&gSys)
   721  		ses := NewSession(ctx, proto, nil, &gSys, true, nil)
   722  
   723  		tenant := &TenantInfo{
   724  			Tenant:   "sys",
   725  			TenantID: 0,
   726  			User:     DefaultTenantMoAdmin,
   727  		}
   728  		ses.SetTenantInfo(tenant)
   729  		ses.mrs = &MysqlResultSet{}
   730  		ses.SetDatabaseName("t")
   731  		proto.SetSession(ses)
   732  		ec := newTestExecCtx(ctx, ctrl)
   733  
   734  		sv := &tree.ShowVariables{Global: false}
   735  		convey.So(handleShowVariables(ses, ec, sv), convey.ShouldBeNil)
   736  
   737  		bh := &backgroundExecTest{}
   738  		bh.init()
   739  
   740  		bhStub := gostub.StubFunc(&NewBackgroundExec, bh)
   741  		defer bhStub.Reset()
   742  		bh.init()
   743  		ses.mrs = &MysqlResultSet{}
   744  
   745  		sql := getSystemVariablesWithAccount(0)
   746  		rows := [][]interface{}{
   747  			{"syspublications", ""},
   748  		}
   749  
   750  		bh.sql2result[sql] = newMrsForSystemVariablesOfAccount(rows)
   751  		sv = &tree.ShowVariables{Global: true}
   752  		convey.So(handleShowVariables(ses, ec, sv), convey.ShouldBeNil)
   753  	})
   754  }
   755  
   756  func Test_GetColumns(t *testing.T) {
   757  	convey.Convey("GetColumns succ", t, func() {
   758  		//cw := &ComputationWrapperImpl{exec: &compile.Exec{}}
   759  		//mysqlCols, err := cw.GetColumns()
   760  		//convey.So(mysqlCols, convey.ShouldBeEmpty)
   761  		//convey.So(err, convey.ShouldBeNil)
   762  	})
   763  }
   764  
   765  func Test_GetComputationWrapper(t *testing.T) {
   766  	convey.Convey("GetComputationWrapper succ", t, func() {
   767  		db, sql, user := "T", "SHOW TABLES", "root"
   768  		var eng engine.Engine
   769  		proc := &process.Process{}
   770  		InitGlobalSystemVariables(GSysVariables)
   771  		ses := &Session{planCache: newPlanCache(1),
   772  			feSessionImpl: feSessionImpl{
   773  				gSysVars: GSysVariables,
   774  			},
   775  		}
   776  		ctrl := gomock.NewController(t)
   777  		ec := newTestExecCtx(context.Background(), ctrl)
   778  		ec.ses = ses
   779  		ec.input = &UserInput{sql: sql}
   780  
   781  		cw, err := GetComputationWrapper(ec, db, user, eng, proc, ses)
   782  		convey.So(cw, convey.ShouldNotBeEmpty)
   783  		convey.So(err, convey.ShouldBeNil)
   784  	})
   785  }
   786  
   787  func runTestHandle(funName string, t *testing.T, handleFun func(ses *Session) error) {
   788  	ctx := context.TODO()
   789  	convey.Convey(fmt.Sprintf("%s succ", funName), t, func() {
   790  		ctrl := gomock.NewController(t)
   791  		defer ctrl.Finish()
   792  
   793  		eng := mock_frontend.NewMockEngine(ctrl)
   794  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   795  		eng.EXPECT().Database(ctx, gomock.Any(), nil).Return(nil, nil).AnyTimes()
   796  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
   797  
   798  		ioses := mock_frontend.NewMockIOSession(ctrl)
   799  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
   800  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   801  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
   802  		ioses.EXPECT().Ref().AnyTimes()
   803  		ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
   804  		pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
   805  		if err != nil {
   806  			t.Error(err)
   807  		}
   808  		setGlobalPu(pu)
   809  
   810  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   811  		var gSys GlobalSystemVariables
   812  		InitGlobalSystemVariables(&gSys)
   813  		ses := NewSession(ctx, proto, nil, &gSys, true, nil)
   814  
   815  		ses.mrs = &MysqlResultSet{}
   816  		ses.txnCompileCtx.execCtx = &ExecCtx{reqCtx: ctx, proc: testutil.NewProc(), ses: ses}
   817  
   818  		convey.So(handleFun(ses), convey.ShouldBeNil)
   819  	})
   820  }
   821  
   822  func Test_HandlePrepareStmt(t *testing.T) {
   823  	ctx := defines.AttachAccountId(context.TODO(), catalog.System_Account)
   824  	stmt, err := parsers.ParseOne(ctx, dialect.MYSQL, "Prepare stmt1 from select 1, 2", 1, 0)
   825  	if err != nil {
   826  		t.Errorf("parser sql error %v", err)
   827  	}
   828  	ctrl := gomock.NewController(t)
   829  	defer ctrl.Finish()
   830  	ec := newTestExecCtx(ctx, ctrl)
   831  
   832  	runTestHandle("handlePrepareStmt", t, func(ses *Session) error {
   833  		stmt := stmt.(*tree.PrepareStmt)
   834  		_, err := handlePrepareStmt(ses, ec, stmt)
   835  		return err
   836  	})
   837  }
   838  
   839  func Test_HandleDeallocate(t *testing.T) {
   840  	ctx := defines.AttachAccountId(context.TODO(), catalog.System_Account)
   841  	stmt, err := parsers.ParseOne(ctx, dialect.MYSQL, "deallocate Prepare stmt1", 1, 0)
   842  	if err != nil {
   843  		t.Errorf("parser sql error %v", err)
   844  	}
   845  	ctrl := gomock.NewController(t)
   846  	defer ctrl.Finish()
   847  	ec := newTestExecCtx(ctx, ctrl)
   848  
   849  	runTestHandle("handleDeallocate", t, func(ses *Session) error {
   850  		stmt := stmt.(*tree.Deallocate)
   851  		return handleDeallocate(ses, ec, stmt)
   852  	})
   853  }
   854  
   855  func Test_CMD_FIELD_LIST(t *testing.T) {
   856  	ctx := defines.AttachAccountId(context.TODO(), catalog.System_Account)
   857  	convey.Convey("cmd field list", t, func() {
   858  		runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime())
   859  		queryData := []byte("A")
   860  		queryData = append(queryData, 0)
   861  		query := string(queryData)
   862  		cmdFieldListQuery := makeCmdFieldListSql(query)
   863  		convey.So(isCmdFieldListSql(cmdFieldListQuery), convey.ShouldBeTrue)
   864  		stmt, err := parseCmdFieldList(ctx, cmdFieldListQuery)
   865  		convey.So(err, convey.ShouldBeNil)
   866  		convey.So(stmt, convey.ShouldNotBeNil)
   867  		s := stmt.String()
   868  		convey.So(isCmdFieldListSql(s), convey.ShouldBeTrue)
   869  
   870  		ctrl := gomock.NewController(t)
   871  		defer ctrl.Finish()
   872  
   873  		ctx, rsStubs := mockRecordStatement(ctx)
   874  		defer rsStubs.Reset()
   875  
   876  		eng := mock_frontend.NewMockEngine(ctrl)
   877  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   878  		db := mock_frontend.NewMockDatabase(ctrl)
   879  		db.EXPECT().Relations(ctx).Return([]string{"t"}, nil).AnyTimes()
   880  
   881  		table := mock_frontend.NewMockRelation(ctrl)
   882  		db.EXPECT().Relation(ctx, "t", nil).Return(table, nil).AnyTimes()
   883  		defs := []engine.TableDef{
   884  			&engine.AttributeDef{Attr: engine.Attribute{Name: "a", Type: types.T_char.ToType()}},
   885  			&engine.AttributeDef{Attr: engine.Attribute{Name: "b", Type: types.T_int32.ToType()}},
   886  		}
   887  
   888  		table.EXPECT().TableDefs(ctx).Return(defs, nil).AnyTimes()
   889  		eng.EXPECT().Database(ctx, gomock.Any(), nil).Return(db, nil).AnyTimes()
   890  		eng.EXPECT().Hints().Return(engine.Hints{
   891  			CommitOrRollbackTimeout: time.Second,
   892  		}).AnyTimes()
   893  
   894  		txnOperator := mock_frontend.NewMockTxnOperator(ctrl)
   895  		txnOperator.EXPECT().Commit(gomock.Any()).Return(nil).AnyTimes()
   896  		txnOperator.EXPECT().Rollback(gomock.Any()).Return(nil).AnyTimes()
   897  		txnOperator.EXPECT().Txn().Return(txn.TxnMeta{}).AnyTimes()
   898  		txnOperator.EXPECT().GetWorkspace().Return(newTestWorkspace()).AnyTimes()
   899  
   900  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
   901  		txnClient.EXPECT().New(gomock.Any(), gomock.Any(), gomock.Any()).Return(txnOperator, nil).AnyTimes()
   902  
   903  		ioses := mock_frontend.NewMockIOSession(ctrl)
   904  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
   905  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   906  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
   907  		ioses.EXPECT().Ref().AnyTimes()
   908  		ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
   909  		pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
   910  		if err != nil {
   911  			t.Error(err)
   912  		}
   913  		setGlobalPu(pu)
   914  
   915  		pu.StorageEngine = eng
   916  		pu.TxnClient = txnClient
   917  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   918  		var gSys GlobalSystemVariables
   919  		InitGlobalSystemVariables(&gSys)
   920  		ses := NewSession(ctx, proto, nil, &gSys, true, nil)
   921  		proto.SetSession(ses)
   922  
   923  		ses.mrs = &MysqlResultSet{}
   924  		ses.SetDatabaseName("t")
   925  		ses.seqLastValue = new(string)
   926  
   927  		ec := newTestExecCtx(ctx, ctrl)
   928  
   929  		err = doComQuery(ses, ec, &UserInput{sql: cmdFieldListQuery})
   930  		convey.So(err, convey.ShouldBeNil)
   931  	})
   932  }
   933  
   934  func Test_fakeoutput(t *testing.T) {
   935  	convey.Convey("fake outout", t, func() {
   936  		mrs := &MysqlResultSet{}
   937  		fo := newFakeOutputQueue(mrs)
   938  		_, _ = fo.getEmptyRow()
   939  		_ = fo.flush()
   940  	})
   941  }
   942  
   943  func Test_statement_type(t *testing.T) {
   944  	convey.Convey("statement", t, func() {
   945  		type kase struct {
   946  			stmt tree.Statement
   947  		}
   948  		kases := []kase{
   949  			{&tree.CreateTable{}},
   950  			{&tree.Insert{}},
   951  			{&tree.BeginTransaction{}},
   952  			{&tree.ShowTables{}},
   953  			{&tree.Use{}},
   954  		}
   955  		ctrl := gomock.NewController(t)
   956  		defer ctrl.Finish()
   957  		ses := newTestSession(t, ctrl)
   958  		for _, k := range kases {
   959  			ret, _ := statementCanBeExecutedInUncommittedTransaction(context.TODO(), ses, k.stmt)
   960  			convey.So(ret, convey.ShouldBeTrue)
   961  		}
   962  
   963  		convey.So(IsDDL(&tree.CreateTable{}), convey.ShouldBeTrue)
   964  		convey.So(IsDropStatement(&tree.DropTable{}), convey.ShouldBeTrue)
   965  		convey.So(IsAdministrativeStatement(&tree.CreateAccount{}), convey.ShouldBeTrue)
   966  		convey.So(IsParameterModificationStatement(&tree.SetVar{}), convey.ShouldBeTrue)
   967  		convey.So(NeedToBeCommittedInActiveTransaction(&tree.SetVar{}), convey.ShouldBeTrue)
   968  		convey.So(NeedToBeCommittedInActiveTransaction(&tree.DropTable{}), convey.ShouldBeFalse)
   969  		convey.So(NeedToBeCommittedInActiveTransaction(&tree.CreateAccount{}), convey.ShouldBeTrue)
   970  		convey.So(NeedToBeCommittedInActiveTransaction(nil), convey.ShouldBeFalse)
   971  	})
   972  }
   973  
   974  func Test_convert_type(t *testing.T) {
   975  	ctx := context.TODO()
   976  	convey.Convey("type conversion", t, func() {
   977  		convertEngineTypeToMysqlType(ctx, types.T_any, &MysqlColumn{})
   978  		convertEngineTypeToMysqlType(ctx, types.T_bool, &MysqlColumn{})
   979  		convertEngineTypeToMysqlType(ctx, types.T_timestamp, &MysqlColumn{})
   980  		convertEngineTypeToMysqlType(ctx, types.T_decimal64, &MysqlColumn{})
   981  		convertEngineTypeToMysqlType(ctx, types.T_decimal128, &MysqlColumn{})
   982  		convertEngineTypeToMysqlType(ctx, types.T_blob, &MysqlColumn{})
   983  		convertEngineTypeToMysqlType(ctx, types.T_text, &MysqlColumn{})
   984  	})
   985  }
   986  func TestSerializePlanToJson(t *testing.T) {
   987  	sqls := []string{
   988  		"SELECT N_NAME, N_REGIONKEY FROM NATION WHERE N_REGIONKEY > 0 AND N_NAME LIKE '%AA' ORDER BY N_NAME DESC, N_REGIONKEY LIMIT 10, 20",
   989  		"SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_REGIONKEY > 0 ORDER BY a DESC",                                                                                  //test alias
   990  		"SELECT N_NAME, count(distinct N_REGIONKEY) FROM NATION group by N_NAME",                                                                                          //test distinct agg function
   991  		"SELECT N_NAME, MAX(N_REGIONKEY) FROM NATION GROUP BY N_NAME HAVING MAX(N_REGIONKEY) > 10",                                                                        //test agg
   992  		"SELECT N_REGIONKEY + 2 as a, N_REGIONKEY/2, N_REGIONKEY* N_NATIONKEY, N_REGIONKEY % N_NATIONKEY, N_REGIONKEY - N_NATIONKEY FROM NATION WHERE -N_NATIONKEY < -20", //test more expr
   993  		"SELECT N_REGIONKEY FROM NATION where N_REGIONKEY >= N_NATIONKEY or (N_NAME like '%ddd' and N_REGIONKEY >0.5)",                                                    //test more expr
   994  		"SELECT N_NAME,N_REGIONKEY FROM NATION join REGION on NATION.N_REGIONKEY = REGION.R_REGIONKEY",
   995  		"SELECT N_NAME, N_REGIONKEY FROM NATION join REGION on NATION.N_REGIONKEY = REGION.R_REGIONKEY WHERE NATION.N_REGIONKEY > 0",
   996  		"SELECT N_NAME, NATION2.R_REGIONKEY FROM NATION2 join REGION using(R_REGIONKEY) WHERE NATION2.R_REGIONKEY > 0",
   997  		"select n_name from nation intersect all select n_name from nation2",
   998  		"select col1 from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a(col1, col2) where col2 > 0 order by col1",
   999  		"select c_custkey from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a join NATION b on a.c_custkey = b.N_REGIONKEY where b.N_NATIONKEY > 10",
  1000  	}
  1001  
  1002  	for _, sql := range sqls {
  1003  		mock := plan.NewMockOptimizer(false)
  1004  		plan, err := buildSingleSql(mock, t, sql)
  1005  		if err != nil {
  1006  			t.Fatalf("%+v", err)
  1007  		}
  1008  		uid, _ := uuid.NewV7()
  1009  		stm := &motrace.StatementInfo{StatementID: uid, Statement: sql, RequestAt: time.Now()}
  1010  		h := NewMarshalPlanHandler(mock.CurrentContext().GetContext(), stm, plan)
  1011  		json := h.Marshal(mock.CurrentContext().GetContext())
  1012  		_, stats := h.Stats(mock.CurrentContext().GetContext())
  1013  		require.Equal(t, int64(0), stats.RowsRead)
  1014  		require.Equal(t, int64(0), stats.BytesScan)
  1015  		t.Logf("SQL plan to json : %s\n", string(json))
  1016  	}
  1017  }
  1018  
  1019  func buildSingleSql(opt plan.Optimizer, t *testing.T, sql string) (*plan.Plan, error) {
  1020  	stmts, err := mysql.Parse(opt.CurrentContext().GetContext(), sql, 1, 0)
  1021  	if err != nil {
  1022  		t.Fatalf("%+v", err)
  1023  	}
  1024  	// this sql always return one stmt
  1025  	ctx := opt.CurrentContext()
  1026  	return plan.BuildPlan(ctx, stmts[0], false)
  1027  }
  1028  
  1029  func Test_getSqlType(t *testing.T) {
  1030  	convey.Convey("call genSqlSourceType func", t, func() {
  1031  		sql := "use db"
  1032  		ses := &Session{}
  1033  		ui := &UserInput{sql: sql}
  1034  		ui.genSqlSourceType(ses)
  1035  		convey.So(ui.getSqlSourceTypes()[0], convey.ShouldEqual, constant.InternalSql)
  1036  
  1037  		user := "special_user"
  1038  		tenant := &TenantInfo{
  1039  			User: user,
  1040  		}
  1041  		ses.SetTenantInfo(tenant)
  1042  		SetSpecialUser(user, nil)
  1043  		ui = &UserInput{sql: sql}
  1044  		ui.genSqlSourceType(ses)
  1045  		convey.So(ui.getSqlSourceTypes()[0], convey.ShouldEqual, constant.InternalSql)
  1046  
  1047  		tenant.User = "dump"
  1048  		ui = &UserInput{sql: sql}
  1049  		ui.genSqlSourceType(ses)
  1050  		convey.So(ui.getSqlSourceTypes()[0], convey.ShouldEqual, constant.ExternSql)
  1051  
  1052  		sql = "/* cloud_user */ use db"
  1053  		ui = &UserInput{sql: sql}
  1054  		ui.genSqlSourceType(ses)
  1055  		convey.So(ui.getSqlSourceTypes()[0], convey.ShouldEqual, constant.CloudUserSql)
  1056  
  1057  		sql = "/* cloud_nonuser */ use db"
  1058  		ui = &UserInput{sql: sql}
  1059  		ui.genSqlSourceType(ses)
  1060  		convey.So(ui.getSqlSourceTypes()[0], convey.ShouldEqual, constant.CloudNoUserSql)
  1061  
  1062  		sql = "/* json */ use db"
  1063  		ui = &UserInput{sql: sql}
  1064  		ui.genSqlSourceType(ses)
  1065  		convey.So(ui.getSqlSourceTypes()[0], convey.ShouldEqual, constant.ExternSql)
  1066  	})
  1067  }
  1068  
  1069  func TestProcessLoadLocal(t *testing.T) {
  1070  	convey.Convey("call processLoadLocal func", t, func() {
  1071  		param := &tree.ExternParam{
  1072  			ExParamConst: tree.ExParamConst{
  1073  				Filepath: "test.csv",
  1074  			},
  1075  		}
  1076  		proc := testutil.NewProc()
  1077  		var writer *io.PipeWriter
  1078  		proc.LoadLocalReader, writer = io.Pipe()
  1079  		ctrl := gomock.NewController(t)
  1080  		defer ctrl.Finish()
  1081  		ioses := mock_frontend.NewMockIOSession(ctrl)
  1082  		cnt := 0
  1083  		ioses.EXPECT().Read(gomock.Any()).DoAndReturn(func(options goetty.ReadOptions) (pkt any, err error) {
  1084  			if cnt == 0 {
  1085  				pkt = &Packet{Length: 5, Payload: []byte("hello"), SequenceID: 1}
  1086  			} else if cnt == 1 {
  1087  				pkt = &Packet{Length: 5, Payload: []byte("world"), SequenceID: 2}
  1088  			} else {
  1089  				err = moerr.NewInvalidInput(context.TODO(), "length 0")
  1090  			}
  1091  			cnt++
  1092  			return
  1093  		}).AnyTimes()
  1094  		ioses.EXPECT().Close().AnyTimes()
  1095  		proto := &FakeProtocol{
  1096  			ioses: ioses,
  1097  		}
  1098  
  1099  		ses := &Session{
  1100  			feSessionImpl: feSessionImpl{
  1101  				proto: proto,
  1102  			},
  1103  		}
  1104  		buffer := make([]byte, 4096)
  1105  		go func(buf []byte) {
  1106  			tmp := buf
  1107  			for {
  1108  				n, err := proc.LoadLocalReader.Read(tmp)
  1109  				if err != nil {
  1110  					break
  1111  				}
  1112  				tmp = tmp[n:]
  1113  			}
  1114  		}(buffer)
  1115  		ec := newTestExecCtx(context.Background(), ctrl)
  1116  		err := processLoadLocal(ses, ec, param, writer)
  1117  		convey.So(err, convey.ShouldBeNil)
  1118  		convey.So(buffer[:10], convey.ShouldResemble, []byte("helloworld"))
  1119  		convey.So(buffer[10:], convey.ShouldResemble, make([]byte, 4096-10))
  1120  	})
  1121  }
  1122  
  1123  func Test_StatementClassify(t *testing.T) {
  1124  	type arg struct {
  1125  		stmt tree.Statement
  1126  		want bool
  1127  	}
  1128  
  1129  	args := []arg{
  1130  		{&tree.ShowCreateTable{}, true},
  1131  		{&tree.ShowCreateView{}, true},
  1132  		{&tree.ShowCreateDatabase{}, true},
  1133  		{&tree.ShowColumns{}, true},
  1134  		{&tree.ShowDatabases{}, true},
  1135  		{&tree.ShowTarget{}, true},
  1136  		{&tree.ShowTableStatus{}, true},
  1137  		{&tree.ShowGrants{}, true},
  1138  		{&tree.ShowTables{}, true},
  1139  		{&tree.ShowProcessList{}, true},
  1140  		{&tree.ShowErrors{}, true},
  1141  		{&tree.ShowWarnings{}, true},
  1142  		{&tree.ShowCollation{}, true},
  1143  		{&tree.ShowVariables{}, true},
  1144  		{&tree.ShowStatus{}, true},
  1145  		{&tree.ShowIndex{}, true},
  1146  		{&tree.ShowFunctionOrProcedureStatus{}, true},
  1147  		{&tree.ShowNodeList{}, true},
  1148  		{&tree.ShowLocks{}, true},
  1149  		{&tree.ShowTableNumber{}, true},
  1150  		{&tree.ShowColumnNumber{}, true},
  1151  		{&tree.ShowTableValues{}, true},
  1152  		{&tree.ShowAccounts{}, true},
  1153  		{&tree.ShowAccountUpgrade{}, true},
  1154  		{&tree.ShowPublications{}, true},
  1155  		{&tree.ShowCreatePublications{}, true},
  1156  		{&tree.ShowBackendServers{}, true},
  1157  	}
  1158  	ses := &Session{
  1159  		feSessionImpl: feSessionImpl{},
  1160  	}
  1161  	for _, a := range args {
  1162  		ret, err := statementCanBeExecutedInUncommittedTransaction(context.TODO(), ses, a.stmt)
  1163  		assert.Nil(t, err)
  1164  		assert.Equal(t, ret, a.want)
  1165  	}
  1166  }
  1167  
  1168  func TestMysqlCmdExecutor_HandleShowBackendServers(t *testing.T) {
  1169  	ctx := context.TODO()
  1170  	runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime())
  1171  	ctrl := gomock.NewController(t)
  1172  	defer ctrl.Finish()
  1173  
  1174  	eng := mock_frontend.NewMockEngine(ctrl)
  1175  	eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
  1176  	eng.EXPECT().Database(ctx, gomock.Any(), nil).Return(nil, nil).AnyTimes()
  1177  	txnClient := mock_frontend.NewMockTxnClient(ctrl)
  1178  
  1179  	ioses := mock_frontend.NewMockIOSession(ctrl)
  1180  	ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
  1181  	ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
  1182  	ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
  1183  	ioses.EXPECT().Ref().AnyTimes()
  1184  	ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
  1185  	pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
  1186  	if err != nil {
  1187  		t.Error(err)
  1188  	}
  1189  	setGlobalPu(pu)
  1190  
  1191  	proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
  1192  	var gSys GlobalSystemVariables
  1193  	InitGlobalSystemVariables(&gSys)
  1194  	ses := NewSession(ctx, proto, nil, &gSys, true, nil)
  1195  
  1196  	ses.GetMysqlProtocol()
  1197  	proto.SetSession(ses)
  1198  	ses.proto = proto
  1199  
  1200  	convey.Convey("no labels", t, func() {
  1201  		ses.mrs = &MysqlResultSet{}
  1202  		cluster := clusterservice.NewMOCluster(
  1203  			nil,
  1204  			0,
  1205  			clusterservice.WithDisableRefresh(),
  1206  			clusterservice.WithServices(
  1207  				[]metadata.CNService{
  1208  					{
  1209  						ServiceID:  "s1",
  1210  						SQLAddress: "addr1",
  1211  						WorkState:  metadata.WorkState_Working,
  1212  					},
  1213  					{
  1214  						ServiceID:  "s2",
  1215  						SQLAddress: "addr2",
  1216  						WorkState:  metadata.WorkState_Working,
  1217  					},
  1218  				},
  1219  				nil,
  1220  			),
  1221  		)
  1222  		runtime.ProcessLevelRuntime().SetGlobalVariables(runtime.ClusterService, cluster)
  1223  		ses.SetTenantInfo(&TenantInfo{Tenant: "t1"})
  1224  		proto.connectAttrs = map[string]string{}
  1225  		ec := newTestExecCtx(ctx, ctrl)
  1226  
  1227  		err = handleShowBackendServers(ses, ec)
  1228  		require.NoError(t, err)
  1229  		rs := ses.GetMysqlResultSet()
  1230  		require.Equal(t, uint64(4), rs.GetColumnCount())
  1231  		require.Equal(t, uint64(2), rs.GetRowCount())
  1232  	})
  1233  
  1234  	convey.Convey("filter label", t, func() {
  1235  		ses.mrs = &MysqlResultSet{}
  1236  		cluster := clusterservice.NewMOCluster(
  1237  			nil,
  1238  			0,
  1239  			clusterservice.WithDisableRefresh(),
  1240  			clusterservice.WithServices(
  1241  				[]metadata.CNService{
  1242  					{
  1243  						ServiceID:  "s1",
  1244  						SQLAddress: "addr1",
  1245  						Labels: map[string]metadata.LabelList{
  1246  							"account": {Labels: []string{"t1"}},
  1247  						},
  1248  						WorkState: metadata.WorkState_Working,
  1249  					},
  1250  					{
  1251  						ServiceID:  "s2",
  1252  						SQLAddress: "addr2",
  1253  						Labels: map[string]metadata.LabelList{
  1254  							"account": {Labels: []string{"t2"}},
  1255  						},
  1256  						WorkState: metadata.WorkState_Working,
  1257  					},
  1258  					{
  1259  						ServiceID:  "s3",
  1260  						SQLAddress: "addr3",
  1261  						WorkState:  metadata.WorkState_Working,
  1262  					},
  1263  				},
  1264  				nil,
  1265  			),
  1266  		)
  1267  		runtime.ProcessLevelRuntime().SetGlobalVariables(runtime.ClusterService, cluster)
  1268  		ses.SetTenantInfo(&TenantInfo{Tenant: "t1"})
  1269  		proto.connectAttrs = map[string]string{}
  1270  		ec := newTestExecCtx(ctx, ctrl)
  1271  
  1272  		err = handleShowBackendServers(ses, ec)
  1273  		require.NoError(t, err)
  1274  		rs := ses.GetMysqlResultSet()
  1275  		require.Equal(t, uint64(4), rs.GetColumnCount())
  1276  		require.Equal(t, uint64(1), rs.GetRowCount())
  1277  
  1278  		row, err := rs.GetRow(ctx, 0)
  1279  		require.NoError(t, err)
  1280  		require.Equal(t, "s1", row[0])
  1281  		require.Equal(t, "addr1", row[1])
  1282  	})
  1283  }
  1284  
  1285  func Test_RecordParseErrorStatement(t *testing.T) {
  1286  	ctrl := gomock.NewController(t)
  1287  	defer ctrl.Finish()
  1288  	ses := newTestSession(t, ctrl)
  1289  
  1290  	proc := &process.Process{
  1291  		Ctx: context.TODO(),
  1292  	}
  1293  
  1294  	motrace.GetTracerProvider().SetEnable(true)
  1295  	ctx, err := RecordParseErrorStatement(context.TODO(), ses, proc, time.Now(), nil, nil, moerr.NewInternalErrorNoCtx("test"))
  1296  	assert.Nil(t, err)
  1297  	si := motrace.StatementFromContext(ctx)
  1298  	require.NotNil(t, si)
  1299  
  1300  	ctx, err = RecordParseErrorStatement(context.TODO(), ses, proc, time.Now(), []string{"abc", "def"}, []string{constant.ExternSql, constant.ExternSql}, moerr.NewInternalErrorNoCtx("test"))
  1301  	assert.Nil(t, err)
  1302  	si = motrace.StatementFromContext(ctx)
  1303  	require.NotNil(t, si)
  1304  
  1305  }
  1306  
  1307  func Test_getExplainOption(t *testing.T) {
  1308  	ctx := context.TODO()
  1309  	var option *explain.ExplainOptions
  1310  	var err error
  1311  
  1312  	// verbose
  1313  	option, err = getExplainOption(ctx, []tree.OptionElem{{Name: "verbose", Value: "true"}})
  1314  	require.Nil(t, err)
  1315  	require.Equal(t, option.Verbose, true)
  1316  
  1317  	option, err = getExplainOption(ctx, []tree.OptionElem{{Name: "verbose", Value: "NULL"}})
  1318  	require.Nil(t, err)
  1319  	require.Equal(t, option.Verbose, true)
  1320  
  1321  	option, err = getExplainOption(ctx, []tree.OptionElem{{Name: "verbose", Value: "false"}})
  1322  	require.Nil(t, err)
  1323  	require.Equal(t, option.Verbose, false)
  1324  
  1325  	_, err = getExplainOption(ctx, []tree.OptionElem{{Name: "verbose", Value: "???"}})
  1326  	require.NotNil(t, err)
  1327  
  1328  	// analyze
  1329  	option, err = getExplainOption(ctx, []tree.OptionElem{{Name: "analyze", Value: "true"}})
  1330  	require.Nil(t, err)
  1331  	require.Equal(t, option.Analyze, true)
  1332  
  1333  	option, err = getExplainOption(ctx, []tree.OptionElem{{Name: "analyze", Value: "NULL"}})
  1334  	require.Nil(t, err)
  1335  	require.Equal(t, option.Analyze, true)
  1336  
  1337  	option, err = getExplainOption(ctx, []tree.OptionElem{{Name: "analyze", Value: "false"}})
  1338  	require.Nil(t, err)
  1339  	require.Equal(t, option.Analyze, false)
  1340  
  1341  	_, err = getExplainOption(ctx, []tree.OptionElem{{Name: "analyze", Value: "???"}})
  1342  	require.NotNil(t, err)
  1343  
  1344  	// format
  1345  	option, err = getExplainOption(ctx, []tree.OptionElem{{Name: "format", Value: "text"}})
  1346  	require.Nil(t, err)
  1347  	require.Equal(t, option.Format, explain.EXPLAIN_FORMAT_TEXT)
  1348  
  1349  	_, err = getExplainOption(ctx, []tree.OptionElem{{Name: "format", Value: "json"}})
  1350  	require.NotNil(t, err)
  1351  
  1352  	_, err = getExplainOption(ctx, []tree.OptionElem{{Name: "format", Value: "dot"}})
  1353  	require.NotNil(t, err)
  1354  
  1355  	_, err = getExplainOption(ctx, []tree.OptionElem{{Name: "format", Value: "???"}})
  1356  	require.NotNil(t, err)
  1357  
  1358  	// other
  1359  	_, err = getExplainOption(ctx, []tree.OptionElem{{Name: "???", Value: "???"}})
  1360  	require.NotNil(t, err)
  1361  }
  1362  
  1363  func Test_ExecRequest(t *testing.T) {
  1364  	ctx := context.TODO()
  1365  	convey.Convey("boot mce succ", t, func() {
  1366  		ctrl := gomock.NewController(t)
  1367  		defer ctrl.Finish()
  1368  
  1369  		ctx, rsStubs := mockRecordStatement(ctx)
  1370  		defer rsStubs.Reset()
  1371  
  1372  		srStub := gostub.Stub(&parsers.HandleSqlForRecord, func(sql string) []string {
  1373  			return make([]string, 7)
  1374  		})
  1375  		defer srStub.Reset()
  1376  
  1377  		eng := mock_frontend.NewMockEngine(ctrl)
  1378  		eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
  1379  		eng.EXPECT().Hints().Return(engine.Hints{
  1380  			CommitOrRollbackTimeout: time.Second,
  1381  		}).AnyTimes()
  1382  		txnOperator := mock_frontend.NewMockTxnOperator(ctrl)
  1383  		txnOperator.EXPECT().Txn().Return(txn.TxnMeta{}).AnyTimes()
  1384  		eng.EXPECT().Database(ctx, gomock.Any(), txnOperator).Return(nil, nil).AnyTimes()
  1385  
  1386  		txnOperator.EXPECT().Commit(gomock.Any()).Return(nil).AnyTimes()
  1387  		txnOperator.EXPECT().Rollback(gomock.Any()).Return(nil).AnyTimes()
  1388  
  1389  		txnClient := mock_frontend.NewMockTxnClient(ctrl)
  1390  		txnClient.EXPECT().New(gomock.Any(), gomock.Any()).Return(txnOperator, nil).AnyTimes()
  1391  
  1392  		ioses := mock_frontend.NewMockIOSession(ctrl)
  1393  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
  1394  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
  1395  		ioses.EXPECT().RemoteAddress().Return("").AnyTimes()
  1396  		ioses.EXPECT().Ref().AnyTimes()
  1397  		ioses.EXPECT().Flush(gomock.Any()).AnyTimes()
  1398  		use_t := mock_frontend.NewMockComputationWrapper(ctrl)
  1399  		use_t.EXPECT().GetUUID().Return(make([]byte, 16)).AnyTimes()
  1400  		stmts, err := parsers.Parse(ctx, dialect.MYSQL, "use T", 1, 0)
  1401  		if err != nil {
  1402  			t.Error(err)
  1403  		}
  1404  		use_t.EXPECT().GetAst().Return(stmts[0]).AnyTimes()
  1405  		use_t.EXPECT().RecordExecPlan(ctx).Return(nil).AnyTimes()
  1406  		use_t.EXPECT().Clear().AnyTimes()
  1407  
  1408  		runner := mock_frontend.NewMockComputationRunner(ctrl)
  1409  		runner.EXPECT().Run(gomock.Any()).Return(nil, nil).AnyTimes()
  1410  
  1411  		pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient)
  1412  		convey.So(err, convey.ShouldBeNil)
  1413  		setGlobalPu(pu)
  1414  
  1415  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
  1416  
  1417  		var gSys GlobalSystemVariables
  1418  		InitGlobalSystemVariables(&gSys)
  1419  
  1420  		ses := NewSession(ctx, proto, nil, &gSys, true, nil)
  1421  		proto.SetSession(ses)
  1422  		ses.txnHandler = &TxnHandler{
  1423  			storage: &engine.EntireEngine{Engine: pu.StorageEngine},
  1424  		}
  1425  
  1426  		ctx = context.WithValue(ctx, config.ParameterUnitKey, pu)
  1427  
  1428  		// A mock autoincrcache manager.
  1429  		req := &Request{
  1430  			cmd:  COM_SET_OPTION,
  1431  			data: []byte("123"),
  1432  		}
  1433  		ec := newTestExecCtx(ctx, ctrl)
  1434  
  1435  		_, err = ExecRequest(ses, ec, req)
  1436  		convey.So(err, convey.ShouldBeNil)
  1437  
  1438  		req = &Request{
  1439  			cmd:  COM_SET_OPTION,
  1440  			data: []byte("1"),
  1441  		}
  1442  		_, err = ExecRequest(ses, ec, req)
  1443  		convey.So(err, convey.ShouldBeNil)
  1444  	})
  1445  }