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