github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/colexec/table_function/generate_series_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 table_function 16 17 import ( 18 "bytes" 19 "context" 20 "github.com/matrixorigin/matrixone/pkg/container/batch" 21 "github.com/matrixorigin/matrixone/pkg/container/types" 22 "github.com/matrixorigin/matrixone/pkg/container/vector" 23 "github.com/matrixorigin/matrixone/pkg/logutil" 24 plan2 "github.com/matrixorigin/matrixone/pkg/pb/plan" 25 "github.com/matrixorigin/matrixone/pkg/sql/plan" 26 "github.com/matrixorigin/matrixone/pkg/testutil" 27 "github.com/stretchr/testify/require" 28 "math" 29 "strings" 30 "testing" 31 ) 32 33 type Kase[T int32 | int64] struct { 34 start T 35 end T 36 step T 37 res []T 38 err bool 39 } 40 41 func TestDoGenerateInt32(t *testing.T) { 42 kases := []Kase[int32]{ 43 { 44 start: 1, 45 end: 10, 46 step: 1, 47 res: []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 48 }, 49 { 50 start: 1, 51 end: 10, 52 step: 2, 53 res: []int32{1, 3, 5, 7, 9}, 54 }, 55 { 56 start: 1, 57 end: 10, 58 step: -1, 59 res: []int32{}, 60 }, 61 { 62 start: 10, 63 end: 1, 64 step: -1, 65 res: []int32{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, 66 }, 67 { 68 start: 10, 69 end: 1, 70 step: -2, 71 res: []int32{10, 8, 6, 4, 2}, 72 }, 73 { 74 start: 10, 75 end: 1, 76 step: 1, 77 res: []int32{}, 78 }, 79 { 80 start: 1, 81 end: 10, 82 step: 0, 83 err: true, 84 }, 85 { 86 start: 1, 87 end: 10, 88 step: -1, 89 res: []int32{}, 90 }, 91 { 92 start: 1, 93 end: 1, 94 step: 0, 95 err: true, 96 }, 97 { 98 start: 1, 99 end: 1, 100 step: 1, 101 res: []int32{1}, 102 }, 103 { 104 start: math.MaxInt32 - 1, 105 end: math.MaxInt32, 106 step: 1, 107 res: []int32{math.MaxInt32 - 1, math.MaxInt32}, 108 }, 109 { 110 start: math.MaxInt32, 111 end: math.MaxInt32 - 1, 112 step: -1, 113 res: []int32{math.MaxInt32, math.MaxInt32 - 1}, 114 }, 115 { 116 start: math.MinInt32, 117 end: math.MinInt32 + 100, 118 step: 19, 119 res: []int32{math.MinInt32, math.MinInt32 + 19, math.MinInt32 + 38, math.MinInt32 + 57, math.MinInt32 + 76, math.MinInt32 + 95}, 120 }, 121 { 122 start: math.MinInt32 + 100, 123 end: math.MinInt32, 124 step: -19, 125 res: []int32{math.MinInt32 + 100, math.MinInt32 + 81, math.MinInt32 + 62, math.MinInt32 + 43, math.MinInt32 + 24, math.MinInt32 + 5}, 126 }, 127 } 128 for _, kase := range kases { 129 res, err := generateInt32(context.TODO(), kase.start, kase.end, kase.step) 130 if kase.err { 131 require.NotNil(t, err) 132 continue 133 } 134 require.Nil(t, err) 135 require.Equal(t, kase.res, res) 136 } 137 } 138 139 func TestDoGenerateInt64(t *testing.T) { 140 kases := []Kase[int64]{ 141 { 142 start: 1, 143 end: 10, 144 step: 1, 145 res: []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 146 }, 147 { 148 start: 1, 149 end: 10, 150 step: 2, 151 res: []int64{1, 3, 5, 7, 9}, 152 }, 153 { 154 start: 1, 155 end: 10, 156 step: -1, 157 res: []int64{}, 158 }, 159 { 160 start: 10, 161 end: 1, 162 step: -1, 163 res: []int64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, 164 }, 165 { 166 start: 10, 167 end: 1, 168 step: -2, 169 res: []int64{10, 8, 6, 4, 2}, 170 }, 171 { 172 start: 10, 173 end: 1, 174 step: 1, 175 res: []int64{}, 176 }, 177 { 178 start: 1, 179 end: 10, 180 step: 0, 181 err: true, 182 }, 183 { 184 start: 1, 185 end: 10, 186 step: -1, 187 res: []int64{}, 188 }, 189 { 190 start: 1, 191 end: 1, 192 step: 0, 193 err: true, 194 }, 195 { 196 start: 1, 197 end: 1, 198 step: 1, 199 res: []int64{1}, 200 }, 201 { 202 start: math.MaxInt32 - 1, 203 end: math.MaxInt32, 204 step: 1, 205 res: []int64{math.MaxInt32 - 1, math.MaxInt32}, 206 }, 207 { 208 start: math.MaxInt32, 209 end: math.MaxInt32 - 1, 210 step: -1, 211 res: []int64{math.MaxInt32, math.MaxInt32 - 1}, 212 }, 213 { 214 start: math.MinInt32, 215 end: math.MinInt32 + 100, 216 step: 19, 217 res: []int64{math.MinInt32, math.MinInt32 + 19, math.MinInt32 + 38, math.MinInt32 + 57, math.MinInt32 + 76, math.MinInt32 + 95}, 218 }, 219 { 220 start: math.MinInt32 + 100, 221 end: math.MinInt32, 222 step: -19, 223 res: []int64{math.MinInt32 + 100, math.MinInt32 + 81, math.MinInt32 + 62, math.MinInt32 + 43, math.MinInt32 + 24, math.MinInt32 + 5}, 224 }, 225 // int64 226 { 227 start: math.MaxInt32, 228 end: math.MaxInt32 + 100, 229 step: 19, 230 res: []int64{math.MaxInt32, math.MaxInt32 + 19, math.MaxInt32 + 38, math.MaxInt32 + 57, math.MaxInt32 + 76, math.MaxInt32 + 95}, 231 }, 232 { 233 start: math.MaxInt32 + 100, 234 end: math.MaxInt32, 235 step: -19, 236 res: []int64{math.MaxInt32 + 100, math.MaxInt32 + 81, math.MaxInt32 + 62, math.MaxInt32 + 43, math.MaxInt32 + 24, math.MaxInt32 + 5}, 237 }, 238 { 239 start: math.MinInt32, 240 end: math.MinInt32 - 100, 241 step: -19, 242 res: []int64{math.MinInt32, math.MinInt32 - 19, math.MinInt32 - 38, math.MinInt32 - 57, math.MinInt32 - 76, math.MinInt32 - 95}, 243 }, 244 { 245 start: math.MinInt32 - 100, 246 end: math.MinInt32, 247 step: 19, 248 res: []int64{math.MinInt32 - 100, math.MinInt32 - 81, math.MinInt32 - 62, math.MinInt32 - 43, math.MinInt32 - 24, math.MinInt32 - 5}, 249 }, 250 { 251 start: math.MaxInt64 - 1, 252 end: math.MaxInt64, 253 step: 1, 254 res: []int64{math.MaxInt64 - 1, math.MaxInt64}, 255 }, 256 { 257 start: math.MaxInt64, 258 end: math.MaxInt64 - 1, 259 step: -1, 260 res: []int64{math.MaxInt64, math.MaxInt64 - 1}, 261 }, 262 { 263 start: math.MaxInt64 - 100, 264 end: math.MaxInt64, 265 step: 19, 266 res: []int64{math.MaxInt64 - 100, math.MaxInt64 - 81, math.MaxInt64 - 62, math.MaxInt64 - 43, math.MaxInt64 - 24, math.MaxInt64 - 5}, 267 }, 268 { 269 start: math.MaxInt64, 270 end: math.MaxInt64 - 100, 271 step: -19, 272 res: []int64{math.MaxInt64, math.MaxInt64 - 19, math.MaxInt64 - 38, math.MaxInt64 - 57, math.MaxInt64 - 76, math.MaxInt64 - 95}, 273 }, 274 { 275 start: math.MinInt64, 276 end: math.MinInt64 + 100, 277 step: 19, 278 res: []int64{math.MinInt64, math.MinInt64 + 19, math.MinInt64 + 38, math.MinInt64 + 57, math.MinInt64 + 76, math.MinInt64 + 95}, 279 }, 280 { 281 start: math.MinInt64 + 100, 282 end: math.MinInt64, 283 step: -19, 284 res: []int64{math.MinInt64 + 100, math.MinInt64 + 81, math.MinInt64 + 62, math.MinInt64 + 43, math.MinInt64 + 24, math.MinInt64 + 5}, 285 }, 286 } 287 for _, kase := range kases { 288 res, err := generateInt64(context.TODO(), kase.start, kase.end, kase.step) 289 if kase.err { 290 require.NotNil(t, err) 291 continue 292 } 293 require.Nil(t, err) 294 require.Equal(t, kase.res, res) 295 } 296 } 297 298 func TestGenerateTimestamp(t *testing.T) { 299 kases := []struct { 300 start string 301 end string 302 step string 303 res []types.Datetime 304 err bool 305 }{ 306 { 307 start: "2019-01-01 00:00:00", 308 end: "2019-01-01 00:01:00", 309 step: "30 second", 310 res: []types.Datetime{ 311 transStr2Datetime("2019-01-01 00:00:00"), 312 transStr2Datetime("2019-01-01 00:00:30"), 313 transStr2Datetime("2019-01-01 00:01:00"), 314 }, 315 }, 316 { 317 start: "2019-01-01 00:01:00", 318 end: "2019-01-01 00:00:00", 319 step: "-30 second", 320 res: []types.Datetime{ 321 transStr2Datetime("2019-01-01 00:01:00"), 322 transStr2Datetime("2019-01-01 00:00:30"), 323 transStr2Datetime("2019-01-01 00:00:00"), 324 }, 325 }, 326 { 327 start: "2019-01-01 00:00:00", 328 end: "2019-01-01 00:01:00", 329 step: "30 minute", 330 res: []types.Datetime{ 331 transStr2Datetime("2019-01-01 00:00:00"), 332 }, 333 }, 334 { 335 start: "2020-02-29 00:01:00", 336 end: "2021-03-01 00:00:00", 337 step: "1 year", 338 res: []types.Datetime{ 339 transStr2Datetime("2020-02-29 00:01:00"), 340 transStr2Datetime("2021-02-28 00:01:00"), 341 }, 342 }, 343 { 344 start: "2020-02-29 00:01:00", 345 end: "2021-03-01 00:00:00", 346 step: "1 month", 347 res: []types.Datetime{ 348 transStr2Datetime("2020-02-29 00:01:00"), 349 transStr2Datetime("2020-03-29 00:01:00"), 350 transStr2Datetime("2020-04-29 00:01:00"), 351 transStr2Datetime("2020-05-29 00:01:00"), 352 transStr2Datetime("2020-06-29 00:01:00"), 353 transStr2Datetime("2020-07-29 00:01:00"), 354 transStr2Datetime("2020-08-29 00:01:00"), 355 transStr2Datetime("2020-09-29 00:01:00"), 356 transStr2Datetime("2020-10-29 00:01:00"), 357 transStr2Datetime("2020-11-29 00:01:00"), 358 transStr2Datetime("2020-12-29 00:01:00"), 359 transStr2Datetime("2021-01-29 00:01:00"), 360 transStr2Datetime("2021-02-28 00:01:00"), 361 }, 362 }, 363 { 364 start: "2020-02-29 00:01:00", 365 end: "2021-03-01 00:00:00", 366 step: "1 year", 367 res: []types.Datetime{ 368 transStr2Datetime("2020-02-29 00:01:00"), 369 transStr2Datetime("2021-02-28 00:01:00"), 370 }, 371 }, 372 { 373 start: "2020-02-28 00:01:00", 374 end: "2021-03-01 00:00:00", 375 step: "1 year", 376 res: []types.Datetime{ 377 transStr2Datetime("2020-02-28 00:01:00"), 378 transStr2Datetime("2021-02-28 00:01:00"), 379 }, 380 }, 381 } 382 for _, kase := range kases { 383 var precision int32 384 p1, p2 := getPrecision(kase.start), getPrecision(kase.end) 385 if p1 > p2 { 386 precision = p1 387 } else { 388 precision = p2 389 } 390 start, err := types.ParseDatetime(kase.start, precision) 391 require.Nil(t, err) 392 end, err := types.ParseDatetime(kase.end, precision) 393 require.Nil(t, err) 394 res, err := generateDatetime(context.TODO(), start, end, kase.step, precision) 395 if kase.err { 396 require.NotNil(t, err) 397 continue 398 } 399 require.Nil(t, err) 400 require.Equal(t, kase.res, res) 401 } 402 } 403 404 func transStr2Datetime(s string) types.Datetime { 405 precision := getPrecision(s) 406 t, err := types.ParseDatetime(s, precision) 407 if err != nil { 408 logutil.Errorf("parse timestamp '%s' failed", s) 409 } 410 return t 411 } 412 413 func getPrecision(s string) int32 { 414 var precision int32 415 ss := strings.Split(s, ".") 416 if len(ss) > 1 { 417 precision = int32(len(ss[1])) 418 } 419 return precision 420 } 421 422 func TestGenerateSeriesString(t *testing.T) { 423 generateSeriesString(nil, new(bytes.Buffer)) 424 } 425 426 func TestGenerateSeriesPrepare(t *testing.T) { 427 err := generateSeriesPrepare(nil, nil) 428 require.Nil(t, err) 429 } 430 func TestGenStep(t *testing.T) { 431 ctx := context.TODO() 432 kase := "10 hour" 433 num, tp, err := genStep(ctx, kase) 434 require.Nil(t, err) 435 require.Equal(t, int64(10), num) 436 require.Equal(t, types.Hour, tp) 437 kase = "10 houx" 438 _, _, err = genStep(ctx, kase) 439 require.NotNil(t, err) 440 kase = "hour" 441 _, _, err = genStep(ctx, kase) 442 require.NotNil(t, err) 443 kase = "989829829129131939147193 hour" 444 _, _, err = genStep(ctx, kase) 445 require.NotNil(t, err) 446 } 447 448 func TestGenerateSeriesCall(t *testing.T) { 449 proc := testutil.NewProc() 450 beforeCall := proc.Mp().CurrNB() 451 arg := &Argument{ 452 Attrs: []string{"result"}, 453 } 454 proc.SetInputBatch(nil) 455 end, err := generateSeriesCall(0, proc, arg) 456 require.Nil(t, err) 457 require.Equal(t, true, end) 458 459 arg.Args = makeInt64List(1, 3, 1) 460 461 bat := makeGenerateSeriesBatch() 462 proc.SetInputBatch(bat) 463 end, err = generateSeriesCall(0, proc, arg) 464 require.Nil(t, err) 465 require.Equal(t, false, end) 466 require.Equal(t, 3, proc.InputBatch().GetVector(0).Length()) 467 proc.InputBatch().Clean(proc.Mp()) 468 469 arg.Args = makeDatetimeList("2020-01-01 00:00:00", "2020-01-01 00:00:59", "1 second", 0) 470 proc.SetInputBatch(bat) 471 end, err = generateSeriesCall(0, proc, arg) 472 require.Nil(t, err) 473 require.Equal(t, false, end) 474 require.Equal(t, 60, proc.InputBatch().GetVector(0).Length()) 475 proc.InputBatch().Clean(proc.Mp()) 476 477 arg.Args = makeVarcharList("2020-01-01 00:00:00", "2020-01-01 00:00:59", "1 second") 478 proc.SetInputBatch(bat) 479 end, err = generateSeriesCall(0, proc, arg) 480 require.Nil(t, err) 481 require.Equal(t, false, end) 482 require.Equal(t, 60, proc.InputBatch().GetVector(0).Length()) 483 proc.InputBatch().Clean(proc.Mp()) 484 485 arg.Args = makeVarcharList("1", "10", "3") 486 proc.SetInputBatch(bat) 487 end, err = generateSeriesCall(0, proc, arg) 488 require.Nil(t, err) 489 require.Equal(t, false, end) 490 require.Equal(t, 4, proc.InputBatch().GetVector(0).Length()) 491 proc.InputBatch().Clean(proc.Mp()) 492 493 arg.Args = arg.Args[:2] 494 proc.SetInputBatch(bat) 495 _, err = generateSeriesCall(0, proc, arg) 496 require.NotNil(t, err) 497 bat.Clean(proc.Mp()) 498 require.Equal(t, beforeCall, proc.Mp().CurrNB()) 499 500 } 501 502 func makeGenerateSeriesBatch() *batch.Batch { 503 bat := batch.NewWithSize(1) 504 bat.Vecs[0] = vector.NewConst(types.Type{Oid: types.T_int64}, 1) 505 bat.Vecs[0].Col = make([]int64, 1) 506 bat.InitZsOne(1) 507 return bat 508 } 509 510 func makeInt64List(start, end, step int64) []*plan.Expr { 511 ret := make([]*plan.Expr, 3) 512 ret[0] = makeInt64Expr(start) 513 ret[1] = makeInt64Expr(end) 514 ret[2] = makeInt64Expr(step) 515 return ret 516 } 517 518 func makeDatetimeList(start, end, step string, precision int32) []*plan.Expr { 519 ret := make([]*plan.Expr, 3) 520 ret[0] = makeDatetimeExpr(start, precision) 521 ret[1] = makeDatetimeExpr(end, precision) 522 ret[2] = makeVarcharExpr(step) 523 return ret 524 } 525 func makeVarcharList(start, end, step string) []*plan.Expr { 526 ret := make([]*plan.Expr, 3) 527 ret[0] = makeVarcharExpr(start) 528 ret[1] = makeVarcharExpr(end) 529 ret[2] = makeVarcharExpr(step) 530 return ret 531 } 532 533 func makeInt64Expr(val int64) *plan.Expr { 534 return &plan.Expr{ 535 Typ: &plan.Type{ 536 Id: int32(types.T_int64), 537 }, 538 Expr: &plan2.Expr_C{ 539 C: &plan.Const{ 540 Value: &plan2.Const_I64Val{ 541 I64Val: val, 542 }, 543 }, 544 }, 545 } 546 } 547 func makeVarcharExpr(val string) *plan.Expr { 548 return &plan.Expr{ 549 Typ: &plan.Type{ 550 Id: int32(types.T_varchar), 551 }, 552 Expr: &plan2.Expr_C{ 553 C: &plan.Const{ 554 Value: &plan2.Const_Sval{ 555 Sval: val, 556 }, 557 }, 558 }, 559 } 560 } 561 562 func makeDatetimeExpr(s string, p int32) *plan.Expr { 563 dt, _ := types.ParseDatetime(s, p) 564 return &plan.Expr{ 565 Typ: &plan.Type{ 566 Id: int32(types.T_datetime), 567 Precision: p, 568 }, 569 Expr: &plan2.Expr_C{ 570 C: &plan.Const{ 571 Value: &plan2.Const_Datetimeval{ 572 Datetimeval: int64(dt), 573 }, 574 }, 575 }, 576 } 577 }