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 }