github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/evaluator/evaluator_test.go (about) 1 // Copyright 2015 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package evaluator 15 16 import ( 17 "testing" 18 "time" 19 20 "fmt" 21 . "github.com/insionng/yougam/libraries/pingcap/check" 22 "github.com/insionng/yougam/libraries/pingcap/tidb/ast" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 24 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 25 "github.com/insionng/yougam/libraries/pingcap/tidb/parser" 26 "github.com/insionng/yougam/libraries/pingcap/tidb/parser/opcode" 27 "github.com/insionng/yougam/libraries/pingcap/tidb/sessionctx/variable" 28 "github.com/insionng/yougam/libraries/pingcap/tidb/util/charset" 29 "github.com/insionng/yougam/libraries/pingcap/tidb/util/mock" 30 "github.com/insionng/yougam/libraries/pingcap/tidb/util/testleak" 31 "github.com/insionng/yougam/libraries/pingcap/tidb/util/testutil" 32 "github.com/insionng/yougam/libraries/pingcap/tidb/util/types" 33 ) 34 35 var _ = Suite(&testEvaluatorSuite{}) 36 37 func TestT(t *testing.T) { 38 TestingT(t) 39 } 40 41 type testEvaluatorSuite struct { 42 } 43 44 func parseExpr(c *C, expr string) ast.ExprNode { 45 s, err := parser.ParseOneStmt("select "+expr, "", "") 46 c.Assert(err, IsNil) 47 stmt := s.(*ast.SelectStmt) 48 return stmt.Fields.Fields[0].Expr 49 } 50 51 type testCase struct { 52 exprStr string 53 resultStr string 54 } 55 56 func (s *testEvaluatorSuite) runTests(c *C, cases []testCase) { 57 ctx := mock.NewContext() 58 for _, ca := range cases { 59 expr := parseExpr(c, ca.exprStr) 60 val, err := Eval(ctx, expr) 61 c.Assert(err, IsNil) 62 valStr := fmt.Sprintf("%v", val.GetValue()) 63 c.Assert(valStr, Equals, ca.resultStr, Commentf("for %s", ca.exprStr)) 64 } 65 } 66 67 func (s *testEvaluatorSuite) TestBetween(c *C) { 68 defer testleak.AfterTest(c)() 69 cases := []testCase{ 70 {exprStr: "1 between 2 and 3", resultStr: "0"}, 71 {exprStr: "1 not between 2 and 3", resultStr: "1"}, 72 } 73 s.runTests(c, cases) 74 } 75 76 func (s *testEvaluatorSuite) TestBinopComparison(c *C) { 77 defer testleak.AfterTest(c)() 78 ctx := mock.NewContext() 79 tbl := []struct { 80 lhs interface{} 81 op opcode.Op 82 rhs interface{} 83 result int64 // 0 for false, 1 for true 84 }{ 85 // test EQ 86 {1, opcode.EQ, 2, 0}, 87 {false, opcode.EQ, false, 1}, 88 {false, opcode.EQ, true, 0}, 89 {true, opcode.EQ, true, 1}, 90 {true, opcode.EQ, false, 0}, 91 {"1", opcode.EQ, true, 1}, 92 {"1", opcode.EQ, false, 0}, 93 94 // test NEQ 95 {1, opcode.NE, 2, 1}, 96 {false, opcode.NE, false, 0}, 97 {false, opcode.NE, true, 1}, 98 {true, opcode.NE, true, 0}, 99 {"1", opcode.NE, true, 0}, 100 {"1", opcode.NE, false, 1}, 101 102 // test GT, GE 103 {1, opcode.GT, 0, 1}, 104 {1, opcode.GT, 1, 0}, 105 {1, opcode.GE, 1, 1}, 106 {3.14, opcode.GT, 3, 1}, 107 {3.14, opcode.GE, 3.14, 1}, 108 109 // test LT, LE 110 {1, opcode.LT, 2, 1}, 111 {1, opcode.LT, 1, 0}, 112 {1, opcode.LE, 1, 1}, 113 } 114 for _, t := range tbl { 115 expr := &ast.BinaryOperationExpr{Op: t.op, L: ast.NewValueExpr(t.lhs), R: ast.NewValueExpr(t.rhs)} 116 v, err := Eval(ctx, expr) 117 c.Assert(err, IsNil) 118 val, err := v.ToBool() 119 c.Assert(err, IsNil) 120 c.Assert(val, Equals, t.result) 121 } 122 123 // test nil 124 nilTbl := []struct { 125 lhs interface{} 126 op opcode.Op 127 rhs interface{} 128 }{ 129 {nil, opcode.EQ, nil}, 130 {nil, opcode.EQ, 1}, 131 {nil, opcode.NE, nil}, 132 {nil, opcode.NE, 1}, 133 {nil, opcode.LT, nil}, 134 {nil, opcode.LT, 1}, 135 {nil, opcode.LE, nil}, 136 {nil, opcode.LE, 1}, 137 {nil, opcode.GT, nil}, 138 {nil, opcode.GT, 1}, 139 {nil, opcode.GE, nil}, 140 {nil, opcode.GE, 1}, 141 } 142 143 for _, t := range nilTbl { 144 expr := &ast.BinaryOperationExpr{Op: t.op, L: ast.NewValueExpr(t.lhs), R: ast.NewValueExpr(t.rhs)} 145 v, err := Eval(ctx, expr) 146 c.Assert(err, IsNil) 147 c.Assert(v.Kind(), Equals, types.KindNull) 148 } 149 } 150 151 func (s *testEvaluatorSuite) TestBinopLogic(c *C) { 152 defer testleak.AfterTest(c)() 153 ctx := mock.NewContext() 154 tbl := []struct { 155 lhs interface{} 156 op opcode.Op 157 rhs interface{} 158 ret interface{} 159 }{ 160 {nil, opcode.AndAnd, 1, nil}, 161 {nil, opcode.AndAnd, 0, 0}, 162 {nil, opcode.OrOr, 1, 1}, 163 {nil, opcode.OrOr, 0, nil}, 164 {nil, opcode.LogicXor, 1, nil}, 165 {nil, opcode.LogicXor, 0, nil}, 166 {1, opcode.AndAnd, 0, 0}, 167 {1, opcode.AndAnd, 1, 1}, 168 {1, opcode.OrOr, 0, 1}, 169 {1, opcode.OrOr, 1, 1}, 170 {0, opcode.OrOr, 0, 0}, 171 {1, opcode.LogicXor, 0, 1}, 172 {1, opcode.LogicXor, 1, 0}, 173 {0, opcode.LogicXor, 0, 0}, 174 {0, opcode.LogicXor, 1, 1}, 175 } 176 for _, t := range tbl { 177 expr := &ast.BinaryOperationExpr{Op: t.op, L: ast.NewValueExpr(t.lhs), R: ast.NewValueExpr(t.rhs)} 178 v, err := Eval(ctx, expr) 179 c.Assert(err, IsNil) 180 switch x := t.ret.(type) { 181 case nil: 182 c.Assert(v.Kind(), Equals, types.KindNull) 183 case int: 184 c.Assert(v, testutil.DatumEquals, types.NewDatum(int64(x))) 185 } 186 } 187 } 188 189 func (s *testEvaluatorSuite) TestBinopBitop(c *C) { 190 defer testleak.AfterTest(c)() 191 ctx := mock.NewContext() 192 tbl := []struct { 193 lhs interface{} 194 op opcode.Op 195 rhs interface{} 196 ret interface{} 197 }{ 198 {1, opcode.And, 1, 1}, 199 {1, opcode.Or, 1, 1}, 200 {1, opcode.Xor, 1, 0}, 201 {1, opcode.LeftShift, 1, 2}, 202 {2, opcode.RightShift, 1, 1}, 203 {nil, opcode.And, 1, nil}, 204 {1, opcode.And, nil, nil}, 205 {nil, opcode.Or, 1, nil}, 206 {nil, opcode.Xor, 1, nil}, 207 {nil, opcode.LeftShift, 1, nil}, 208 {nil, opcode.RightShift, 1, nil}, 209 } 210 211 for _, t := range tbl { 212 expr := &ast.BinaryOperationExpr{Op: t.op, L: ast.NewValueExpr(t.lhs), R: ast.NewValueExpr(t.rhs)} 213 v, err := Eval(ctx, expr) 214 c.Assert(err, IsNil) 215 216 switch x := t.ret.(type) { 217 case nil: 218 c.Assert(v.Kind(), Equals, types.KindNull) 219 case int: 220 c.Assert(v, testutil.DatumEquals, types.NewDatum(uint64(x))) 221 } 222 } 223 } 224 225 func (s *testEvaluatorSuite) TestBinopNumeric(c *C) { 226 defer testleak.AfterTest(c)() 227 ctx := mock.NewContext() 228 tbl := []struct { 229 lhs interface{} 230 op opcode.Op 231 rhs interface{} 232 ret interface{} 233 }{ 234 // plus 235 {1, opcode.Plus, 1, 2}, 236 {1, opcode.Plus, uint64(1), 2}, 237 {1, opcode.Plus, "1", 2}, 238 {1, opcode.Plus, mysql.NewDecimalFromInt(1, 0), 2}, 239 {uint64(1), opcode.Plus, 1, 2}, 240 {uint64(1), opcode.Plus, uint64(1), 2}, 241 {1, opcode.Plus, []byte("1"), 2}, 242 {1, opcode.Plus, mysql.Hex{Value: 1}, 2}, 243 {1, opcode.Plus, mysql.Bit{Value: 1, Width: 1}, 2}, 244 {1, opcode.Plus, mysql.Enum{Name: "a", Value: 1}, 2}, 245 {1, opcode.Plus, mysql.Set{Name: "a", Value: 1}, 2}, 246 247 // minus 248 {1, opcode.Minus, 1, 0}, 249 {1, opcode.Minus, uint64(1), 0}, 250 {1, opcode.Minus, float64(1), 0}, 251 {1, opcode.Minus, mysql.NewDecimalFromInt(1, 0), 0}, 252 {uint64(1), opcode.Minus, 1, 0}, 253 {uint64(1), opcode.Minus, uint64(1), 0}, 254 {mysql.NewDecimalFromInt(1, 0), opcode.Minus, 1, 0}, 255 {"1", opcode.Minus, []byte("1"), 0}, 256 257 // mul 258 {1, opcode.Mul, 1, 1}, 259 {1, opcode.Mul, uint64(1), 1}, 260 {1, opcode.Mul, float64(1), 1}, 261 {1, opcode.Mul, mysql.NewDecimalFromInt(1, 0), 1}, 262 {uint64(1), opcode.Mul, 1, 1}, 263 {uint64(1), opcode.Mul, uint64(1), 1}, 264 {mysql.Time{}, opcode.Mul, 0, 0}, 265 {mysql.ZeroDuration, opcode.Mul, 0, 0}, 266 {mysql.Time{Time: time.Now(), Fsp: 0, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0}, 267 {mysql.Time{Time: time.Now(), Fsp: 6, Type: mysql.TypeDatetime}, opcode.Mul, 0, 0}, 268 {mysql.Duration{Duration: 100000000, Fsp: 6}, opcode.Mul, 0, 0}, 269 270 // div 271 {1, opcode.Div, float64(1), 1}, 272 {1, opcode.Div, float64(0), nil}, 273 {1, opcode.Div, 2, 0.5}, 274 {1, opcode.Div, 0, nil}, 275 276 // int div 277 {1, opcode.IntDiv, 2, 0}, 278 {1, opcode.IntDiv, uint64(2), 0}, 279 {1, opcode.IntDiv, 0, nil}, 280 {1, opcode.IntDiv, uint64(0), nil}, 281 {uint64(1), opcode.IntDiv, 2, 0}, 282 {uint64(1), opcode.IntDiv, uint64(2), 0}, 283 {uint64(1), opcode.IntDiv, 0, nil}, 284 {uint64(1), opcode.IntDiv, uint64(0), nil}, 285 {1.0, opcode.IntDiv, 2.0, 0}, 286 {1.0, opcode.IntDiv, 0, nil}, 287 288 // mod 289 {10, opcode.Mod, 2, 0}, 290 {10, opcode.Mod, uint64(2), 0}, 291 {10, opcode.Mod, 0, nil}, 292 {10, opcode.Mod, uint64(0), nil}, 293 {-10, opcode.Mod, uint64(2), 0}, 294 {uint64(10), opcode.Mod, 2, 0}, 295 {uint64(10), opcode.Mod, uint64(2), 0}, 296 {uint64(10), opcode.Mod, 0, nil}, 297 {uint64(10), opcode.Mod, uint64(0), nil}, 298 {uint64(10), opcode.Mod, -2, 0}, 299 {float64(10), opcode.Mod, 2, 0}, 300 {float64(10), opcode.Mod, 0, nil}, 301 {mysql.NewDecimalFromInt(10, 0), opcode.Mod, 2, 0}, 302 {mysql.NewDecimalFromInt(10, 0), opcode.Mod, 0, nil}, 303 } 304 305 for _, t := range tbl { 306 expr := &ast.BinaryOperationExpr{Op: t.op, L: ast.NewValueExpr(t.lhs), R: ast.NewValueExpr(t.rhs)} 307 v, err := Eval(ctx, expr) 308 c.Assert(err, IsNil) 309 switch v.Kind() { 310 case types.KindNull: 311 c.Assert(t.ret, IsNil) 312 default: 313 // we use float64 as the result type check for all. 314 f, err := v.ToFloat64() 315 c.Assert(err, IsNil) 316 317 r, err := types.ToFloat64(t.ret) 318 c.Assert(err, IsNil) 319 c.Assert(r, Equals, f) 320 } 321 } 322 } 323 324 func (s *testEvaluatorSuite) TestCaseWhen(c *C) { 325 defer testleak.AfterTest(c)() 326 cases := []testCase{ 327 { 328 exprStr: "case 1 when 1 then 'str1' when 2 then 'str2' end", 329 resultStr: "str1", 330 }, 331 { 332 exprStr: "case 2 when 1 then 'str1' when 2 then 'str2' end", 333 resultStr: "str2", 334 }, 335 { 336 exprStr: "case 3 when 1 then 'str1' when 2 then 'str2' end", 337 resultStr: "<nil>", 338 }, 339 { 340 exprStr: "case 4 when 1 then 'str1' when 2 then 'str2' else 'str3' end", 341 resultStr: "str3", 342 }, 343 } 344 s.runTests(c, cases) 345 346 // When expression value changed, result set back to null. 347 valExpr := ast.NewValueExpr(1) 348 whenClause := &ast.WhenClause{Expr: ast.NewValueExpr(1), Result: ast.NewValueExpr(1)} 349 caseExpr := &ast.CaseExpr{ 350 Value: valExpr, 351 WhenClauses: []*ast.WhenClause{whenClause}, 352 } 353 ctx := mock.NewContext() 354 v, err := Eval(ctx, caseExpr) 355 c.Assert(err, IsNil) 356 c.Assert(v, testutil.DatumEquals, types.NewDatum(int64(1))) 357 valExpr.SetValue(4) 358 ast.ResetEvaluatedFlag(caseExpr) 359 v, err = Eval(ctx, caseExpr) 360 c.Assert(err, IsNil) 361 c.Assert(v.Kind(), Equals, types.KindNull) 362 } 363 364 func (s *testEvaluatorSuite) TestCall(c *C) { 365 defer testleak.AfterTest(c)() 366 ctx := mock.NewContext() 367 368 // Test case for correct number of arguments 369 expr := &ast.FuncCallExpr{ 370 FnName: model.NewCIStr("date"), 371 Args: []ast.ExprNode{ast.NewValueExpr("2015-12-21 11:11:11")}, 372 } 373 v, err := Eval(ctx, expr) 374 c.Assert(err, IsNil) 375 c.Assert(v.Kind(), Equals, types.KindMysqlTime) 376 c.Assert(v.GetMysqlTime().String(), Equals, "2015-12-21") 377 378 // Test case for unlimited upper bound 379 expr = &ast.FuncCallExpr{ 380 FnName: model.NewCIStr("concat"), 381 Args: []ast.ExprNode{ast.NewValueExpr("Ti"), 382 ast.NewValueExpr("D"), ast.NewValueExpr("B")}, 383 } 384 v, err = Eval(ctx, expr) 385 c.Assert(err, IsNil) 386 c.Assert(v.Kind(), Equals, types.KindString) 387 c.Assert(v.GetString(), Equals, "TiDB") 388 389 // Test case for unknown function 390 expr = &ast.FuncCallExpr{ 391 FnName: model.NewCIStr("unknown"), 392 Args: []ast.ExprNode{}, 393 } 394 _, err = Eval(ctx, expr) 395 c.Assert(err, NotNil) 396 397 // Test case for invalid number of arguments, violating the lower bound 398 expr = &ast.FuncCallExpr{ 399 FnName: model.NewCIStr("date"), 400 Args: []ast.ExprNode{}, 401 } 402 _, err = Eval(ctx, expr) 403 c.Assert(err, NotNil) 404 405 // Test case for invalid number of arguments, violating the upper bound 406 expr = &ast.FuncCallExpr{ 407 FnName: model.NewCIStr("date"), 408 Args: []ast.ExprNode{ast.NewValueExpr("2015-12-21"), 409 ast.NewValueExpr("2015-12-22")}, 410 } 411 _, err = Eval(ctx, expr) 412 c.Assert(err, NotNil) 413 } 414 415 func (s *testEvaluatorSuite) TestCast(c *C) { 416 defer testleak.AfterTest(c)() 417 f := types.NewFieldType(mysql.TypeLonglong) 418 419 expr := &ast.FuncCastExpr{ 420 Expr: ast.NewValueExpr(1), 421 Tp: f, 422 } 423 ast.SetFlag(expr) 424 ctx := mock.NewContext() 425 v, err := Eval(ctx, expr) 426 c.Assert(err, IsNil) 427 c.Assert(v, testutil.DatumEquals, types.NewDatum(int64(1))) 428 429 f.Flag |= mysql.UnsignedFlag 430 v, err = Eval(ctx, expr) 431 c.Assert(err, IsNil) 432 c.Assert(v, testutil.DatumEquals, types.NewDatum(uint64(1))) 433 434 f.Tp = mysql.TypeString 435 f.Charset = charset.CharsetBin 436 v, err = Eval(ctx, expr) 437 c.Assert(err, IsNil) 438 c.Assert(v, testutil.DatumEquals, types.NewDatum([]byte("1"))) 439 440 f.Tp = mysql.TypeString 441 f.Charset = "utf8" 442 v, err = Eval(ctx, expr) 443 c.Assert(err, IsNil) 444 c.Assert(v, testutil.DatumEquals, types.NewDatum("1")) 445 446 expr.Expr = ast.NewValueExpr(nil) 447 v, err = Eval(ctx, expr) 448 c.Assert(err, IsNil) 449 c.Assert(v.Kind(), Equals, types.KindNull) 450 } 451 452 func (s *testEvaluatorSuite) TestExtract(c *C) { 453 defer testleak.AfterTest(c)() 454 str := "2011-11-11 10:10:10.123456" 455 tbl := []struct { 456 Unit string 457 Expect int64 458 }{ 459 {"MICROSECOND", 123456}, 460 {"SECOND", 10}, 461 {"MINUTE", 10}, 462 {"HOUR", 10}, 463 {"DAY", 11}, 464 {"WEEK", 45}, 465 {"MONTH", 11}, 466 {"QUARTER", 4}, 467 {"YEAR", 2011}, 468 {"SECOND_MICROSECOND", 10123456}, 469 {"MINUTE_MICROSECOND", 1010123456}, 470 {"MINUTE_SECOND", 1010}, 471 {"HOUR_MICROSECOND", 101010123456}, 472 {"HOUR_SECOND", 101010}, 473 {"HOUR_MINUTE", 1010}, 474 {"DAY_MICROSECOND", 11101010123456}, 475 {"DAY_SECOND", 11101010}, 476 {"DAY_MINUTE", 111010}, 477 {"DAY_HOUR", 1110}, 478 {"YEAR_MONTH", 201111}, 479 } 480 ctx := mock.NewContext() 481 for _, t := range tbl { 482 e := &ast.FuncCallExpr{ 483 FnName: model.NewCIStr("EXTRACT"), 484 Args: []ast.ExprNode{ast.NewValueExpr(t.Unit), ast.NewValueExpr(str)}, 485 } 486 v, err := Eval(ctx, e) 487 c.Assert(err, IsNil) 488 c.Assert(v, testutil.DatumEquals, types.NewDatum(t.Expect)) 489 } 490 491 // Test nil 492 e := &ast.FuncCallExpr{ 493 FnName: model.NewCIStr("EXTRACT"), 494 Args: []ast.ExprNode{ast.NewValueExpr("SECOND"), ast.NewValueExpr(nil)}, 495 } 496 497 v, err := Eval(ctx, e) 498 c.Assert(err, IsNil) 499 c.Assert(v.Kind(), Equals, types.KindNull) 500 } 501 502 func (s *testEvaluatorSuite) TestPatternIn(c *C) { 503 defer testleak.AfterTest(c)() 504 cases := []testCase{ 505 { 506 exprStr: "1 not in (1, 2, 3)", 507 resultStr: "0", 508 }, 509 { 510 exprStr: "1 in (1, 2, 3)", 511 resultStr: "1", 512 }, 513 { 514 exprStr: "1 in (2, 3)", 515 resultStr: "0", 516 }, 517 { 518 exprStr: "NULL in (2, 3)", 519 resultStr: "<nil>", 520 }, 521 { 522 exprStr: "NULL not in (2, 3)", 523 resultStr: "<nil>", 524 }, 525 { 526 exprStr: "NULL in (NULL, 3)", 527 resultStr: "<nil>", 528 }, 529 { 530 exprStr: "1 in (1, NULL)", 531 resultStr: "1", 532 }, 533 { 534 exprStr: "1 in (NULL, 1)", 535 resultStr: "1", 536 }, 537 { 538 exprStr: "2 in (1, NULL)", 539 resultStr: "<nil>", 540 }, 541 { 542 exprStr: "(-(23)++46/51*+51) in (+23)", 543 resultStr: "0", 544 }, 545 } 546 s.runTests(c, cases) 547 } 548 549 func (s *testEvaluatorSuite) TestIsNull(c *C) { 550 defer testleak.AfterTest(c)() 551 cases := []testCase{ 552 { 553 exprStr: "1 IS NULL", 554 resultStr: "0", 555 }, 556 { 557 exprStr: "1 IS NOT NULL", 558 resultStr: "1", 559 }, 560 { 561 exprStr: "NULL IS NULL", 562 resultStr: "1", 563 }, 564 { 565 exprStr: "NULL IS NOT NULL", 566 resultStr: "0", 567 }, 568 } 569 s.runTests(c, cases) 570 } 571 572 func (s *testEvaluatorSuite) TestIsTruth(c *C) { 573 defer testleak.AfterTest(c)() 574 cases := []testCase{ 575 { 576 exprStr: "1 IS TRUE", 577 resultStr: "1", 578 }, 579 { 580 exprStr: "2 IS TRUE", 581 resultStr: "1", 582 }, 583 { 584 exprStr: "0 IS TRUE", 585 resultStr: "0", 586 }, 587 { 588 exprStr: "NULL IS TRUE", 589 resultStr: "0", 590 }, 591 { 592 exprStr: "1 IS FALSE", 593 resultStr: "0", 594 }, 595 { 596 exprStr: "2 IS FALSE", 597 resultStr: "0", 598 }, 599 { 600 exprStr: "0 IS FALSE", 601 resultStr: "1", 602 }, 603 { 604 exprStr: "NULL IS NOT FALSE", 605 resultStr: "1", 606 }, 607 { 608 exprStr: "1 IS NOT TRUE", 609 resultStr: "0", 610 }, 611 { 612 exprStr: "2 IS NOT TRUE", 613 resultStr: "0", 614 }, 615 { 616 exprStr: "0 IS NOT TRUE", 617 resultStr: "1", 618 }, 619 { 620 exprStr: "NULL IS NOT TRUE", 621 resultStr: "1", 622 }, 623 { 624 exprStr: "1 IS NOT FALSE", 625 resultStr: "1", 626 }, 627 { 628 exprStr: "2 IS NOT FALSE", 629 resultStr: "1", 630 }, 631 { 632 exprStr: "0 IS NOT FALSE", 633 resultStr: "0", 634 }, 635 { 636 exprStr: "NULL IS NOT FALSE", 637 resultStr: "1", 638 }, 639 } 640 s.runTests(c, cases) 641 } 642 643 func (s *testEvaluatorSuite) TestLike(c *C) { 644 defer testleak.AfterTest(c)() 645 tbl := []struct { 646 pattern string 647 input string 648 escape byte 649 match bool 650 }{ 651 {"", "a", '\\', false}, 652 {"a", "a", '\\', true}, 653 {"a", "b", '\\', false}, 654 {"aA", "aA", '\\', true}, 655 {"_", "a", '\\', true}, 656 {"_", "ab", '\\', false}, 657 {"__", "b", '\\', false}, 658 {"_ab", "AAB", '\\', true}, 659 {"%", "abcd", '\\', true}, 660 {"%", "", '\\', true}, 661 {"%a", "AAA", '\\', true}, 662 {"%b", "AAA", '\\', false}, 663 {"b%", "BBB", '\\', true}, 664 {"%a%", "BBB", '\\', false}, 665 {"%a%", "BAB", '\\', true}, 666 {"a%", "BBB", '\\', false}, 667 {`\%a`, `%a`, '\\', true}, 668 {`\%a`, `aa`, '\\', false}, 669 {`\_a`, `_a`, '\\', true}, 670 {`\_a`, `aa`, '\\', false}, 671 {`\\_a`, `\xa`, '\\', true}, 672 {`\a\b`, `\a\b`, '\\', true}, 673 {"%%_", `abc`, '\\', true}, 674 {`+_a`, `_a`, '+', true}, 675 {`+%a`, `%a`, '+', true}, 676 {`\%a`, `%a`, '+', false}, 677 {`++a`, `+a`, '+', true}, 678 {`++_a`, `+xa`, '+', true}, 679 } 680 for _, v := range tbl { 681 patChars, patTypes := compilePattern(v.pattern, v.escape) 682 match := doMatch(v.input, patChars, patTypes) 683 c.Assert(match, Equals, v.match, Commentf("%v", v)) 684 } 685 cases := []testCase{ 686 { 687 exprStr: "'a' LIKE ''", 688 resultStr: "0", 689 }, 690 { 691 exprStr: "'a' LIKE 'a'", 692 resultStr: "1", 693 }, 694 { 695 exprStr: "'a' LIKE 'b'", 696 resultStr: "0", 697 }, 698 { 699 exprStr: "'aA' LIKE 'Aa'", 700 resultStr: "1", 701 }, 702 { 703 exprStr: "'aAb' LIKE 'Aa%'", 704 resultStr: "1", 705 }, 706 { 707 exprStr: "'aAb' LIKE 'Aa_'", 708 resultStr: "1", 709 }, 710 } 711 s.runTests(c, cases) 712 } 713 714 func (s *testEvaluatorSuite) TestRegexp(c *C) { 715 defer testleak.AfterTest(c)() 716 tbl := []struct { 717 pattern string 718 input string 719 match int64 720 }{ 721 {"^$", "a", 0}, 722 {"a", "a", 1}, 723 {"a", "b", 0}, 724 {"aA", "aA", 1}, 725 {".", "a", 1}, 726 {"^.$", "ab", 0}, 727 {"..", "b", 0}, 728 {".ab", "aab", 1}, 729 {".*", "abcd", 1}, 730 } 731 ctx := mock.NewContext() 732 for _, v := range tbl { 733 pattern := &ast.PatternRegexpExpr{ 734 Pattern: ast.NewValueExpr(v.pattern), 735 Expr: ast.NewValueExpr(v.input), 736 } 737 match, err := Eval(ctx, pattern) 738 c.Assert(err, IsNil) 739 c.Assert(match, testutil.DatumEquals, types.NewDatum(v.match), Commentf("%v", v)) 740 } 741 } 742 743 func (s *testEvaluatorSuite) TestUnaryOp(c *C) { 744 defer testleak.AfterTest(c)() 745 tbl := []struct { 746 arg interface{} 747 op opcode.Op 748 result interface{} 749 }{ 750 // test NOT. 751 {1, opcode.Not, int64(0)}, 752 {0, opcode.Not, int64(1)}, 753 {nil, opcode.Not, nil}, 754 {mysql.Hex{Value: 0}, opcode.Not, int64(1)}, 755 {mysql.Bit{Value: 0, Width: 1}, opcode.Not, int64(1)}, 756 {mysql.Enum{Name: "a", Value: 1}, opcode.Not, int64(0)}, 757 {mysql.Set{Name: "a", Value: 1}, opcode.Not, int64(0)}, 758 759 // test BitNeg. 760 {nil, opcode.BitNeg, nil}, 761 {-1, opcode.BitNeg, uint64(0)}, 762 763 // test Plus. 764 {nil, opcode.Plus, nil}, 765 {float64(1.0), opcode.Plus, float64(1.0)}, 766 {int64(1), opcode.Plus, int64(1)}, 767 {int64(1), opcode.Plus, int64(1)}, 768 {uint64(1), opcode.Plus, uint64(1)}, 769 {"1.0", opcode.Plus, "1.0"}, 770 {[]byte("1.0"), opcode.Plus, []byte("1.0")}, 771 {mysql.Hex{Value: 1}, opcode.Plus, mysql.Hex{Value: 1}}, 772 {mysql.Bit{Value: 1, Width: 1}, opcode.Plus, mysql.Bit{Value: 1, Width: 1}}, 773 {true, opcode.Plus, int64(1)}, 774 {false, opcode.Plus, int64(0)}, 775 {mysql.Enum{Name: "a", Value: 1}, opcode.Plus, mysql.Enum{Name: "a", Value: 1}}, 776 {mysql.Set{Name: "a", Value: 1}, opcode.Plus, mysql.Set{Name: "a", Value: 1}}, 777 778 // test Minus. 779 {nil, opcode.Minus, nil}, 780 {float64(1.0), opcode.Minus, float64(-1.0)}, 781 {int64(1), opcode.Minus, int64(-1)}, 782 {int64(1), opcode.Minus, int64(-1)}, 783 {uint64(1), opcode.Minus, -int64(1)}, 784 {"1.0", opcode.Minus, -1.0}, 785 {[]byte("1.0"), opcode.Minus, -1.0}, 786 {mysql.Hex{Value: 1}, opcode.Minus, -1.0}, 787 {mysql.Bit{Value: 1, Width: 1}, opcode.Minus, -1.0}, 788 {true, opcode.Minus, int64(-1)}, 789 {false, opcode.Minus, int64(0)}, 790 {mysql.Enum{Name: "a", Value: 1}, opcode.Minus, -1.0}, 791 {mysql.Set{Name: "a", Value: 1}, opcode.Minus, -1.0}, 792 } 793 ctx := mock.NewContext() 794 for i, t := range tbl { 795 expr := &ast.UnaryOperationExpr{} 796 expr.Op = t.op 797 expr.V = ast.NewValueExpr(t.arg) 798 result, err := Eval(ctx, expr) 799 c.Assert(err, IsNil) 800 c.Assert(result, testutil.DatumEquals, types.NewDatum(t.result), Commentf("%d", i)) 801 } 802 803 tbl = []struct { 804 arg interface{} 805 op opcode.Op 806 result interface{} 807 }{ 808 {mysql.NewDecimalFromInt(1, 0), opcode.Plus, mysql.NewDecimalFromInt(1, 0)}, 809 {mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}, opcode.Plus, 810 mysql.Duration{Duration: time.Duration(838*3600 + 59*60 + 59), Fsp: mysql.DefaultFsp}}, 811 {mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Plus, mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}}, 812 813 {mysql.NewDecimalFromInt(1, 0), opcode.Minus, mysql.NewDecimalFromInt(-1, 0)}, 814 {mysql.ZeroDuration, opcode.Minus, mysql.NewDecimalFromInt(0, 0)}, 815 {mysql.Time{Time: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), Type: mysql.TypeDatetime, Fsp: 0}, opcode.Minus, mysql.NewDecimalFromInt(-20091110230000, 0)}, 816 } 817 818 for _, t := range tbl { 819 expr := &ast.UnaryOperationExpr{Op: t.op, V: ast.NewValueExpr(t.arg)} 820 821 result, err := Eval(ctx, expr) 822 c.Assert(err, IsNil) 823 824 ret, err := result.CompareDatum(types.NewDatum(t.result)) 825 c.Assert(err, IsNil) 826 c.Assert(ret, Equals, 0) 827 } 828 } 829 830 func (s *testEvaluatorSuite) TestColumnNameExpr(c *C) { 831 defer testleak.AfterTest(c)() 832 ctx := mock.NewContext() 833 value1 := ast.NewValueExpr(1) 834 rf := &ast.ResultField{Expr: value1} 835 expr := &ast.ColumnNameExpr{Refer: rf} 836 837 ast.SetFlag(expr) 838 result, err := Eval(ctx, expr) 839 c.Assert(err, IsNil) 840 c.Assert(result, testutil.DatumEquals, types.NewDatum(int64(1))) 841 842 value2 := ast.NewValueExpr(2) 843 rf.Expr = value2 844 result, err = Eval(ctx, expr) 845 c.Assert(err, IsNil) 846 c.Assert(result, testutil.DatumEquals, types.NewDatum(int64(2))) 847 } 848 849 func (s *testEvaluatorSuite) TestAggFuncAvg(c *C) { 850 defer testleak.AfterTest(c)() 851 ctx := mock.NewContext() 852 avg := &ast.AggregateFuncExpr{ 853 F: ast.AggFuncAvg, 854 } 855 avg.CurrentGroup = "emptyGroup" 856 ast.SetFlag(avg) 857 result, err := Eval(ctx, avg) 858 c.Assert(err, IsNil) 859 // Empty group should return nil. 860 c.Assert(result.Kind(), Equals, types.KindNull) 861 862 avg.Args = []ast.ExprNode{ast.NewValueExpr(2)} 863 avg.Update() 864 avg.Args = []ast.ExprNode{ast.NewValueExpr(4)} 865 avg.Update() 866 867 result, err = Eval(ctx, avg) 868 c.Assert(err, IsNil) 869 expect, _ := mysql.ConvertToDecimal(3) 870 c.Assert(result.Kind(), Equals, types.KindMysqlDecimal) 871 c.Assert(result.GetMysqlDecimal().Equals(expect), IsTrue) 872 } 873 874 func (s *testEvaluatorSuite) TestGetTimeValue(c *C) { 875 defer testleak.AfterTest(c)() 876 v, err := GetTimeValue(nil, "2012-12-12 00:00:00", mysql.TypeTimestamp, mysql.MinFsp) 877 c.Assert(err, IsNil) 878 879 c.Assert(v.Kind(), Equals, types.KindMysqlTime) 880 timeValue := v.GetMysqlTime() 881 c.Assert(timeValue.String(), Equals, "2012-12-12 00:00:00") 882 883 ctx := mock.NewContext() 884 variable.BindSessionVars(ctx) 885 sessionVars := variable.GetSessionVars(ctx) 886 887 sessionVars.Systems["timestamp"] = "" 888 v, err = GetTimeValue(ctx, "2012-12-12 00:00:00", mysql.TypeTimestamp, mysql.MinFsp) 889 c.Assert(err, IsNil) 890 891 c.Assert(v.Kind(), Equals, types.KindMysqlTime) 892 timeValue = v.GetMysqlTime() 893 c.Assert(timeValue.String(), Equals, "2012-12-12 00:00:00") 894 895 sessionVars.Systems["timestamp"] = "0" 896 v, err = GetTimeValue(ctx, "2012-12-12 00:00:00", mysql.TypeTimestamp, mysql.MinFsp) 897 c.Assert(err, IsNil) 898 899 c.Assert(v.Kind(), Equals, types.KindMysqlTime) 900 timeValue = v.GetMysqlTime() 901 c.Assert(timeValue.String(), Equals, "2012-12-12 00:00:00") 902 903 delete(sessionVars.Systems, "timestamp") 904 v, err = GetTimeValue(ctx, "2012-12-12 00:00:00", mysql.TypeTimestamp, mysql.MinFsp) 905 c.Assert(err, IsNil) 906 907 c.Assert(v.Kind(), Equals, types.KindMysqlTime) 908 timeValue = v.GetMysqlTime() 909 c.Assert(timeValue.String(), Equals, "2012-12-12 00:00:00") 910 911 sessionVars.Systems["timestamp"] = "1234" 912 913 tbl := []struct { 914 Expr interface{} 915 Ret interface{} 916 }{ 917 {"2012-12-12 00:00:00", "2012-12-12 00:00:00"}, 918 {CurrentTimestamp, time.Unix(1234, 0).Format(mysql.TimeFormat)}, 919 {ZeroTimestamp, "0000-00-00 00:00:00"}, 920 {ast.NewValueExpr("2012-12-12 00:00:00"), "2012-12-12 00:00:00"}, 921 {ast.NewValueExpr(int64(0)), "0000-00-00 00:00:00"}, 922 {ast.NewValueExpr(nil), nil}, 923 {&ast.FuncCallExpr{FnName: model.NewCIStr(CurrentTimestamp)}, CurrentTimestamp}, 924 {&ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr(int64(0))}, "0000-00-00 00:00:00"}, 925 } 926 927 for i, t := range tbl { 928 comment := Commentf("expr: %d", i) 929 v, err := GetTimeValue(ctx, t.Expr, mysql.TypeTimestamp, mysql.MinFsp) 930 c.Assert(err, IsNil) 931 932 switch v.Kind() { 933 case types.KindMysqlTime: 934 c.Assert(v.GetMysqlTime().String(), DeepEquals, t.Ret, comment) 935 default: 936 c.Assert(v.GetValue(), DeepEquals, t.Ret, comment) 937 } 938 } 939 940 errTbl := []struct { 941 Expr interface{} 942 }{ 943 {"2012-13-12 00:00:00"}, 944 {ast.NewValueExpr("2012-13-12 00:00:00")}, 945 {ast.NewValueExpr(int64(1))}, 946 {&ast.FuncCallExpr{FnName: model.NewCIStr("xxx")}}, 947 {&ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr(int64(1))}}, 948 } 949 950 for _, t := range errTbl { 951 _, err := GetTimeValue(ctx, t.Expr, mysql.TypeTimestamp, mysql.MinFsp) 952 c.Assert(err, NotNil) 953 } 954 } 955 956 func (s *testEvaluatorSuite) TestIsCurrentTimeExpr(c *C) { 957 defer testleak.AfterTest(c)() 958 v := IsCurrentTimeExpr(ast.NewValueExpr("abc")) 959 c.Assert(v, IsFalse) 960 961 v = IsCurrentTimeExpr(&ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP")}) 962 c.Assert(v, IsTrue) 963 } 964 965 func (s *testEvaluatorSuite) TestEvaluatedFlag(c *C) { 966 l := ast.NewValueExpr(int64(1)) 967 r := ast.NewValueExpr(int64(2)) 968 b := &ast.BinaryOperationExpr{L: l, R: r, Op: opcode.Plus} 969 ast.SetFlag(b) 970 c.Assert(ast.IsPreEvaluable(b), Equals, true) 971 ctx := mock.NewContext() 972 d, err := Eval(ctx, b) 973 c.Assert(ast.IsEvaluated(b), Equals, true) 974 c.Assert(err, IsNil) 975 c.Assert(d, testutil.DatumEquals, types.NewIntDatum(3)) 976 977 funcCall := &ast.FuncCallExpr{ 978 FnName: model.NewCIStr("abs"), 979 Args: []ast.ExprNode{ast.NewValueExpr(int(-1))}, 980 } 981 b = &ast.BinaryOperationExpr{L: funcCall, R: r, Op: opcode.Plus} 982 ast.ResetEvaluatedFlag(b) 983 ast.SetFlag(b) 984 c.Assert(ast.IsPreEvaluable(b), Equals, true) 985 d, err = Eval(ctx, b) 986 c.Assert(ast.IsEvaluated(b), Equals, false) 987 c.Assert(err, IsNil) 988 c.Assert(d, testutil.DatumEquals, types.NewIntDatum(3)) 989 990 rf := &ast.ResultField{Expr: ast.NewValueExpr(int64(1))} 991 colExpr := &ast.ColumnNameExpr{Refer: rf} 992 b = &ast.BinaryOperationExpr{L: colExpr, R: r, Op: opcode.Plus} 993 ast.ResetEvaluatedFlag(b) 994 ast.SetFlag(b) 995 c.Assert(ast.IsPreEvaluable(b), Equals, false) 996 d, err = Eval(ctx, b) 997 c.Assert(ast.IsEvaluated(b), Equals, false) 998 c.Assert(err, IsNil) 999 c.Assert(d, testutil.DatumEquals, types.NewIntDatum(3)) 1000 } 1001 1002 func (s *testEvaluatorSuite) TestMod(c *C) { 1003 cases := []testCase{ 1004 { 1005 exprStr: "MOD(234, 10)", 1006 resultStr: "4", 1007 }, 1008 { 1009 exprStr: "MOD(29, 9)", 1010 resultStr: "2", 1011 }, 1012 { 1013 exprStr: "MOD(34.5, 3)", 1014 resultStr: "1.5", 1015 }, 1016 } 1017 s.runTests(c, cases) 1018 }