github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/evaluator/builtin_string_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 "errors" 18 "strings" 19 "time" 20 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/util/mock" 26 "github.com/insionng/yougam/libraries/pingcap/tidb/util/testleak" 27 "github.com/insionng/yougam/libraries/pingcap/tidb/util/testutil" 28 "github.com/insionng/yougam/libraries/pingcap/tidb/util/types" 29 ) 30 31 func (s *testEvaluatorSuite) TestLength(c *C) { 32 defer testleak.AfterTest(c)() 33 d, err := builtinLength(types.MakeDatums([]interface{}{nil}...), nil) 34 c.Assert(err, IsNil) 35 c.Assert(d.Kind(), Equals, types.KindNull) 36 37 tbl := []struct { 38 Input interface{} 39 Expected int64 40 }{ 41 {"abc", 3}, 42 {1, 1}, 43 {3.14, 4}, 44 {mysql.Time{Time: time.Now(), Fsp: 6, Type: mysql.TypeDatetime}, 26}, 45 {mysql.Bit{Value: 1, Width: 8}, 1}, 46 {mysql.Hex{Value: 1}, 1}, 47 {mysql.Set{Value: 1, Name: "abc"}, 3}, 48 } 49 50 dtbl := tblToDtbl(tbl) 51 52 for _, t := range dtbl { 53 d, err = builtinLength(t["Input"], nil) 54 c.Assert(err, IsNil) 55 c.Assert(d, testutil.DatumEquals, t["Expected"][0]) 56 } 57 } 58 59 func (s *testEvaluatorSuite) TestASCII(c *C) { 60 defer testleak.AfterTest(c)() 61 v, err := builtinASCII(types.MakeDatums([]interface{}{nil}...), nil) 62 c.Assert(err, IsNil) 63 c.Assert(v.Kind(), Equals, types.KindNull) 64 65 for _, t := range []struct { 66 Input interface{} 67 Expected int64 68 }{ 69 {"", 0}, 70 {"A", 65}, 71 {"你好", 228}, 72 {1, 49}, 73 {1.2, 49}, 74 {true, 49}, 75 {false, 48}, 76 } { 77 v, err = builtinASCII(types.MakeDatums(t.Input), nil) 78 c.Assert(err, IsNil) 79 c.Assert(v.GetInt64(), Equals, t.Expected) 80 } 81 82 v, err = builtinASCII(types.MakeDatums([]interface{}{errors.New("must error")}...), nil) 83 c.Assert(err, NotNil) 84 } 85 86 func (s *testEvaluatorSuite) TestConcat(c *C) { 87 defer testleak.AfterTest(c)() 88 args := []interface{}{nil} 89 90 v, err := builtinConcat(types.MakeDatums(args...), nil) 91 c.Assert(err, IsNil) 92 c.Assert(v.Kind(), Equals, types.KindNull) 93 94 args = []interface{}{"a", "b", "c"} 95 v, err = builtinConcat(types.MakeDatums(args...), nil) 96 c.Assert(err, IsNil) 97 c.Assert(v.GetString(), Equals, "abc") 98 99 args = []interface{}{"a", "b", nil, "c"} 100 v, err = builtinConcat(types.MakeDatums(args...), nil) 101 c.Assert(err, IsNil) 102 c.Assert(v.Kind(), Equals, types.KindNull) 103 104 args = []interface{}{errors.New("must error")} 105 _, err = builtinConcat(types.MakeDatums(args...), nil) 106 c.Assert(err, NotNil) 107 } 108 109 func (s *testEvaluatorSuite) TestConcatWS(c *C) { 110 defer testleak.AfterTest(c)() 111 args := types.MakeDatums([]interface{}{nil}...) 112 113 v, err := builtinConcatWS(args, nil) 114 c.Assert(err, IsNil) 115 c.Assert(v.Kind(), Equals, types.KindNull) 116 117 args = types.MakeDatums([]interface{}{"|", "a", nil, "b", "c"}...) 118 119 v, err = builtinConcatWS(args, nil) 120 c.Assert(err, IsNil) 121 c.Assert(v.GetString(), Equals, "a|b|c") 122 123 args = types.MakeDatums([]interface{}{errors.New("must error")}...) 124 _, err = builtinConcatWS(args, nil) 125 c.Assert(err, NotNil) 126 } 127 128 func (s *testEvaluatorSuite) TestLeft(c *C) { 129 defer testleak.AfterTest(c)() 130 args := types.MakeDatums([]interface{}{"abcdefg", int64(2)}...) 131 v, err := builtinLeft(args, nil) 132 c.Assert(err, IsNil) 133 c.Assert(v.GetString(), Equals, "ab") 134 135 args = types.MakeDatums([]interface{}{"abcdefg", int64(-1)}...) 136 v, err = builtinLeft(args, nil) 137 c.Assert(err, IsNil) 138 c.Assert(v.GetString(), Equals, "") 139 140 args = types.MakeDatums([]interface{}{"abcdefg", int64(100)}...) 141 v, err = builtinLeft(args, nil) 142 c.Assert(err, IsNil) 143 c.Assert(v.GetString(), Equals, "abcdefg") 144 145 args = types.MakeDatums([]interface{}{1, int64(1)}...) 146 _, err = builtinLeft(args, nil) 147 c.Assert(err, IsNil) 148 149 args = types.MakeDatums([]interface{}{"abcdefg", "xxx"}...) 150 _, err = builtinLeft(args, nil) 151 c.Assert(err, NotNil) 152 } 153 154 func (s *testEvaluatorSuite) TestRepeat(c *C) { 155 defer testleak.AfterTest(c)() 156 args := []interface{}{"a", int64(2)} 157 v, err := builtinRepeat(types.MakeDatums(args...), nil) 158 c.Assert(err, IsNil) 159 c.Assert(v.GetString(), Equals, "aa") 160 161 args = []interface{}{"a", uint64(2)} 162 v, err = builtinRepeat(types.MakeDatums(args...), nil) 163 c.Assert(err, IsNil) 164 c.Assert(v.GetString(), Equals, "aa") 165 166 args = []interface{}{"a", int64(-1)} 167 v, err = builtinRepeat(types.MakeDatums(args...), nil) 168 c.Assert(err, IsNil) 169 c.Assert(v.GetString(), Equals, "") 170 171 args = []interface{}{"a", int64(0)} 172 v, err = builtinRepeat(types.MakeDatums(args...), nil) 173 c.Assert(err, IsNil) 174 c.Assert(v.GetString(), Equals, "") 175 176 args = []interface{}{"a", uint64(0)} 177 v, err = builtinRepeat(types.MakeDatums(args...), nil) 178 c.Assert(err, IsNil) 179 c.Assert(v.GetString(), Equals, "") 180 } 181 182 func (s *testEvaluatorSuite) TestLowerAndUpper(c *C) { 183 defer testleak.AfterTest(c)() 184 d, err := builtinLower(types.MakeDatums([]interface{}{nil}...), nil) 185 c.Assert(err, IsNil) 186 c.Assert(d.Kind(), Equals, types.KindNull) 187 188 d, err = builtinUpper(types.MakeDatums([]interface{}{nil}...), nil) 189 c.Assert(err, IsNil) 190 c.Assert(d.Kind(), Equals, types.KindNull) 191 192 tbl := []struct { 193 Input interface{} 194 Expect string 195 }{ 196 {"abc", "abc"}, 197 {1, "1"}, 198 } 199 200 dtbl := tblToDtbl(tbl) 201 202 for _, t := range dtbl { 203 d, err = builtinLower(t["Input"], nil) 204 c.Assert(err, IsNil) 205 c.Assert(d, testutil.DatumEquals, t["Expect"][0]) 206 207 d, err = builtinUpper(t["Input"], nil) 208 c.Assert(err, IsNil) 209 c.Assert(d.GetString(), Equals, strings.ToUpper(t["Expect"][0].GetString())) 210 } 211 } 212 213 func (s *testEvaluatorSuite) TestReverse(c *C) { 214 defer testleak.AfterTest(c)() 215 d, err := builtinReverse(types.MakeDatums([]interface{}{nil}...), nil) 216 c.Assert(err, IsNil) 217 c.Assert(d.Kind(), Equals, types.KindNull) 218 219 tbl := []struct { 220 Input interface{} 221 Expect string 222 }{ 223 {"abc", "cba"}, 224 {"LIKE", "EKIL"}, 225 {123, "321"}, 226 {"", ""}, 227 } 228 229 dtbl := tblToDtbl(tbl) 230 231 for _, t := range dtbl { 232 d, err = builtinReverse(t["Input"], nil) 233 c.Assert(err, IsNil) 234 c.Assert(d, testutil.DatumEquals, t["Expect"][0]) 235 } 236 } 237 238 func (s *testEvaluatorSuite) TestStrcmp(c *C) { 239 defer testleak.AfterTest(c)() 240 tbl := []struct { 241 Input []interface{} 242 Expect interface{} 243 }{ 244 {[]interface{}{"1", "2"}, -1}, 245 {[]interface{}{"2", "1"}, 1}, 246 {[]interface{}{"123", "2"}, -1}, 247 {[]interface{}{"1", "213"}, -1}, 248 {[]interface{}{"123", "123"}, 0}, 249 {[]interface{}{"", "123"}, -1}, 250 {[]interface{}{"123", ""}, 1}, 251 {[]interface{}{"", ""}, 0}, 252 {[]interface{}{nil, "123"}, nil}, 253 {[]interface{}{"123", nil}, nil}, 254 {[]interface{}{nil, nil}, nil}, 255 {[]interface{}{"", nil}, nil}, 256 {[]interface{}{nil, ""}, nil}, 257 } 258 259 dtbl := tblToDtbl(tbl) 260 for _, t := range dtbl { 261 d, err := builtinStrcmp(t["Input"], nil) 262 c.Assert(err, IsNil) 263 c.Assert(d, testutil.DatumEquals, t["Expect"][0]) 264 } 265 } 266 267 func (s *testEvaluatorSuite) TestReplace(c *C) { 268 defer testleak.AfterTest(c)() 269 tbl := []struct { 270 Input []interface{} 271 Expect interface{} 272 }{ 273 {[]interface{}{nil, nil, nil}, nil}, 274 {[]interface{}{1, nil, 2}, nil}, 275 {[]interface{}{1, 1, nil}, nil}, 276 {[]interface{}{"12345", 2, 222}, "1222345"}, 277 {[]interface{}{"12325", 2, "a"}, "1a3a5"}, 278 {[]interface{}{12345, 2, "aa"}, "1aa345"}, 279 } 280 281 dtbl := tblToDtbl(tbl) 282 283 for _, t := range dtbl { 284 d, err := builtinReplace(t["Input"], nil) 285 c.Assert(err, IsNil) 286 c.Assert(d, testutil.DatumEquals, t["Expect"][0]) 287 } 288 } 289 290 func (s *testEvaluatorSuite) TestSubstring(c *C) { 291 defer testleak.AfterTest(c)() 292 293 d, err := builtinSubstring(types.MakeDatums([]interface{}{"hello", 2, -1}...), nil) 294 c.Assert(err, IsNil) 295 c.Assert(d.GetString(), Equals, "") 296 297 tbl := []struct { 298 str string 299 pos int64 300 slen int64 301 result string 302 }{ 303 {"Quadratically", 5, -1, "ratically"}, 304 {"foobarbar", 4, -1, "barbar"}, 305 {"Sakila", 1, -1, "Sakila"}, 306 {"Sakila", 2, -1, "akila"}, 307 {"Sakila", -3, -1, "ila"}, 308 {"Sakila", -5, 3, "aki"}, 309 {"Sakila", -4, 2, "ki"}, 310 {"Quadratically", 5, 6, "ratica"}, 311 {"Sakila", 1, 4, "Saki"}, 312 {"Sakila", -6, 4, "Saki"}, 313 {"Sakila", 2, 1000, "akila"}, 314 {"Sakila", -5, 1000, "akila"}, 315 {"Sakila", 2, -2, ""}, 316 {"Sakila", -5, -2, ""}, 317 {"Sakila", 2, 0, ""}, 318 {"Sakila", -5, -3, ""}, 319 {"Sakila", -1000, 3, ""}, 320 {"Sakila", 1000, 2, ""}, 321 {"", 2, 3, ""}, 322 } 323 ctx := mock.NewContext() 324 for _, v := range tbl { 325 f := &ast.FuncCallExpr{ 326 FnName: model.NewCIStr("SUBSTRING"), 327 Args: []ast.ExprNode{ast.NewValueExpr(v.str), ast.NewValueExpr(v.pos)}, 328 } 329 if v.slen != -1 { 330 f.Args = append(f.Args, ast.NewValueExpr(v.slen)) 331 } 332 r, err := Eval(ctx, f) 333 c.Assert(err, IsNil) 334 c.Assert(r.Kind(), Equals, types.KindString) 335 c.Assert(r.GetString(), Equals, v.result) 336 337 r1, err := Eval(ctx, f) 338 c.Assert(err, IsNil) 339 c.Assert(r1.Kind(), Equals, types.KindString) 340 c.Assert(r.GetString(), Equals, r1.GetString()) 341 } 342 errTbl := []struct { 343 str interface{} 344 pos interface{} 345 len interface{} 346 result string 347 }{ 348 {"foobarbar", "4", -1, "barbar"}, 349 {"Quadratically", 5, "6", "ratica"}, 350 } 351 for _, v := range errTbl { 352 f := &ast.FuncCallExpr{ 353 FnName: model.NewCIStr("SUBSTRING"), 354 Args: []ast.ExprNode{ast.NewValueExpr(v.str), ast.NewValueExpr(v.pos)}, 355 } 356 if v.len != -1 { 357 f.Args = append(f.Args, ast.NewValueExpr(v.len)) 358 } 359 _, err := Eval(ctx, f) 360 c.Assert(err, NotNil) 361 } 362 } 363 364 func (s *testEvaluatorSuite) TestConvert(c *C) { 365 defer testleak.AfterTest(c)() 366 ctx := mock.NewContext() 367 tbl := []struct { 368 str string 369 cs string 370 result string 371 }{ 372 {"haha", "utf8", "haha"}, 373 {"haha", "ascii", "haha"}, 374 } 375 for _, v := range tbl { 376 f := &ast.FuncCallExpr{ 377 FnName: model.NewCIStr("CONVERT"), 378 Args: []ast.ExprNode{ 379 ast.NewValueExpr(v.str), 380 ast.NewValueExpr(v.cs), 381 }, 382 } 383 384 r, err := Eval(ctx, f) 385 c.Assert(err, IsNil) 386 c.Assert(r.Kind(), Equals, types.KindString) 387 c.Assert(r.GetString(), Equals, v.result) 388 } 389 390 // Test case for error 391 errTbl := []struct { 392 str interface{} 393 cs string 394 result string 395 }{ 396 {"haha", "wrongcharset", "haha"}, 397 } 398 for _, v := range errTbl { 399 f := &ast.FuncCallExpr{ 400 FnName: model.NewCIStr("CONVERT"), 401 Args: []ast.ExprNode{ 402 ast.NewValueExpr(v.str), 403 ast.NewValueExpr(v.cs), 404 }, 405 } 406 407 _, err := Eval(ctx, f) 408 c.Assert(err, NotNil) 409 } 410 } 411 412 func (s *testEvaluatorSuite) TestSubstringIndex(c *C) { 413 defer testleak.AfterTest(c)() 414 tbl := []struct { 415 str string 416 delim string 417 count int64 418 result string 419 }{ 420 {"www.mysql.com", ".", 2, "www.mysql"}, 421 {"www.mysql.com", ".", -2, "mysql.com"}, 422 {"www.mysql.com", ".", 0, ""}, 423 {"www.mysql.com", ".", 3, "www.mysql.com"}, 424 {"www.mysql.com", ".", 4, "www.mysql.com"}, 425 {"www.mysql.com", ".", -3, "www.mysql.com"}, 426 {"www.mysql.com", ".", -4, "www.mysql.com"}, 427 428 {"www.mysql.com", "d", 1, "www.mysql.com"}, 429 {"www.mysql.com", "d", 0, ""}, 430 {"www.mysql.com", "d", -1, "www.mysql.com"}, 431 432 {"", ".", 2, ""}, 433 {"", ".", -2, ""}, 434 {"", ".", 0, ""}, 435 436 {"www.mysql.com", "", 1, ""}, 437 {"www.mysql.com", "", -1, ""}, 438 {"www.mysql.com", "", 0, ""}, 439 } 440 ctx := mock.NewContext() 441 for _, v := range tbl { 442 f := &ast.FuncCallExpr{ 443 FnName: model.NewCIStr("SUBSTRING_INDEX"), 444 Args: []ast.ExprNode{ast.NewValueExpr(v.str), ast.NewValueExpr(v.delim), ast.NewValueExpr(v.count)}, 445 } 446 r, err := Eval(ctx, f) 447 c.Assert(err, IsNil) 448 c.Assert(r.Kind(), Equals, types.KindString) 449 c.Assert(r.GetString(), Equals, v.result) 450 } 451 errTbl := []struct { 452 str interface{} 453 delim interface{} 454 count interface{} 455 }{ 456 {nil, ".", 2}, 457 {nil, ".", -2}, 458 {nil, ".", 0}, 459 {"asdf", nil, 2}, 460 {"asdf", nil, -2}, 461 {"asdf", nil, 0}, 462 {"www.mysql.com", ".", nil}, 463 } 464 for _, v := range errTbl { 465 f := &ast.FuncCallExpr{ 466 FnName: model.NewCIStr("SUBSTRING_INDEX"), 467 Args: []ast.ExprNode{ast.NewValueExpr(v.str), ast.NewValueExpr(v.delim), ast.NewValueExpr(v.count)}, 468 } 469 r, err := Eval(ctx, f) 470 c.Assert(err, NotNil) 471 c.Assert(r.Kind(), Equals, types.KindNull) 472 } 473 } 474 475 func (s *testEvaluatorSuite) TestLocate(c *C) { 476 defer testleak.AfterTest(c)() 477 tbl := []struct { 478 subStr string 479 Str string 480 result int64 481 }{ 482 {"bar", "foobarbar", 4}, 483 {"xbar", "foobar", 0}, 484 {"", "foobar", 1}, 485 {"foobar", "", 0}, 486 {"", "", 1}, 487 } 488 ctx := mock.NewContext() 489 for _, v := range tbl { 490 f := &ast.FuncCallExpr{ 491 FnName: model.NewCIStr("LOCATE"), 492 Args: []ast.ExprNode{ast.NewValueExpr(v.subStr), ast.NewValueExpr(v.Str)}, 493 } 494 r, err := Eval(ctx, f) 495 c.Assert(err, IsNil) 496 c.Assert(r.Kind(), Equals, types.KindInt64) 497 c.Assert(r.GetInt64(), Equals, v.result) 498 } 499 500 tbl2 := []struct { 501 subStr string 502 Str string 503 pos int64 504 result int64 505 }{ 506 {"bar", "foobarbar", 5, 7}, 507 {"xbar", "foobar", 1, 0}, 508 {"", "foobar", 2, 2}, 509 {"foobar", "", 1, 0}, 510 {"", "", 2, 0}, 511 } 512 for _, v := range tbl2 { 513 f := &ast.FuncCallExpr{ 514 FnName: model.NewCIStr("LOCATE"), 515 Args: []ast.ExprNode{ast.NewValueExpr(v.subStr), ast.NewValueExpr(v.Str), ast.NewValueExpr(v.pos)}, 516 } 517 r, err := Eval(ctx, f) 518 c.Assert(err, IsNil) 519 c.Assert(r.Kind(), Equals, types.KindInt64) 520 c.Assert(r.GetInt64(), Equals, v.result) 521 } 522 523 errTbl := []struct { 524 subStr interface{} 525 Str interface{} 526 }{ 527 {nil, nil}, 528 {"", nil}, 529 {nil, ""}, 530 {"foo", nil}, 531 {nil, "bar"}, 532 } 533 for _, v := range errTbl { 534 f := &ast.FuncCallExpr{ 535 FnName: model.NewCIStr("LOCATE"), 536 Args: []ast.ExprNode{ast.NewValueExpr(v.subStr), ast.NewValueExpr(v.Str)}, 537 } 538 r, _ := Eval(ctx, f) 539 c.Assert(r.Kind(), Equals, types.KindNull) 540 } 541 542 errTbl2 := []struct { 543 subStr interface{} 544 Str interface{} 545 pos interface{} 546 }{ 547 {nil, nil, 1}, 548 {"", nil, 1}, 549 {nil, "", 1}, 550 {"foo", nil, -1}, 551 {nil, "bar", 0}, 552 } 553 for _, v := range errTbl2 { 554 f := &ast.FuncCallExpr{ 555 FnName: model.NewCIStr("LOCATE"), 556 Args: []ast.ExprNode{ast.NewValueExpr(v.subStr), ast.NewValueExpr(v.Str), ast.NewValueExpr(v.pos)}, 557 } 558 r, _ := Eval(ctx, f) 559 c.Assert(r.Kind(), Equals, types.KindNull) 560 } 561 } 562 563 func (s *testEvaluatorSuite) TestTrim(c *C) { 564 defer testleak.AfterTest(c)() 565 tbl := []struct { 566 str interface{} 567 remstr interface{} 568 dir ast.TrimDirectionType 569 result interface{} 570 }{ 571 {" bar ", nil, ast.TrimBothDefault, "bar"}, 572 {"xxxbarxxx", "x", ast.TrimLeading, "barxxx"}, 573 {"xxxbarxxx", "x", ast.TrimBoth, "bar"}, 574 {"barxxyz", "xyz", ast.TrimTrailing, "barx"}, 575 {nil, "xyz", ast.TrimBoth, nil}, 576 {1, 2, ast.TrimBoth, "1"}, 577 {" \t\rbar\n ", nil, ast.TrimBothDefault, "bar"}, 578 } 579 ctx := mock.NewContext() 580 for _, v := range tbl { 581 f := &ast.FuncCallExpr{ 582 FnName: model.NewCIStr("TRIM"), 583 Args: []ast.ExprNode{ 584 ast.NewValueExpr(v.str), 585 ast.NewValueExpr(v.remstr), 586 ast.NewValueExpr(v.dir), 587 }, 588 } 589 r, err := Eval(ctx, f) 590 c.Assert(err, IsNil) 591 c.Assert(r, testutil.DatumEquals, types.NewDatum(v.result)) 592 } 593 594 for _, v := range []struct { 595 str, result interface{} 596 fn string 597 }{ 598 {" ", "", "LTRIM"}, 599 {" ", "", "RTRIM"}, 600 {"foo0", "foo0", "LTRIM"}, 601 {"bar0", "bar0", "RTRIM"}, 602 {" foo1", "foo1", "LTRIM"}, 603 {"bar1 ", "bar1", "RTRIM"}, 604 {spaceChars + "foo2 ", "foo2 ", "LTRIM"}, 605 {" bar2" + spaceChars, " bar2", "RTRIM"}, 606 {nil, nil, "LTRIM"}, 607 {nil, nil, "RTRIM"}, 608 } { 609 f := &ast.FuncCallExpr{ 610 FnName: model.NewCIStr(v.fn), 611 Args: []ast.ExprNode{ast.NewValueExpr(v.str)}, 612 } 613 r, err := Eval(ctx, f) 614 c.Assert(err, IsNil) 615 c.Assert(r, testutil.DatumEquals, types.NewDatum(v.result)) 616 } 617 }