github.com/matrixorigin/matrixone@v0.7.0/pkg/testutil/util_function.go (about) 1 // Copyright 2021 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 testutil 16 17 import ( 18 "fmt" 19 "github.com/matrixorigin/matrixone/pkg/common/mpool" 20 "github.com/matrixorigin/matrixone/pkg/container/nulls" 21 "github.com/matrixorigin/matrixone/pkg/container/types" 22 "github.com/matrixorigin/matrixone/pkg/container/vector" 23 "github.com/matrixorigin/matrixone/pkg/vm/process" 24 ) 25 26 type fEvalFn func(parameters []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int) error 27 28 type FunctionTestCase struct { 29 proc *process.Process 30 parameters []*vector.Vector 31 result vector.FunctionResultWrapper 32 expected FunctionTestResult 33 fn fEvalFn 34 fnLength int 35 } 36 37 // FunctionTestInput 38 // the values should fit to typ. 39 // for example: 40 // if typ is int64, the values should be []int64 41 // if your typ is string type (varchar or others), the values should be []string. 42 type FunctionTestInput struct { 43 typ types.Type 44 values any 45 nullList []bool 46 } 47 48 // FunctionTestResult 49 // the wanted should fit to typ. 50 // for example: 51 // if typ is int64, the wanted should be []int64 52 // if your typ is string type (varchar or others), the wanted should be []string. 53 type FunctionTestResult struct { 54 typ types.Type 55 wantErr bool 56 wanted any 57 nullList []bool 58 } 59 60 func NewFunctionTestInput(typ types.Type, values any, nullList []bool) FunctionTestInput { 61 return FunctionTestInput{ 62 typ: typ, 63 values: values, 64 nullList: nullList, 65 } 66 } 67 68 func NewFunctionTestResult(typ types.Type, wantErr bool, wanted any, nullList []bool) FunctionTestResult { 69 return FunctionTestResult{ 70 typ: typ, 71 wantErr: wantErr, 72 wanted: wanted, 73 nullList: nullList, 74 } 75 } 76 77 // NewFunctionTestCase generate a testcase for built-in function F. 78 // fn is the evaluate method of F. 79 func NewFunctionTestCase( 80 proc *process.Process, 81 inputs []FunctionTestInput, 82 wanted FunctionTestResult, 83 fn fEvalFn) FunctionTestCase { 84 f := FunctionTestCase{proc: proc} 85 mp := proc.Mp() 86 // allocate vector for function parameters 87 f.parameters = make([]*vector.Vector, len(inputs)) 88 for i := range f.parameters { 89 typ := inputs[i].typ 90 // generate the nulls. 91 var nsp *nulls.Nulls = nil 92 if len(inputs[i].nullList) != 0 { 93 nsp = nulls.NewWithSize(len(inputs[i].nullList)) 94 for j, b := range inputs[i].nullList { 95 if b { 96 nsp.Set(uint64(j)) 97 } 98 } 99 } 100 // new the vector. 101 f.parameters[i] = newVectorByType(proc.Mp(), typ, inputs[i].values, nsp) 102 } 103 // new the result 104 if len(f.parameters) == 0 { 105 f.result = vector.NewFunctionResultWrapper(wanted.typ, mp, false, 1) 106 f.fnLength = 1 107 } else { 108 f.result = vector.NewFunctionResultWrapper(wanted.typ, mp, false, f.parameters[0].Length()) 109 f.fnLength = f.parameters[0].Length() 110 } 111 f.expected = wanted 112 f.fn = fn 113 return f 114 } 115 116 // Run will run the function case and do the correctness check for result. 117 func (fc *FunctionTestCase) Run() (succeed bool, errInfo string) { 118 err := fc.fn(fc.parameters, fc.result, fc.proc, fc.fnLength) 119 if err != nil { 120 if fc.expected.wantErr { 121 return true, "" 122 } 123 return false, fmt.Sprintf("expected to run success, but get an error that '%s'", 124 err.Error()) 125 } 126 if fc.expected.wantErr { 127 return false, "expected to run failed, but run succeed with no error" 128 } 129 v := fc.result.GetResultVector() 130 // check the length 131 if fc.fnLength != v.Length() { 132 return false, fmt.Sprintf("expected %d rows but get %d rows", fc.fnLength, v.Length()) 133 } 134 // check type (it's stupid, haha 135 if v.Typ.Oid != fc.expected.typ.Oid { 136 return false, fmt.Sprintf("expected result type %s but get type %s", fc.expected.typ, 137 v.Typ) 138 } 139 // generate the expected nsp 140 var expectedNsp *nulls.Nulls = nil 141 if fc.expected.nullList != nil { 142 expectedNsp = nulls.NewWithSize(len(fc.expected.nullList)) 143 for i, b := range fc.expected.nullList { 144 if b { 145 expectedNsp.Np.Add(uint64(i)) 146 } 147 } 148 } 149 // check the value 150 col := fc.expected.wanted 151 vExpected := newVectorByType(fc.proc.Mp(), fc.expected.typ, col, expectedNsp) 152 var i uint64 153 switch v.Typ.Oid { 154 case types.T_bool: 155 r := vector.GenerateFunctionFixedTypeParameter[bool](v) 156 s := vector.GenerateFunctionFixedTypeParameter[bool](vExpected) 157 for i = 0; i < uint64(fc.fnLength); i++ { 158 want, null1 := s.GetValue(i) 159 get, null2 := r.GetValue(i) 160 if null1 { 161 if null2 { 162 continue 163 } else { 164 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 165 } 166 } 167 if want != get { 168 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 169 i+1, want, get) 170 } 171 } 172 case types.T_int8: 173 r := vector.GenerateFunctionFixedTypeParameter[int8](v) 174 s := vector.GenerateFunctionFixedTypeParameter[int8](vExpected) 175 for i = 0; i < uint64(fc.fnLength); i++ { 176 want, null1 := s.GetValue(i) 177 get, null2 := r.GetValue(i) 178 if null1 { 179 if null2 { 180 continue 181 } else { 182 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 183 } 184 } 185 if want != get { 186 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 187 i+1, want, get) 188 } 189 } 190 case types.T_int16: 191 r := vector.GenerateFunctionFixedTypeParameter[int16](v) 192 s := vector.GenerateFunctionFixedTypeParameter[int16](vExpected) 193 for i = 0; i < uint64(fc.fnLength); i++ { 194 want, null1 := s.GetValue(i) 195 get, null2 := r.GetValue(i) 196 if null1 { 197 if null2 { 198 continue 199 } else { 200 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 201 } 202 } 203 if want != get { 204 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 205 i+1, want, get) 206 } 207 } 208 case types.T_int32: 209 r := vector.GenerateFunctionFixedTypeParameter[int32](v) 210 s := vector.GenerateFunctionFixedTypeParameter[int32](vExpected) 211 for i = 0; i < uint64(fc.fnLength); i++ { 212 want, null1 := s.GetValue(i) 213 get, null2 := r.GetValue(i) 214 if null1 { 215 if null2 { 216 continue 217 } else { 218 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 219 } 220 } 221 if want != get { 222 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 223 i+1, want, get) 224 } 225 } 226 case types.T_int64: 227 r := vector.GenerateFunctionFixedTypeParameter[int64](v) 228 s := vector.GenerateFunctionFixedTypeParameter[int64](vExpected) 229 for i = 0; i < uint64(fc.fnLength); i++ { 230 want, null1 := s.GetValue(i) 231 get, null2 := r.GetValue(i) 232 if null1 { 233 if null2 { 234 continue 235 } else { 236 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 237 } 238 } 239 if want != get { 240 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 241 i+1, want, get) 242 } 243 } 244 case types.T_uint8: 245 r := vector.GenerateFunctionFixedTypeParameter[uint8](v) 246 s := vector.GenerateFunctionFixedTypeParameter[uint8](vExpected) 247 for i = 0; i < uint64(fc.fnLength); i++ { 248 want, null1 := s.GetValue(i) 249 get, null2 := r.GetValue(i) 250 if null1 { 251 if null2 { 252 continue 253 } else { 254 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 255 } 256 } 257 if want != get { 258 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 259 i+1, want, get) 260 } 261 } 262 case types.T_uint16: 263 r := vector.GenerateFunctionFixedTypeParameter[uint16](v) 264 s := vector.GenerateFunctionFixedTypeParameter[uint16](vExpected) 265 for i = 0; i < uint64(fc.fnLength); i++ { 266 want, null1 := s.GetValue(i) 267 get, null2 := r.GetValue(i) 268 if null1 { 269 if null2 { 270 continue 271 } else { 272 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 273 } 274 } 275 if want != get { 276 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 277 i+1, want, get) 278 } 279 } 280 case types.T_uint32: 281 r := vector.GenerateFunctionFixedTypeParameter[uint32](v) 282 s := vector.GenerateFunctionFixedTypeParameter[uint32](vExpected) 283 for i = 0; i < uint64(fc.fnLength); i++ { 284 want, null1 := s.GetValue(i) 285 get, null2 := r.GetValue(i) 286 if null1 { 287 if null2 { 288 continue 289 } else { 290 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 291 } 292 } 293 if want != get { 294 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 295 i+1, want, get) 296 } 297 } 298 case types.T_uint64: 299 r := vector.GenerateFunctionFixedTypeParameter[uint64](v) 300 s := vector.GenerateFunctionFixedTypeParameter[uint64](vExpected) 301 for i = 0; i < uint64(fc.fnLength); i++ { 302 want, null1 := s.GetValue(i) 303 get, null2 := r.GetValue(i) 304 if null1 { 305 if null2 { 306 continue 307 } else { 308 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 309 } 310 } 311 if want != get { 312 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 313 i+1, want, get) 314 } 315 } 316 case types.T_float32: 317 r := vector.GenerateFunctionFixedTypeParameter[float32](v) 318 s := vector.GenerateFunctionFixedTypeParameter[float32](vExpected) 319 for i = 0; i < uint64(fc.fnLength); i++ { 320 want, null1 := s.GetValue(i) 321 get, null2 := r.GetValue(i) 322 if null1 { 323 if null2 { 324 continue 325 } else { 326 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 327 } 328 } 329 if want != get { 330 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 331 i+1, want, get) 332 } 333 } 334 case types.T_float64: 335 r := vector.GenerateFunctionFixedTypeParameter[float64](v) 336 s := vector.GenerateFunctionFixedTypeParameter[float64](vExpected) 337 for i = 0; i < uint64(fc.fnLength); i++ { 338 want, null1 := s.GetValue(i) 339 get, null2 := r.GetValue(i) 340 if null1 { 341 if null2 { 342 continue 343 } else { 344 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 345 } 346 } 347 if want != get { 348 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 349 i+1, want, get) 350 } 351 } 352 case types.T_decimal64: 353 r := vector.GenerateFunctionFixedTypeParameter[types.Decimal64](v) 354 s := vector.GenerateFunctionFixedTypeParameter[types.Decimal64](vExpected) 355 for i = 0; i < uint64(fc.fnLength); i++ { 356 want, null1 := s.GetValue(i) 357 get, null2 := r.GetValue(i) 358 if null1 { 359 if null2 { 360 continue 361 } else { 362 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 363 } 364 } 365 if want != get { 366 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 367 i+1, want, get) 368 } 369 } 370 case types.T_decimal128: 371 r := vector.GenerateFunctionFixedTypeParameter[types.Decimal128](v) 372 s := vector.GenerateFunctionFixedTypeParameter[types.Decimal128](vExpected) 373 for i = 0; i < uint64(fc.fnLength); i++ { 374 want, null1 := s.GetValue(i) 375 get, null2 := r.GetValue(i) 376 if null1 { 377 if null2 { 378 continue 379 } else { 380 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 381 } 382 } 383 if want != get { 384 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 385 i+1, want, get) 386 } 387 } 388 case types.T_date: 389 r := vector.GenerateFunctionFixedTypeParameter[types.Date](v) 390 s := vector.GenerateFunctionFixedTypeParameter[types.Date](vExpected) 391 for i = 0; i < uint64(fc.fnLength); i++ { 392 want, null1 := s.GetValue(i) 393 get, null2 := r.GetValue(i) 394 if null1 { 395 if null2 { 396 continue 397 } else { 398 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 399 } 400 } 401 if want != get { 402 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 403 i+1, want, get) 404 } 405 } 406 case types.T_datetime: 407 r := vector.GenerateFunctionFixedTypeParameter[types.Datetime](v) 408 s := vector.GenerateFunctionFixedTypeParameter[types.Datetime](vExpected) 409 for i = 0; i < uint64(fc.fnLength); i++ { 410 want, null1 := s.GetValue(i) 411 get, null2 := r.GetValue(i) 412 if null1 { 413 if null2 { 414 continue 415 } else { 416 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 417 } 418 } 419 if want != get { 420 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 421 i+1, want, get) 422 } 423 } 424 case types.T_time: 425 r := vector.GenerateFunctionFixedTypeParameter[types.Time](v) 426 s := vector.GenerateFunctionFixedTypeParameter[types.Time](vExpected) 427 for i = 0; i < uint64(fc.fnLength); i++ { 428 want, null1 := s.GetValue(i) 429 get, null2 := r.GetValue(i) 430 if null1 { 431 if null2 { 432 continue 433 } else { 434 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 435 } 436 } 437 if want != get { 438 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 439 i+1, want, get) 440 } 441 } 442 case types.T_timestamp: 443 r := vector.GenerateFunctionFixedTypeParameter[types.Timestamp](v) 444 s := vector.GenerateFunctionFixedTypeParameter[types.Timestamp](vExpected) 445 for i = 0; i < uint64(fc.fnLength); i++ { 446 want, null1 := s.GetValue(i) 447 get, null2 := r.GetValue(i) 448 if null1 { 449 if null2 { 450 continue 451 } else { 452 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 453 } 454 } 455 if want != get { 456 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 457 i+1, want, get) 458 } 459 } 460 case types.T_char, types.T_varchar, types.T_blob, types.T_text: 461 r := vector.GenerateFunctionStrParameter(v) 462 s := vector.GenerateFunctionStrParameter(vExpected) 463 for i = 0; i < uint64(fc.fnLength); i++ { 464 want, null1 := s.GetStrValue(i) 465 get, null2 := r.GetStrValue(i) 466 if null1 { 467 if null2 { 468 continue 469 } else { 470 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 471 } 472 } 473 if string(want) != string(get) { 474 return false, fmt.Sprintf("the %dth row expected %s, but get %s", 475 i+1, string(want), string(get)) 476 } 477 } 478 case types.T_uuid: 479 r := vector.GenerateFunctionFixedTypeParameter[types.Uuid](v) 480 s := vector.GenerateFunctionFixedTypeParameter[types.Uuid](vExpected) 481 for i = 0; i < uint64(fc.fnLength); i++ { 482 want, null1 := s.GetValue(i) 483 get, null2 := r.GetValue(i) 484 if null1 { 485 if null2 { 486 continue 487 } else { 488 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 489 } 490 } 491 if want != get { 492 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 493 i+1, want, get) 494 } 495 } 496 case types.T_TS: 497 r := vector.GenerateFunctionFixedTypeParameter[types.TS](v) 498 s := vector.GenerateFunctionFixedTypeParameter[types.TS](vExpected) 499 for i = 0; i < uint64(fc.fnLength); i++ { 500 want, null1 := s.GetValue(i) 501 get, null2 := r.GetValue(i) 502 if null1 { 503 if null2 { 504 continue 505 } else { 506 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 507 } 508 } 509 if want != get { 510 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 511 i+1, want, get) 512 } 513 } 514 case types.T_Rowid: 515 r := vector.GenerateFunctionFixedTypeParameter[types.Rowid](v) 516 s := vector.GenerateFunctionFixedTypeParameter[types.Rowid](vExpected) 517 for i = 0; i < uint64(fc.fnLength); i++ { 518 want, null1 := s.GetValue(i) 519 get, null2 := r.GetValue(i) 520 if null1 { 521 if null2 { 522 continue 523 } else { 524 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 525 } 526 } 527 if want != get { 528 return false, fmt.Sprintf("the %dth row expected %v, but get %v", 529 i+1, want, get) 530 } 531 } 532 case types.T_json: 533 r := vector.GenerateFunctionStrParameter(v) 534 s := vector.GenerateFunctionStrParameter(vExpected) 535 for i = 0; i < uint64(fc.fnLength); i++ { 536 want, null1 := s.GetStrValue(i) 537 get, null2 := r.GetStrValue(i) 538 if null1 { 539 if null2 { 540 continue 541 } else { 542 return false, fmt.Sprintf("the %dth row expected NULL, but get not null", i+1) 543 } 544 } 545 if string(want) != string(get) { 546 return false, fmt.Sprintf("the %dth row expected %s, but get %s", 547 i+1, string(want), string(get)) 548 } 549 } 550 default: 551 panic(fmt.Sprintf("unsupported result type %s for function ut framework", v.Typ)) 552 } 553 return true, "" 554 } 555 556 // DebugRun will not run the compare logic for function result but return the result vector directly. 557 func (fc *FunctionTestCase) DebugRun() (*vector.Vector, error) { 558 err := fc.fn(fc.parameters, fc.result, fc.proc, fc.fnLength) 559 return fc.result.GetResultVector(), err 560 } 561 562 // BenchMarkRun will run the function case N times without correctness check for result. 563 func (fc *FunctionTestCase) BenchMarkRun() error { 564 num := 100 565 for num > 0 { 566 num-- 567 err := fc.fn(fc.parameters, fc.result, fc.proc, fc.fnLength) 568 // XXX maybe free is unnecessary. 569 fc.result.Free() 570 if err != nil { 571 return err 572 } 573 } 574 return nil 575 } 576 577 func newVectorByType( 578 mp *mpool.MPool, 579 typ types.Type, val any, nsp *nulls.Nulls) *vector.Vector { 580 switch typ.Oid { 581 case types.T_bool: 582 values := val.([]bool) 583 return vector.NewWithFixed[bool](typ, values, nsp, mp) 584 case types.T_int8: 585 values := val.([]int8) 586 return vector.NewWithFixed[int8](typ, values, nsp, mp) 587 case types.T_int16: 588 values := val.([]int16) 589 return vector.NewWithFixed[int16](typ, values, nsp, mp) 590 case types.T_int32: 591 values := val.([]int32) 592 return vector.NewWithFixed[int32](typ, values, nsp, mp) 593 case types.T_int64: 594 values := val.([]int64) 595 return vector.NewWithFixed[int64](typ, values, nsp, mp) 596 case types.T_uint8: 597 values := val.([]uint8) 598 return vector.NewWithFixed[uint8](typ, values, nsp, mp) 599 case types.T_uint16: 600 values := val.([]uint16) 601 return vector.NewWithFixed[uint16](typ, values, nsp, mp) 602 case types.T_uint32: 603 values := val.([]uint32) 604 return vector.NewWithFixed[uint32](typ, values, nsp, mp) 605 case types.T_uint64: 606 values := val.([]uint64) 607 return vector.NewWithFixed[uint64](typ, values, nsp, mp) 608 case types.T_float32: 609 values := val.([]float32) 610 return vector.NewWithFixed[float32](typ, values, nsp, mp) 611 case types.T_float64: 612 values := val.([]float64) 613 return vector.NewWithFixed[float64](typ, values, nsp, mp) 614 case types.T_decimal64: 615 values := val.([]types.Decimal64) 616 return vector.NewWithFixed[types.Decimal64](typ, values, nsp, mp) 617 case types.T_decimal128: 618 values := val.([]types.Decimal128) 619 return vector.NewWithFixed[types.Decimal128](typ, values, nsp, mp) 620 case types.T_date: 621 values := val.([]types.Date) 622 return vector.NewWithFixed[types.Date](typ, values, nsp, mp) 623 case types.T_datetime: 624 values := val.([]types.Datetime) 625 return vector.NewWithFixed[types.Datetime](typ, values, nsp, mp) 626 case types.T_time: 627 values := val.([]types.Time) 628 return vector.NewWithFixed[types.Time](typ, values, nsp, mp) 629 case types.T_timestamp: 630 values := val.([]types.Timestamp) 631 return vector.NewWithFixed[types.Timestamp](typ, values, nsp, mp) 632 case types.T_char, types.T_varchar, types.T_blob, types.T_text: 633 values := val.([]string) 634 return vector.NewWithStrings(typ, values, nsp, mp) 635 case types.T_uuid: 636 values := val.([]types.Uuid) 637 return vector.NewWithFixed[types.Uuid](typ, values, nsp, mp) 638 case types.T_TS: 639 values := val.([]types.TS) 640 return vector.NewWithFixed[types.TS](typ, values, nsp, mp) 641 case types.T_Rowid: 642 values := val.([]types.Rowid) 643 return vector.NewWithFixed[types.Rowid](typ, values, nsp, mp) 644 case types.T_json: 645 values := val.([]string) 646 return vector.NewWithStrings(typ, values, nsp, mp) 647 } 648 panic(fmt.Sprintf("function test framework do not support typ %s", typ)) 649 }