github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/build_expr_test.go (about) 1 // Copyright 2021 - 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 plan 16 17 import ( 18 "testing" 19 "time" 20 21 "github.com/matrixorigin/matrixone/pkg/container/batch" 22 "github.com/matrixorigin/matrixone/pkg/sql/colexec" 23 "github.com/matrixorigin/matrixone/pkg/testutil" 24 "github.com/stretchr/testify/require" 25 26 "github.com/matrixorigin/matrixone/pkg/common/moerr" 27 "github.com/matrixorigin/matrixone/pkg/container/types" 28 "github.com/matrixorigin/matrixone/pkg/pb/plan" 29 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" 30 "github.com/smartystreets/goconvey/convey" 31 ) 32 33 func TestExpr_1(t *testing.T) { 34 convey.Convey("selectAndStmt succ", t, func() { 35 mock := NewMockOptimizer(false) 36 params := []bool{false, true} 37 input := []string{"select 0 and 1 from dual;", 38 "select false and 1 from dual;", 39 "select false and true from dual;", 40 "select 0 and true from dual;"} 41 42 for i := 0; i < len(input); i++ { 43 pl, err := runOneExprStmt(mock, t, input[i]) 44 if err != nil { 45 t.Fatalf("%+v", err) 46 } 47 query, ok := pl.Plan.(*plan.Plan_Query) 48 if !ok { 49 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 50 } 51 expr := query.Query.Nodes[1].ProjectList[0] 52 exprF, ok := expr.Expr.(*plan.Expr_F) 53 if !ok { 54 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 55 } 56 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 57 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "and") 58 for j, arg := range exprF.F.Args { 59 convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool) 60 exprC, ok := arg.Expr.(*plan.Expr_Lit) 61 if !ok { 62 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 63 } 64 constB, ok := exprC.Lit.Value.(*plan.Literal_Bval) 65 if !ok { 66 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 67 } 68 convey.So(constB.Bval, convey.ShouldEqual, params[j]) 69 } 70 } 71 }) 72 } 73 74 func TestExpr_2(t *testing.T) { 75 convey.Convey("selectORStmt succ", t, func() { 76 mock := NewMockOptimizer(false) 77 params := []bool{false, true} 78 input := []string{"select 0 or 1 from dual;", 79 "select false or 1 from dual;", 80 "select false or true from dual;", 81 "select 0 or true from dual;"} 82 83 for i := 0; i < len(input); i++ { 84 pl, err := runOneExprStmt(mock, t, input[i]) 85 if err != nil { 86 t.Fatalf("%+v", err) 87 } 88 query, ok := pl.Plan.(*plan.Plan_Query) 89 if !ok { 90 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 91 } 92 expr := query.Query.Nodes[1].ProjectList[0] 93 exprF, ok := expr.Expr.(*plan.Expr_F) 94 if !ok { 95 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 96 } 97 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 98 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "or") 99 for j, arg := range exprF.F.Args { 100 convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool) 101 exprC, ok := arg.Expr.(*plan.Expr_Lit) 102 if !ok { 103 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 104 } 105 constB, ok := exprC.Lit.Value.(*plan.Literal_Bval) 106 if !ok { 107 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 108 } 109 convey.So(constB.Bval, convey.ShouldEqual, params[j]) 110 } 111 } 112 }) 113 } 114 115 func TestExpr_3(t *testing.T) { 116 convey.Convey("selectNotStmt succ", t, func() { 117 mock := NewMockOptimizer(false) 118 params := []bool{false, false, true, true} 119 input := []string{"select not 0 from dual;", 120 "select not false from dual;", 121 "select not 1 from dual;", 122 "select not true from dual;"} 123 124 for i := 0; i < len(input); i++ { 125 pl, err := runOneExprStmt(mock, t, input[i]) 126 if err != nil { 127 t.Fatalf("%+v", err) 128 } 129 query, ok := pl.Plan.(*plan.Plan_Query) 130 if !ok { 131 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 132 } 133 expr := query.Query.Nodes[1].ProjectList[0] 134 exprF, ok := expr.Expr.(*plan.Expr_F) 135 if !ok { 136 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 137 } 138 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 139 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "not") 140 for _, arg := range exprF.F.Args { 141 convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool) 142 exprC, ok := arg.Expr.(*plan.Expr_Lit) 143 if !ok { 144 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 145 } 146 constB, ok := exprC.Lit.Value.(*plan.Literal_Bval) 147 if !ok { 148 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 149 } 150 convey.So(constB.Bval, convey.ShouldEqual, params[i]) 151 } 152 } 153 }) 154 } 155 156 func TestExpr_4(t *testing.T) { 157 convey.Convey("selectEqualStmt succ", t, func() { 158 mock := NewMockOptimizer(false) 159 // var params []bool = []bool{false, false, true, true} 160 input := []string{"select 0 = 1 from dual;", 161 "select 1 = 1 from dual;", 162 "select true = false from dual;", 163 "select true = 1 from dual;", 164 "select 0 = false from dual;"} 165 166 for i := 0; i < len(input); i++ { 167 pl, err := runOneExprStmt(mock, t, input[i]) 168 if err != nil { 169 t.Fatalf("%+v", err) 170 } 171 query, ok := pl.Plan.(*plan.Plan_Query) 172 if !ok { 173 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 174 } 175 expr := query.Query.Nodes[1].ProjectList[0] 176 exprF, ok := expr.Expr.(*plan.Expr_F) 177 if !ok { 178 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 179 } 180 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 181 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "=") 182 } 183 }) 184 } 185 186 func TestExpr_5(t *testing.T) { 187 convey.Convey("selectLessStmt succ", t, func() { 188 mock := NewMockOptimizer(false) 189 // var params []bool = []bool{false, false, true, true} 190 input := []string{"select 0 < 1 from dual;", 191 "select 1 < 1 from dual;", 192 "select 1 < 0 from dual;"} 193 194 for i := 0; i < len(input); i++ { 195 pl, err := runOneExprStmt(mock, t, input[i]) 196 if err != nil { 197 t.Fatalf("%+v", err) 198 } 199 query, ok := pl.Plan.(*plan.Plan_Query) 200 if !ok { 201 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 202 } 203 expr := query.Query.Nodes[1].ProjectList[0] 204 exprF, ok := expr.Expr.(*plan.Expr_F) 205 if !ok { 206 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 207 } 208 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 209 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "<") 210 } 211 }) 212 } 213 214 func TestExpr_6(t *testing.T) { 215 convey.Convey("selectLessEqualStmt succ", t, func() { 216 mock := NewMockOptimizer(false) 217 // var params []bool = []bool{false, false, true, true} 218 input := []string{"select 0 <= 1 from dual;", 219 "select 1 <= 1 from dual;", 220 "select 1 <= 0 from dual;"} 221 222 for i := 0; i < len(input); i++ { 223 pl, err := runOneExprStmt(mock, t, input[i]) 224 if err != nil { 225 t.Fatalf("%+v", err) 226 } 227 query, ok := pl.Plan.(*plan.Plan_Query) 228 if !ok { 229 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 230 } 231 expr := query.Query.Nodes[1].ProjectList[0] 232 exprF, ok := expr.Expr.(*plan.Expr_F) 233 if !ok { 234 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 235 } 236 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 237 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "<=") 238 } 239 }) 240 } 241 242 func TestExpr_7(t *testing.T) { 243 convey.Convey("selectGreatStmt succ", t, func() { 244 mock := NewMockOptimizer(false) 245 // var params []bool = []bool{false, false, true, true} 246 input := []string{"select 0 > 1 from dual;", 247 "select 1 > 1 from dual;", 248 "select 1 > 0 from dual;"} 249 250 for i := 0; i < len(input); i++ { 251 pl, err := runOneExprStmt(mock, t, input[i]) 252 if err != nil { 253 t.Fatalf("%+v", err) 254 } 255 query, ok := pl.Plan.(*plan.Plan_Query) 256 if !ok { 257 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 258 } 259 expr := query.Query.Nodes[1].ProjectList[0] 260 exprF, ok := expr.Expr.(*plan.Expr_F) 261 if !ok { 262 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 263 } 264 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 265 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, ">") 266 } 267 }) 268 } 269 270 func TestExpr_8(t *testing.T) { 271 convey.Convey("selectGreatEqualStmt succ", t, func() { 272 mock := NewMockOptimizer(false) 273 // var params []bool = []bool{false, false, true, true} 274 input := []string{"select 0 >= 1 from dual;", 275 "select 1 >= 1 from dual;", 276 "select 1 >= 0 from dual;"} 277 278 for i := 0; i < len(input); i++ { 279 pl, err := runOneExprStmt(mock, t, input[i]) 280 if err != nil { 281 t.Fatalf("%+v", err) 282 } 283 query, ok := pl.Plan.(*plan.Plan_Query) 284 if !ok { 285 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 286 } 287 expr := query.Query.Nodes[1].ProjectList[0] 288 exprF, ok := expr.Expr.(*plan.Expr_F) 289 if !ok { 290 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 291 } 292 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 293 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, ">=") 294 } 295 }) 296 } 297 298 func TestExpr_9(t *testing.T) { 299 convey.Convey("selectGreatEqualStmt succ", t, func() { 300 mock := NewMockOptimizer(false) 301 // var params []bool = []bool{false, false, true, true} 302 input := []string{"select 0 != 1 from dual;", 303 "select 1 != 1 from dual;", 304 "select 1 != 0 from dual;", 305 "select 0 <> 1 from dual;", 306 "select 1 <> 1 from dual;", 307 "select 1 <> 0 from dual;"} 308 309 for i := 0; i < len(input); i++ { 310 pl, err := runOneExprStmt(mock, t, input[i]) 311 if err != nil { 312 t.Fatalf("%+v", err) 313 } 314 query, ok := pl.Plan.(*plan.Plan_Query) 315 if !ok { 316 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 317 } 318 expr := query.Query.Nodes[1].ProjectList[0] 319 exprF, ok := expr.Expr.(*plan.Expr_F) 320 if !ok { 321 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 322 } 323 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 324 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "<>") 325 } 326 }) 327 } 328 329 func TestExpr_A(t *testing.T) { 330 convey.Convey("selectAndStmt succ", t, func() { 331 mock := NewMockOptimizer(false) 332 // var params []bool = []bool{false, false, true, true} 333 input := []string{"select 0 < 1 and 1 > 0 from dual;", 334 "select 0 < 1 or 1 > 0 from dual;", 335 "select not 0 < 1 from dual;"} 336 name := []string{"and", "or", "not"} 337 for i := 0; i < len(input); i++ { 338 pl, err := runOneExprStmt(mock, t, input[i]) 339 if err != nil { 340 t.Fatalf("%+v", err) 341 } 342 query, ok := pl.Plan.(*plan.Plan_Query) 343 if !ok { 344 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 345 } 346 expr := query.Query.Nodes[1].ProjectList[0] 347 exprF, ok := expr.Expr.(*plan.Expr_F) 348 if !ok { 349 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 350 } 351 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 352 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, name[i]) 353 for _, arg := range exprF.F.Args { 354 convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool) 355 } 356 } 357 }) 358 } 359 360 func TestExpr_B(t *testing.T) { 361 convey.Convey("selectAndStmt succ", t, func() { 362 mock := NewMockOptimizer(false) 363 // var params []bool = []bool{false, false, true, true} 364 input := []string{"select 0 < 1 and 1 > 0 && not false from dual;"} 365 for i := 0; i < len(input); i++ { 366 pl, err := runOneExprStmt(mock, t, input[i]) 367 if err != nil { 368 t.Fatalf("%+v", err) 369 } 370 query, ok := pl.Plan.(*plan.Plan_Query) 371 if !ok { 372 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right")) 373 } 374 expr := query.Query.Nodes[1].ProjectList[0] 375 exprF, ok := expr.Expr.(*plan.Expr_F) 376 if !ok { 377 t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right")) 378 } 379 convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool) 380 convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "and") 381 for _, arg := range exprF.F.Args { 382 convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool) 383 } 384 } 385 }) 386 } 387 388 func runOneExprStmt(opt Optimizer, t *testing.T, sql string) (*plan.Plan, error) { 389 stmts, err := mysql.Parse(opt.CurrentContext().GetContext(), sql, 1, 0) 390 if err != nil { 391 return nil, err 392 } 393 ctx := opt.CurrentContext() 394 395 var pl *plan.Plan 396 for _, ast := range stmts { 397 pl, err = BuildPlan(ctx, ast, false) 398 if err != nil { 399 return nil, err 400 } 401 } 402 return pl, nil 403 } 404 405 func makeTimeExpr(s string, p int32) *plan.Expr { 406 dt, _ := types.ParseTime(s, 0) 407 return &plan.Expr{ 408 Typ: plan.Type{ 409 Id: int32(types.T_time), 410 Scale: p, 411 }, 412 Expr: &plan.Expr_Lit{ 413 Lit: &plan.Literal{ 414 Value: &plan.Literal_Timeval{ 415 Timeval: int64(dt), 416 }, 417 }, 418 }, 419 } 420 } 421 422 func makeDateExpr(s string) *plan.Expr { 423 dt, _ := types.ParseDateCast(s) 424 return &plan.Expr{ 425 Typ: plan.Type{ 426 Id: int32(types.T_date), 427 }, 428 Expr: &plan.Expr_Lit{ 429 Lit: &plan.Literal{ 430 Value: &plan.Literal_Dateval{ 431 Dateval: int32(dt), 432 }, 433 }, 434 }, 435 } 436 } 437 438 func makeTimestampExpr(s string, p int32, loc *time.Location) *plan.Expr { 439 dt, _ := types.ParseTimestamp(loc, s, p) 440 return &plan.Expr{ 441 Typ: plan.Type{ 442 Id: int32(types.T_timestamp), 443 }, 444 Expr: &plan.Expr_Lit{ 445 Lit: &plan.Literal{ 446 Value: &plan.Literal_Timestampval{ 447 Timestampval: int64(dt), 448 }, 449 }, 450 }, 451 } 452 } 453 func makeDatetimeExpr(s string, p int32) *plan.Expr { 454 dt, _ := types.ParseDatetime(s, p) 455 return &plan.Expr{ 456 Typ: plan.Type{ 457 Id: int32(types.T_datetime), 458 }, 459 Expr: &plan.Expr_Lit{ 460 Lit: &plan.Literal{ 461 Value: &plan.Literal_Datetimeval{ 462 Datetimeval: int64(dt), 463 }, 464 }, 465 }, 466 } 467 } 468 469 func TestTime(t *testing.T) { 470 s := "12:34:56" 471 e := makeTimeExpr(s, 0) 472 bat := batch.NewWithSize(1) 473 bat.SetRowCount(1) 474 executor, err := colexec.NewExpressionExecutor(testutil.NewProc(), e) 475 require.NoError(t, err) 476 r, err := executor.Eval(testutil.NewProc(), []*batch.Batch{bat}) 477 require.NoError(t, err) 478 require.Equal(t, 1, r.Length()) 479 } 480 481 func TestDatetime(t *testing.T) { 482 s := "2019-12-12 12:34:56" 483 e := makeDatetimeExpr(s, 0) 484 bat := batch.NewWithSize(1) 485 bat.SetRowCount(1) 486 executor, err := colexec.NewExpressionExecutor(testutil.NewProc(), e) 487 require.NoError(t, err) 488 r, err := executor.Eval(testutil.NewProc(), []*batch.Batch{bat}) 489 require.NoError(t, err) 490 require.Equal(t, 1, r.Length()) 491 } 492 func TestTimestamp(t *testing.T) { 493 s := "2019-12-12 12:34:56" 494 e := makeTimestampExpr(s, 0, time.Local) 495 bat := batch.NewWithSize(1) 496 bat.SetRowCount(1) 497 executor, err := colexec.NewExpressionExecutor(testutil.NewProc(), e) 498 require.NoError(t, err) 499 r, err := executor.Eval(testutil.NewProc(), []*batch.Batch{bat}) 500 require.NoError(t, err) 501 require.Equal(t, 1, r.Length()) 502 } 503 func TestDate(t *testing.T) { 504 s := "2019-12-12" 505 e := makeDateExpr(s) 506 bat := batch.NewWithSize(1) 507 bat.SetRowCount(1) 508 executor, err := colexec.NewExpressionExecutor(testutil.NewProc(), e) 509 require.NoError(t, err) 510 r, err := executor.Eval(testutil.NewProc(), []*batch.Batch{bat}) 511 require.NoError(t, err) 512 require.Equal(t, 1, r.Length()) 513 }