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