github.com/matrixorigin/matrixone@v0.7.0/pkg/frontend/load_test.go (about)

     1  // Copyright 2021 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package frontend
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"os"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/golang/mock/gomock"
    25  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    26  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    27  	"github.com/matrixorigin/matrixone/pkg/container/types"
    28  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    29  	mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test"
    30  	"github.com/matrixorigin/matrixone/pkg/testutil"
    31  	"github.com/smartystreets/goconvey/convey"
    32  	"github.com/stretchr/testify/require"
    33  )
    34  
    35  func Test_readTextFile(t *testing.T) {
    36  	data, err := os.ReadFile("test/loadfile.csv")
    37  	require.NoError(t, err)
    38  	fmt.Printf("%v\n", data)
    39  }
    40  
    41  /*func Test_loadJSON(t *testing.T) {
    42  	convey.Convey("loadJSON succ", t, func() {
    43  		ctrl := gomock.NewController(t)
    44  		defer ctrl.Finish()
    45  
    46  		eng := mock_frontend.NewMockTxnEngine(ctrl)
    47      eng.EXPECT().Hints().Return(engine.Hints{
    48        CommitOrRollbackTimeout: time.Second,
    49      }).AnyTimes()
    50  		txn := mock_frontend.NewMockTxn(ctrl)
    51  		txn.EXPECT().GetCtx().Return(nil).AnyTimes()
    52  		txn.EXPECT().Commit().Return(nil).AnyTimes()
    53  		txn.EXPECT().Rollback().Return(nil).AnyTimes()
    54  		txn.EXPECT().String().Return("txn0").AnyTimes()
    55  		eng.EXPECT().StartTxn(nil).Return(txn, nil).AnyTimes()
    56  
    57  		db := mock_frontend.NewMockDatabase(ctrl)
    58  		rel := mock_frontend.NewMockRelation(ctrl)
    59  		tableDefs := []engine.TableDef{
    60  			&engine.AttributeDef{
    61  				Attr: engine.Attribute{
    62  					Type: types.Type{Oid: types.T_json},
    63  					Name: "a"}},
    64  			&engine.AttributeDef{
    65  				Attr: engine.Attribute{
    66  					Type: types.Type{Oid: types.T_varchar, Width: types.MaxVarcharLen},
    67  					Name: "b"}},
    68  			&engine.AttributeDef{
    69  				Attr: engine.Attribute{
    70  					Type: types.Type{Oid: types.T_uint8},
    71  					Name: "c"}},
    72  		}
    73  		ctx := context.TODO()
    74  		rel.EXPECT().TableDefs(gomock.Any()).Return(tableDefs, nil).AnyTimes()
    75  		cnt := 0
    76  		rel.EXPECT().Write(ctx, gomock.Any()).DoAndReturn(
    77  			func(a, b interface{}) error {
    78  				cnt++
    79  				if cnt == 1 {
    80  					return nil
    81  				} else if cnt == 2 {
    82  					return context.DeadlineExceeded
    83  				}
    84  
    85  				return nil
    86  			},
    87  		).AnyTimes()
    88  		db.EXPECT().Relation(ctx, gomock.Any()).Return(rel, nil).AnyTimes()
    89  		eng.EXPECT().Database(ctx, gomock.Any(), nil).Return(db, nil).AnyTimes()
    90  
    91  		ioses := mock_frontend.NewMockIOSession(ctrl)
    92  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
    93  		ioses.EXPECT().WriteAndFlush(gomock.Any()).Return(nil).AnyTimes()
    94  
    95  		cws := []ComputationWrapper{}
    96  		var self_handle_sql = []string{
    97  			"load data " +
    98  				"infile 'test/loadfile6' " +
    99  				"ignore " +
   100  				"INTO TABLE T.A " +
   101  				"FIELDS TERMINATED BY '\t' " +
   102  				"ignore 1 lines ",
   103  			"load data " +
   104  				"infile 'test/loadfile6' " +
   105  				"ignore " +
   106  				"INTO TABLE T.A " +
   107  				"FIELDS TERMINATED BY '\t' " +
   108  				"ignore 1 lines " +
   109  				"(a, b, c)",
   110  		}
   111  		for i := 0; i < len(self_handle_sql); i++ {
   112  			select_2 := mock_frontend.NewMockComputationWrapper(ctrl)
   113  			stmts, err := parsers.Parse(dialect.MYSQL, self_handle_sql[i])
   114  			convey.So(err, convey.ShouldBeNil)
   115  			select_2.EXPECT().GetAst().Return(stmts[0]).AnyTimes()
   116  			select_2.EXPECT().SetDatabaseName(gomock.Any()).Return(nil).AnyTimes()
   117  			select_2.EXPECT().Compile(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
   118  			select_2.EXPECT().Run(gomock.Any()).Return(nil).AnyTimes()
   119  
   120  			cws = append(cws, select_2)
   121  		}
   122  
   123  		stubs := gostub.StubFunc(&GetComputationWrapper, cws, nil)
   124  		defer stubs.Reset()
   125  
   126  		stubs2 := gostub.StubFunc(&PathExists, true, true, nil)
   127  		defer stubs2.Reset()
   128  
   129  		pu, err := getParameterUnit("test/system_vars_config.toml", eng)
   130  		convey.So(err, convey.ShouldBeNil)
   131  
   132  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   133  
   134  		guestMmu := guest.New(pu.SV.GetGuestMmuLimitation(), pu.HostMmu)
   135  		config.StorageEngine = eng
   136  		defer func() {
   137  			config.StorageEngine = nil
   138  		}()
   139  		ses := NewSession(proto, guestMmu, pu.Mempool, pu, gSysVariables)
   140      ses.SetRequestContext(ctx)
   141  
   142  		mce := NewMysqlCmdExecutor()
   143  
   144  		mce.PrepareSessionBeforeExecRequest(ses)
   145  
   146  		req := &Request{
   147  			cmd:  int(COM_QUERY),
   148  			data: []byte("test anywhere"),
   149  		}
   150  
   151  		resp, err := mce.ExecRequest(req)
   152  		convey.So(err, convey.ShouldBeNil)
   153  		convey.So(resp, convey.ShouldBeNil)
   154  	})
   155  }*/
   156  
   157  /*func Test_load(t *testing.T) {
   158  	convey.Convey("load succ", t, func() {
   159  		ctrl := gomock.NewController(t)
   160  		defer ctrl.Finish()
   161  
   162  		eng := mock_frontend.NewMockTxnEngine(ctrl)
   163      eng.EXPECT().Hints().Return(engine.Hints{
   164        CommitOrRollbackTimeout: time.Second,
   165      }).AnyTimes()
   166  		txn := mock_frontend.NewMockTxn(ctrl)
   167  		txn.EXPECT().GetCtx().Return(nil).AnyTimes()
   168  		txn.EXPECT().GetID().Return(uint64(0)).AnyTimes()
   169  		txn.EXPECT().Commit().Return(nil).AnyTimes()
   170  		txn.EXPECT().Rollback().Return(nil).AnyTimes()
   171  		txn.EXPECT().String().Return("txn0").AnyTimes()
   172  		eng.EXPECT().StartTxn(nil).Return(txn, nil).AnyTimes()
   173  
   174  		db := mock_frontend.NewMockDatabase(ctrl)
   175  		rel := mock_frontend.NewMockRelation(ctrl)
   176  		//table def
   177  		tableDefs := []engine.TableDef{
   178  			&engine.AttributeDef{
   179  				Attr: engine.Attribute{
   180  					Type: types.Type{Oid: types.T_char},
   181  					Name: "a"}},
   182  			&engine.AttributeDef{
   183  				Attr: engine.Attribute{
   184  					Type: types.Type{Oid: types.T_varchar, Width: types.MaxVarcharLen},
   185  					Name: "b"}},
   186  			&engine.AttributeDef{
   187  				Attr: engine.Attribute{
   188  					Type: types.Type{Oid: types.T_uint8},
   189  					Name: "c"}},
   190  			&engine.AttributeDef{
   191  				Attr: engine.Attribute{
   192  					Type: types.Type{Oid: types.T_int8},
   193  					Name: "d"}},
   194  			&engine.AttributeDef{
   195  				Attr: engine.Attribute{
   196  					Type: types.Type{Oid: types.T_uint16},
   197  					Name: "e"}},
   198  			&engine.AttributeDef{
   199  				Attr: engine.Attribute{
   200  					Type: types.Type{Oid: types.T_int16},
   201  					Name: "f"}},
   202  			&engine.AttributeDef{
   203  				Attr: engine.Attribute{
   204  					Type: types.Type{Oid: types.T_uint32},
   205  					Name: "g"}},
   206  			&engine.AttributeDef{
   207  				Attr: engine.Attribute{
   208  					Type: types.Type{Oid: types.T_int32},
   209  					Name: "h"}},
   210  			&engine.AttributeDef{
   211  				Attr: engine.Attribute{
   212  					Type: types.Type{Oid: types.T_uint64},
   213  					Name: "i"}},
   214  			&engine.AttributeDef{
   215  				Attr: engine.Attribute{
   216  					Type: types.Type{Oid: types.T_int64},
   217  					Name: "j"}},
   218  			&engine.AttributeDef{
   219  				Attr: engine.Attribute{
   220  					Type: types.Type{Oid: types.T_float32},
   221  					Name: "k"}},
   222  			&engine.AttributeDef{
   223  				Attr: engine.Attribute{
   224  					Type: types.Type{Oid: types.T_float64},
   225  					Name: "l"}},
   226  			&engine.AttributeDef{
   227  				Attr: engine.Attribute{
   228  					Type: types.Type{Oid: types.T_date},
   229  					Name: "m"}},
   230  			&engine.AttributeDef{
   231  				Attr: engine.Attribute{
   232  					Type: types.Type{Oid: types.T_datetime},
   233  					Name: "n"}},
   234  			&engine.AttributeDef{
   235  				Attr: engine.Attribute{
   236  					Type: types.Type{
   237  						Oid:       types.T_decimal64,
   238  						Size:      0,
   239  						Width:     10,
   240  						Scale:     2,
   241  						Precision: 0,
   242  					},
   243  					Name: "o"}},
   244  			&engine.AttributeDef{
   245  				Attr: engine.Attribute{
   246  					Type: types.Type{
   247  						Oid:       types.T_decimal128,
   248  						Size:      0,
   249  						Width:     20,
   250  						Scale:     2,
   251  						Precision: 0,
   252  					},
   253  					Name: "p"}},
   254  			&engine.AttributeDef{
   255  				Attr: engine.Attribute{
   256  					Type: types.Type{
   257  						Oid:       types.T_timestamp,
   258  						Size:      0,
   259  						Width:     0,
   260  						Scale:     0,
   261  						Precision: 6,
   262  					},
   263  					Name: "r"}},
   264  		}
   265  		ctx := context.TODO()
   266  		rel.EXPECT().TableDefs(gomock.Any()).Return(tableDefs, nil).AnyTimes()
   267  		cnt := 0
   268  		rel.EXPECT().Write(ctx, gomock.Any()).DoAndReturn(
   269  			func(a, b interface{}) error {
   270  				cnt++
   271  				if cnt == 1 {
   272  					return nil
   273  				} else if cnt == 2 {
   274  					return context.DeadlineExceeded
   275  				}
   276  
   277  				return nil
   278  			},
   279  		).AnyTimes()
   280  		db.EXPECT().Relation(ctx, gomock.Any()).Return(rel, nil).AnyTimes()
   281  		eng.EXPECT().Database(ctx, gomock.Any(), nil).Return(db, nil).AnyTimes()
   282  
   283  		ioses := mock_frontend.NewMockIOSession(ctrl)
   284  		ioses.EXPECT().OutBuf().Return(buf.NewByteBuf(1024)).AnyTimes()
   285  		ioses.EXPECT().Write(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
   286  
   287  		cws := []ComputationWrapper{}
   288  
   289  		var self_handle_sql = []string{
   290  			"load data " +
   291  				"infile 'test/loadfile5' " +
   292  				"ignore " +
   293  				"INTO TABLE T.A " +
   294  				"FIELDS TERMINATED BY ',' ",
   295  			"load data " +
   296  				"infile 'test/loadfile5' " +
   297  				"ignore " +
   298  				"INTO TABLE T.A " +
   299  				"FIELDS TERMINATED BY ',' " +
   300  				"(@s,@t,c,d,e,f)",
   301  		}
   302  
   303  		for i := 0; i < len(self_handle_sql); i++ {
   304  			select_2 := mock_frontend.NewMockComputationWrapper(ctrl)
   305  			stmts, err := parsers.Parse(dialect.MYSQL, self_handle_sql[i])
   306  			convey.So(err, convey.ShouldBeNil)
   307  			select_2.EXPECT().GetAst().Return(stmts[0]).AnyTimes()
   308  			select_2.EXPECT().SetDatabaseName(gomock.Any()).Return(nil).AnyTimes()
   309  			select_2.EXPECT().Compile(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
   310  			select_2.EXPECT().Run(gomock.Any()).Return(nil).AnyTimes()
   311  
   312  			cws = append(cws, select_2)
   313  		}
   314  
   315  		stubs := gostub.StubFunc(&GetComputationWrapper, cws, nil)
   316  		defer stubs.Reset()
   317  
   318  		stubs2 := gostub.StubFunc(&PathExists, true, true, nil)
   319  		defer stubs2.Reset()
   320  
   321  		pu, err := getParameterUnit("test/system_vars_config.toml", eng)
   322  		convey.So(err, convey.ShouldBeNil)
   323  
   324  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   325  
   326  		guestMmu := guest.New(pu.SV.GuestMmuLimitation, pu.HostMmu)
   327  		ses := NewSession(proto, guestMmu, pu.Mempool, pu, gSysVariables)
   328      ses.SetRequestContext(ctx)
   329  
   330  		mce := NewMysqlCmdExecutor()
   331  
   332  		mce.PrepareSessionBeforeExecRequest(ses)
   333  
   334  		req := &Request{
   335  			cmd:  int(COM_QUERY),
   336  			data: []byte("test anywhere"),
   337  		}
   338  
   339  		resp, err := mce.ExecRequest(ctx, req)
   340  		convey.So(err, convey.ShouldBeNil)
   341  		convey.So(resp, convey.ShouldBeNil)
   342  	})
   343  
   344  	convey.Convey("load failed", t, func() {
   345  		ctrl := gomock.NewController(t)
   346  		defer ctrl.Finish()
   347  
   348  		eng := mock_frontend.NewMockTxnEngine(ctrl)
   349      eng.EXPECT().Hints().Return(engine.Hints{
   350        CommitOrRollbackTimeout: time.Second,
   351      }).AnyTimes()
   352  		txn := mock_frontend.NewMockTxn(ctrl)
   353  		txn.EXPECT().GetCtx().Return(nil).AnyTimes()
   354  		txn.EXPECT().Commit().Return(nil).AnyTimes()
   355  		txn.EXPECT().Rollback().Return(nil).AnyTimes()
   356  		txn.EXPECT().String().Return("txn0").AnyTimes()
   357  		eng.EXPECT().StartTxn(nil).Return(txn, nil).AnyTimes()
   358  
   359  		db := mock_frontend.NewMockDatabase(ctrl)
   360  		rel := mock_frontend.NewMockRelation(ctrl)
   361  		//table def
   362  		tableDefs := []engine.TableDef{
   363  			&engine.AttributeDef{
   364  				Attr: engine.Attribute{
   365  					Type: types.Type{Oid: types.T_char},
   366  					Name: "a"}},
   367  			&engine.AttributeDef{
   368  				Attr: engine.Attribute{
   369  					Type: types.Type{Oid: types.T_varchar, Width: types.MaxVarcharLen},
   370  					Name: "b"}},
   371  			&engine.AttributeDef{
   372  				Attr: engine.Attribute{
   373  					Type: types.Type{Oid: types.T_uint8},
   374  					Name: "c"}},
   375  			&engine.AttributeDef{
   376  				Attr: engine.Attribute{
   377  					Type: types.Type{Oid: types.T_int8},
   378  					Name: "d"}},
   379  			&engine.AttributeDef{
   380  				Attr: engine.Attribute{
   381  					Type: types.Type{Oid: types.T_uint16},
   382  					Name: "e"}},
   383  			&engine.AttributeDef{
   384  				Attr: engine.Attribute{
   385  					Type: types.Type{Oid: types.T_int16},
   386  					Name: "f"}},
   387  			&engine.AttributeDef{
   388  				Attr: engine.Attribute{
   389  					Type: types.Type{Oid: types.T_uint32},
   390  					Name: "g"}},
   391  			&engine.AttributeDef{
   392  				Attr: engine.Attribute{
   393  					Type: types.Type{Oid: types.T_int32},
   394  					Name: "h"}},
   395  			&engine.AttributeDef{
   396  				Attr: engine.Attribute{
   397  					Type: types.Type{Oid: types.T_uint64},
   398  					Name: "i"}},
   399  			&engine.AttributeDef{
   400  				Attr: engine.Attribute{
   401  					Type: types.Type{Oid: types.T_int64},
   402  					Name: "j"}},
   403  			&engine.AttributeDef{
   404  				Attr: engine.Attribute{
   405  					Type: types.Type{Oid: types.T_float32},
   406  					Name: "k"}},
   407  			&engine.AttributeDef{
   408  				Attr: engine.Attribute{
   409  					Type: types.Type{Oid: types.T_float64},
   410  					Name: "l"}},
   411  			&engine.AttributeDef{
   412  				Attr: engine.Attribute{
   413  					Type: types.Type{Oid: types.T_date},
   414  					Name: "m"}},
   415  			&engine.AttributeDef{
   416  				Attr: engine.Attribute{
   417  					Type: types.Type{Oid: types.T_datetime},
   418  					Name: "n"}},
   419  			&engine.AttributeDef{
   420  				Attr: engine.Attribute{
   421  					Type: types.Type{
   422  						Oid:       types.T_decimal64,
   423  						Size:      0,
   424  						Width:     10,
   425  						Scale:     2,
   426  						Precision: 0,
   427  					},
   428  					Name: "o"}},
   429  			&engine.AttributeDef{
   430  				Attr: engine.Attribute{
   431  					Type: types.Type{
   432  						Oid:       types.T_decimal128,
   433  						Size:      0,
   434  						Width:     20,
   435  						Scale:     2,
   436  						Precision: 0,
   437  					},
   438  					Name: "p"}},
   439  			&engine.AttributeDef{
   440  				Attr: engine.Attribute{
   441  					Type: types.Type{
   442  						Oid:       types.T_timestamp,
   443  						Size:      0,
   444  						Width:     0,
   445  						Scale:     0,
   446  						Precision: 6,
   447  					},
   448  					Name: "r"}},
   449  		}
   450  		ctx := context.TODO()
   451  		rel.EXPECT().TableDefs(ctx).Return(tableDefs, nil).AnyTimes()
   452  		cnt := 0
   453  		rel.EXPECT().Write(ctx, gomock.Any()).DoAndReturn(
   454  			func(a, b interface{}) error {
   455  				cnt++
   456  				if cnt == 1 {
   457  					return moerr.NewInternalError("fake error")
   458  				} else if cnt == 2 {
   459  					return moerr.NewInternalError("exec timeout")
   460  				}
   461  
   462  				return nil
   463  			},
   464  		).AnyTimes()
   465  		db.EXPECT().Relation(gomock.Any(), gomock.Any()).Return(rel, nil).AnyTimes()
   466  		eng.EXPECT().Database(ctx, gomock.Any(), nil).Return(db, nil).AnyTimes()
   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  
   472  		cws := []*tree.Load{}
   473  
   474  		type kase struct {
   475  			sql  string
   476  			fail bool
   477  		}
   478  
   479  		kases := []kase{
   480  			{
   481  				sql: "load data " +
   482  					"infile 'test/loadfile5' " +
   483  					"INTO TABLE T.A " +
   484  					"FIELDS TERMINATED BY ',' ",
   485  				fail: true,
   486  			},
   487  			{
   488  				sql: "load data " +
   489  					"infile 'test/loadfile5' " +
   490  					"INTO TABLE T.A " +
   491  					"FIELDS TERMINATED BY ',' " +
   492  					"(@a,b,d,e)",
   493  				fail: true,
   494  			},
   495  			{
   496  				sql: "load data " +
   497  					"infile 'test/loadfile5' " +
   498  					"ignore " +
   499  					"INTO TABLE T.A " +
   500  					"FIELDS TERMINATED BY ',' " +
   501  					"(@a,b,d,e)",
   502  				fail: false,
   503  			},
   504  			{
   505  				sql: "load data " +
   506  					"infile 'test/loadfile5' " +
   507  					"INTO TABLE T.A " +
   508  					"FIELDS TERMINATED BY ',' ",
   509  				fail: false,
   510  			},
   511  		}
   512  
   513  		for i := 0; i < len(kases); i++ {
   514  			stmts, err := parsers.Parse(dialect.MYSQL, kases[i].sql)
   515  			convey.So(err, convey.ShouldBeNil)
   516  			cws = append(cws, stmts[0].(*tree.Load))
   517  		}
   518  
   519  		stubs2 := gostub.StubFunc(&PathExists, true, true, nil)
   520  		defer stubs2.Reset()
   521  
   522  		pu, err := getParameterUnit("test/system_vars_config.toml", eng)
   523  		convey.So(err, convey.ShouldBeNil)
   524  
   525  		proto := NewMysqlClientProtocol(0, ioses, 1024, pu.SV)
   526  
   527  		guestMmu := guest.New(pu.SV.GuestMmuLimitation, pu.HostMmu)
   528  
   529  		ses := NewSession(proto, guestMmu, pu.Mempool, pu, gSysVariables)
   530      ses.SetRequestContext(ctx)
   531  
   532  		mce := NewMysqlCmdExecutor()
   533  
   534  		mce.PrepareSessionBeforeExecRequest(ses)
   535  
   536  		var row2col *gostub.Stubs = nil
   537  		for i := 0; i < len(kases); i++ {
   538  			if i == 3 {
   539  				row2col = gostub.Stub(&row2colChoose, false)
   540  			}
   541  
   542  			_, err := mce.LoadLoop(context.TODO(), cws[i], db, rel, "T")
   543  			if kases[i].fail {
   544  				convey.So(err, convey.ShouldBeError)
   545  			} else {
   546  				convey.So(err, convey.ShouldBeNil)
   547  			}
   548  
   549  			if i == 3 {
   550  				row2col.Reset()
   551  			}
   552  		}
   553  	})
   554  }*/
   555  
   556  func Test_rowToColumnAndSaveToStorage(t *testing.T) {
   557  	ctx := context.TODO()
   558  	convey.Convey("rowToColumnAndSaveToStorage succ", t, func() {
   559  		ctrl := gomock.NewController(t)
   560  		defer ctrl.Finish()
   561  		rel := mock_frontend.NewMockRelation(ctrl)
   562  		rel.EXPECT().Write(ctx, gomock.Any()).Return(nil).AnyTimes()
   563  
   564  		// XXX the test is so strange, curBatchSize is used as both batch size and column count?
   565  		var curBatchSize = 13
   566  		handler := &WriteBatchHandler{
   567  			SharePart: SharePart{
   568  				tableHandler:               rel,
   569  				lineIdx:                    curBatchSize,
   570  				maxFieldCnt:                curBatchSize,
   571  				simdCsvLineArray:           make([][]string, curBatchSize),
   572  				dataColumnId2TableColumnId: make([]int, curBatchSize),
   573  				ses:                        &Session{timeZone: time.Local},
   574  				result:                     &LoadResult{},
   575  				ignoreFieldError:           true},
   576  			batchData: &batch.Batch{
   577  				Vecs:  make([]*vector.Vector, curBatchSize),
   578  				Attrs: make([]string, curBatchSize),
   579  				Cnt:   1,
   580  			},
   581  			ThreadInfo: &ThreadInfo{},
   582  		}
   583  		mp, err := mpool.NewMPool("session", 0, mpool.NoFixed)
   584  		if err != nil {
   585  			panic(err)
   586  		}
   587  		proc := testutil.NewProcessWithMPool(mp)
   588  		field := [][]string{{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "8", "9"}}
   589  		Oid := []types.T{types.T_int8, types.T_int16, types.T_int32, types.T_int64, types.T_uint8, types.T_uint16,
   590  			types.T_uint32, types.T_uint64, types.T_float32, types.T_float64, types.T_char, types.T_date, types.T_datetime}
   591  		fmt.Println(Oid)
   592  		handler.simdCsvLineArray[0] = field[0]
   593  		for i := 0; i < curBatchSize; i++ {
   594  			handler.dataColumnId2TableColumnId[i] = i
   595  			handler.batchData.Vecs[i] = vector.PreAllocType(Oid[i].ToType(), curBatchSize, curBatchSize, proc.Mp())
   596  			handler.batchData.Vecs[i].SetOriginal(false)
   597  		}
   598  		var force = false
   599  		convey.So(rowToColumnAndSaveToStorage(handler, proc, force, row2colChoose), convey.ShouldBeNil)
   600  
   601  		row2colChoose = false
   602  		handler.lineIdx = 1
   603  		convey.So(rowToColumnAndSaveToStorage(handler, proc, force, row2colChoose), convey.ShouldBeNil)
   604  
   605  		handler.maxFieldCnt = 0
   606  		convey.So(rowToColumnAndSaveToStorage(handler, proc, force, row2colChoose), convey.ShouldBeNil)
   607  
   608  		handler.batchData.Clean(proc.Mp())
   609  		row2colChoose = true
   610  
   611  		handler.batchData.Vecs = make([]*vector.Vector, curBatchSize)
   612  		handler.ignoreFieldError = false
   613  		for i := 0; i < curBatchSize; i++ {
   614  			if Oid[i] == types.T_char {
   615  				continue
   616  			}
   617  			// XXX Vecs[0]?   What are we testing?
   618  			handler.batchData.Vecs[i] = vector.PreAllocType(Oid[i].ToType(), curBatchSize, curBatchSize, proc.Mp())
   619  			convey.So(rowToColumnAndSaveToStorage(handler, proc, force, row2colChoose), convey.ShouldNotBeNil)
   620  			vector.Clean(handler.batchData.Vecs[i], proc.Mp())
   621  		}
   622  
   623  		row2colChoose = false
   624  		handler.maxFieldCnt = curBatchSize
   625  		for i := 0; i < curBatchSize; i++ {
   626  			if Oid[i] == types.T_char {
   627  				continue
   628  			}
   629  			// XXX Vecs[0]?   What are we testing?
   630  			handler.batchData.Vecs[i] = vector.PreAllocType(Oid[i].ToType(), curBatchSize, curBatchSize, proc.Mp())
   631  			convey.So(rowToColumnAndSaveToStorage(handler, proc, force, row2colChoose), convey.ShouldNotBeNil)
   632  			vector.Clean(handler.batchData.Vecs[i], proc.Mp())
   633  		}
   634  		a := proc.Mp().Stats().NumAlloc.Load()
   635  		b := proc.Mp().Stats().NumFree.Load()
   636  		convey.So(a, convey.ShouldEqual, b)
   637  	})
   638  }
   639  
   640  func Test_PrintThreadInfo(t *testing.T) {
   641  	convey.Convey("PrintThreadInfo succ", t, func() {
   642  		handler := &ParseLineHandler{
   643  			threadInfo: make(map[int]*ThreadInfo),
   644  		}
   645  		handler.threadInfo[1] = &ThreadInfo{}
   646  		handler.threadInfo[1].SetTime(time.Now())
   647  		handler.threadInfo[1].SetCnt(1)
   648  		close := &CloseFlag{}
   649  		var a time.Duration = 1
   650  		go func() {
   651  			time.Sleep(a * time.Second)
   652  			close.Close()
   653  		}()
   654  
   655  		PrintThreadInfo(handler, close, a)
   656  
   657  	})
   658  }