github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/index/dolt_index_test.go (about) 1 // Copyright 2020 Dolthub, 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 // 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 index_test 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 "io" 22 "sort" 23 "strings" 24 "testing" 25 "time" 26 27 "github.com/dolthub/go-mysql-server/sql" 28 "github.com/dolthub/go-mysql-server/sql/types" 29 "github.com/shopspring/decimal" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 33 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 34 "github.com/dolthub/dolt/go/libraries/doltcore/dtestutils" 35 "github.com/dolthub/dolt/go/libraries/doltcore/sqle" 36 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/index" 37 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/sqlutil" 38 ) 39 40 type indexComp int 41 42 const ( 43 indexComp_Eq = iota 44 indexComp_NEq 45 indexComp_Gt 46 indexComp_GtE 47 indexComp_Lt 48 indexComp_LtE 49 ) 50 51 type doltIndexTestCase struct { 52 indexName string 53 keys []interface{} 54 expectedRows []sql.Row 55 } 56 57 type doltIndexBetweenTestCase struct { 58 indexName string 59 greaterThanOrEqual []interface{} 60 lessThanOrEqual []interface{} 61 expectedRows []sql.Row 62 } 63 64 var typesTests = []struct { 65 indexName string 66 belowfirstValue []interface{} 67 firstValue []interface{} 68 secondValue []interface{} 69 thirdValue []interface{} 70 fourthValue []interface{} 71 fifthValue []interface{} 72 abovefifthValue []interface{} 73 }{ 74 { 75 "types:primaryKey", 76 []interface{}{-4}, 77 []interface{}{-3}, 78 []interface{}{-1}, 79 []interface{}{0}, 80 []interface{}{1}, 81 []interface{}{3}, 82 []interface{}{4}, 83 }, 84 { 85 "types:idx_bit", 86 []interface{}{0}, 87 []interface{}{1}, 88 []interface{}{2}, 89 []interface{}{3}, 90 []interface{}{4}, 91 []interface{}{5}, 92 []interface{}{6}, 93 }, 94 { 95 "types:idx_datetime", 96 []interface{}{"2020-05-14 11:59:59"}, 97 []interface{}{"2020-05-14 12:00:00"}, 98 []interface{}{"2020-05-14 12:00:01"}, 99 []interface{}{"2020-05-14 12:00:02"}, 100 []interface{}{"2020-05-14 12:00:03"}, 101 []interface{}{"2020-05-14 12:00:04"}, 102 []interface{}{"2020-05-14 12:00:05"}, 103 }, 104 { 105 "types:idx_decimal", 106 []interface{}{"-4"}, 107 []interface{}{"-3.3"}, 108 []interface{}{"-1.1"}, 109 []interface{}{0}, 110 []interface{}{"1.1"}, 111 []interface{}{"3.3"}, 112 []interface{}{4}, 113 }, 114 { 115 "types:idx_enum", 116 []interface{}{"_"}, 117 []interface{}{"a"}, 118 []interface{}{"b"}, 119 []interface{}{"c"}, 120 []interface{}{"d"}, 121 []interface{}{"e"}, 122 []interface{}{"."}, 123 }, 124 { 125 "types:idx_double", 126 []interface{}{-4}, 127 []interface{}{-3.3}, 128 []interface{}{-1.1}, 129 []interface{}{0}, 130 []interface{}{1.1}, 131 []interface{}{3.3}, 132 []interface{}{4}, 133 }, 134 { 135 "types:idx_set", 136 []interface{}{""}, 137 []interface{}{"a"}, 138 []interface{}{"a,b"}, 139 []interface{}{"c"}, 140 []interface{}{"a,c"}, 141 []interface{}{"b,c"}, 142 []interface{}{"a,b,c"}, 143 }, 144 { 145 "types:idx_time", 146 []interface{}{"-00:04:04"}, 147 []interface{}{"-00:03:03"}, 148 []interface{}{"-00:01:01"}, 149 []interface{}{"00:00:00"}, 150 []interface{}{"00:01:01"}, 151 []interface{}{"00:03:03"}, 152 []interface{}{"00:04:04"}, 153 }, 154 { 155 "types:idx_varchar", 156 []interface{}{"_"}, 157 []interface{}{"a"}, 158 []interface{}{"b"}, 159 []interface{}{"c"}, 160 []interface{}{"d"}, 161 []interface{}{"e"}, 162 []interface{}{"f"}, 163 }, 164 { 165 "types:idx_year", 166 []interface{}{1975}, 167 []interface{}{1980}, 168 []interface{}{1990}, 169 []interface{}{2000}, 170 []interface{}{2010}, 171 []interface{}{2020}, 172 []interface{}{2025}, 173 }, 174 } 175 176 var ( 177 typesTableRow1 = sql.Row{int32(-3), uint64(1), mustTime("2020-05-14 12:00:00"), mustDecimal("-3.30000"), uint16(2), -3.3, uint64(1), types.Timespan(-183000000), "a", int16(1980)} 178 typesTableRow2 = sql.Row{int32(-1), uint64(2), mustTime("2020-05-14 12:00:01"), mustDecimal("-1.10000"), uint16(3), -1.1, uint64(3), types.Timespan(-61000000), "b", int16(1990)} 179 typesTableRow3 = sql.Row{int32(0), uint64(3), mustTime("2020-05-14 12:00:02"), mustDecimal("0.00000"), uint16(4), 0.0, uint64(4), types.Timespan(0), "c", int16(2000)} 180 typesTableRow4 = sql.Row{int32(1), uint64(4), mustTime("2020-05-14 12:00:03"), mustDecimal("1.10000"), uint16(5), 1.1, uint64(5), types.Timespan(61000000), "d", int16(2010)} 181 typesTableRow5 = sql.Row{int32(3), uint64(5), mustTime("2020-05-14 12:00:04"), mustDecimal("3.30000"), uint16(6), 3.3, uint64(6), types.Timespan(183000000), "e", int16(2020)} 182 ) 183 184 func TestDoltIndexEqual(t *testing.T) { 185 root, indexMap := doltIndexSetup(t) 186 187 tests := []doltIndexTestCase{ 188 { 189 "onepk:primaryKey", 190 []interface{}{1}, 191 []sql.Row{{1, 1, 1}}, 192 }, 193 { 194 "onepk:primaryKey", 195 []interface{}{3}, 196 []sql.Row{{3, 3, 3}}, 197 }, 198 { 199 "onepk:primaryKey", 200 []interface{}{0}, 201 nil, 202 }, 203 { 204 "onepk:primaryKey", 205 []interface{}{5}, 206 nil, 207 }, 208 { 209 "onepk:idx_v1", 210 []interface{}{1}, 211 []sql.Row{{1, 1, 1}, {2, 1, 2}}, 212 }, 213 { 214 "onepk:idx_v1", 215 []interface{}{3}, 216 []sql.Row{{3, 3, 3}}, 217 }, 218 { 219 "twopk:primaryKey", 220 []interface{}{1, 1}, 221 []sql.Row{{1, 1, 3, 3}}, 222 }, 223 { 224 "twopk:primaryKey", 225 []interface{}{2, 0}, 226 nil, 227 }, 228 { 229 "twopk:primaryKey", 230 []interface{}{2, 1}, 231 []sql.Row{{2, 1, 4, 4}}, 232 }, 233 { 234 "twopk:idx_v2v1", 235 []interface{}{3, 4}, 236 []sql.Row{{2, 2, 4, 3}}, 237 }, 238 { 239 "twopk:idx_v2v1", 240 []interface{}{4, 3}, 241 []sql.Row{{1, 2, 3, 4}}, 242 }, 243 //{ 244 // "twopk:idx_v2v1_PARTIAL_1", 245 // []interface{}{3}, 246 // []sql.Row{{1, 1, 3, 3}, {2, 2, 4, 3}}, 247 //}, 248 //{ 249 // "twopk:idx_v2v1_PARTIAL_1", 250 // []interface{}{4}, 251 // []sql.Row{{1, 2, 3, 4}, {2, 1, 4, 4}}, 252 //}, 253 } 254 255 for _, typesTest := range typesTests { 256 tests = append(tests, doltIndexTestCase{ 257 typesTest.indexName, 258 typesTest.belowfirstValue, 259 nil, 260 }, doltIndexTestCase{ 261 typesTest.indexName, 262 typesTest.firstValue, 263 []sql.Row{ 264 typesTableRow1, 265 }, 266 }, doltIndexTestCase{ 267 typesTest.indexName, 268 typesTest.secondValue, 269 []sql.Row{ 270 typesTableRow2, 271 }, 272 }, doltIndexTestCase{ 273 typesTest.indexName, 274 typesTest.thirdValue, 275 []sql.Row{ 276 typesTableRow3, 277 }, 278 }, doltIndexTestCase{ 279 typesTest.indexName, 280 typesTest.fourthValue, 281 []sql.Row{ 282 typesTableRow4, 283 }, 284 }, doltIndexTestCase{ 285 typesTest.indexName, 286 typesTest.fifthValue, 287 []sql.Row{ 288 typesTableRow5, 289 }, 290 }, doltIndexTestCase{ 291 typesTest.indexName, 292 typesTest.abovefifthValue, 293 nil, 294 }) 295 } 296 297 for _, test := range tests { 298 t.Run(fmt.Sprintf("%s|%v", test.indexName, test.keys), func(t *testing.T) { 299 ctx := sql.NewEmptyContext() 300 idx, ok := indexMap[test.indexName] 301 require.True(t, ok) 302 testDoltIndex(t, ctx, root, test.keys, test.expectedRows, idx, indexComp_Eq) 303 }) 304 } 305 } 306 307 func TestDoltIndexGreaterThan(t *testing.T) { 308 root, indexMap := doltIndexSetup(t) 309 310 tests := []struct { 311 indexName string 312 keys []interface{} 313 expectedRows []sql.Row 314 }{ 315 { 316 "onepk:primaryKey", 317 []interface{}{1}, 318 []sql.Row{{2, 1, 2}, {3, 3, 3}, {4, 4, 3}}, 319 }, 320 { 321 "onepk:primaryKey", 322 []interface{}{3}, 323 []sql.Row{{4, 4, 3}}, 324 }, 325 { 326 "onepk:primaryKey", 327 []interface{}{4}, 328 nil, 329 }, 330 { 331 "onepk:idx_v1", 332 []interface{}{1}, 333 []sql.Row{{3, 3, 3}, {4, 4, 3}}, 334 }, 335 { 336 "onepk:idx_v1", 337 []interface{}{3}, 338 []sql.Row{{4, 4, 3}}, 339 }, 340 { 341 "onepk:idx_v1", 342 []interface{}{4}, 343 nil, 344 }, 345 { 346 "twopk:primaryKey", 347 []interface{}{1, 1}, 348 []sql.Row{{2, 2, 4, 3}}, 349 }, 350 { 351 "twopk:primaryKey", 352 []interface{}{2, 1}, 353 nil, 354 }, 355 { 356 "twopk:idx_v2v1", 357 []interface{}{2, 3}, 358 []sql.Row{{2, 1, 4, 4}, {2, 2, 4, 3}}, 359 }, 360 { 361 "twopk:idx_v2v1", 362 []interface{}{3, 3}, 363 []sql.Row{{2, 1, 4, 4}}, 364 }, 365 { 366 "twopk:idx_v2v1", 367 []interface{}{3, 4}, 368 nil, 369 }, 370 { 371 "twopk:idx_v2v1", 372 []interface{}{4, 3}, 373 nil, 374 }, 375 //{ 376 // "twopk:idx_v2v1_PARTIAL_1", 377 // []interface{}{3}, 378 // []sql.Row{{1, 2, 3, 4}, {2, 1, 4, 4}}, 379 //}, 380 //{ 381 // "twopk:idx_v2v1_PARTIAL_1", 382 // []interface{}{4}, 383 // nil, 384 //}, 385 } 386 387 for _, typesTest := range typesTests { 388 tests = append(tests, doltIndexTestCase{ 389 typesTest.indexName, 390 typesTest.belowfirstValue, 391 []sql.Row{ 392 typesTableRow1, 393 typesTableRow2, 394 typesTableRow3, 395 typesTableRow4, 396 typesTableRow5, 397 }, 398 }, doltIndexTestCase{ 399 typesTest.indexName, 400 typesTest.firstValue, 401 []sql.Row{ 402 typesTableRow2, 403 typesTableRow3, 404 typesTableRow4, 405 typesTableRow5, 406 }, 407 }, doltIndexTestCase{ 408 typesTest.indexName, 409 typesTest.secondValue, 410 []sql.Row{ 411 typesTableRow3, 412 typesTableRow4, 413 typesTableRow5, 414 }, 415 }, doltIndexTestCase{ 416 typesTest.indexName, 417 typesTest.thirdValue, 418 []sql.Row{ 419 typesTableRow4, 420 typesTableRow5, 421 }, 422 }, doltIndexTestCase{ 423 typesTest.indexName, 424 typesTest.fourthValue, 425 []sql.Row{ 426 typesTableRow5, 427 }, 428 }, doltIndexTestCase{ 429 typesTest.indexName, 430 typesTest.fifthValue, 431 nil, 432 }, doltIndexTestCase{ 433 typesTest.indexName, 434 typesTest.abovefifthValue, 435 nil, 436 }) 437 } 438 439 for _, test := range tests { 440 t.Run(fmt.Sprintf("%s|%v", test.indexName, test.keys), func(t *testing.T) { 441 ctx := sql.NewEmptyContext() 442 index, ok := indexMap[test.indexName] 443 require.True(t, ok) 444 testDoltIndex(t, ctx, root, test.keys, test.expectedRows, index, indexComp_Gt) 445 }) 446 } 447 } 448 449 func TestDoltIndexGreaterThanOrEqual(t *testing.T) { 450 root, indexMap := doltIndexSetup(t) 451 452 tests := []struct { 453 indexName string 454 keys []interface{} 455 expectedRows []sql.Row 456 }{ 457 { 458 "onepk:primaryKey", 459 []interface{}{1}, 460 []sql.Row{{1, 1, 1}, {2, 1, 2}, {3, 3, 3}, {4, 4, 3}}, 461 }, 462 { 463 "onepk:primaryKey", 464 []interface{}{3}, 465 []sql.Row{{3, 3, 3}, {4, 4, 3}}, 466 }, 467 { 468 "onepk:primaryKey", 469 []interface{}{4}, 470 []sql.Row{{4, 4, 3}}, 471 }, 472 { 473 "onepk:idx_v1", 474 []interface{}{1}, 475 []sql.Row{{1, 1, 1}, {2, 1, 2}, {3, 3, 3}, {4, 4, 3}}, 476 }, 477 { 478 "onepk:idx_v1", 479 []interface{}{3}, 480 []sql.Row{{3, 3, 3}, {4, 4, 3}}, 481 }, 482 { 483 "onepk:idx_v1", 484 []interface{}{4}, 485 []sql.Row{{4, 4, 3}}, 486 }, 487 { 488 "twopk:primaryKey", 489 []interface{}{1, 1}, 490 []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}, {2, 1, 4, 4}, {2, 2, 4, 3}}, 491 }, 492 { 493 "twopk:primaryKey", 494 []interface{}{2, 1}, 495 []sql.Row{{2, 1, 4, 4}, {2, 2, 4, 3}}, 496 }, 497 { 498 "twopk:idx_v2v1", 499 []interface{}{3, 4}, 500 []sql.Row{{2, 1, 4, 4}, {2, 2, 4, 3}}, 501 }, 502 { 503 "twopk:idx_v2v1", 504 []interface{}{4, 3}, 505 []sql.Row{{1, 2, 3, 4}, {2, 1, 4, 4}}, 506 }, 507 //{ 508 // "twopk:idx_v2v1_PARTIAL_1", 509 // []interface{}{3}, 510 // []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}, {2, 1, 4, 4}, {2, 2, 4, 3}}, 511 //}, 512 //{ 513 // "twopk:idx_v2v1_PARTIAL_1", 514 // []interface{}{4}, 515 // []sql.Row{{1, 2, 3, 4}, {2, 1, 4, 4}}, 516 //}, 517 } 518 519 for _, typesTest := range typesTests { 520 tests = append(tests, doltIndexTestCase{ 521 typesTest.indexName, 522 typesTest.belowfirstValue, 523 []sql.Row{ 524 typesTableRow1, 525 typesTableRow2, 526 typesTableRow3, 527 typesTableRow4, 528 typesTableRow5, 529 }, 530 }, doltIndexTestCase{ 531 typesTest.indexName, 532 typesTest.firstValue, 533 []sql.Row{ 534 typesTableRow1, 535 typesTableRow2, 536 typesTableRow3, 537 typesTableRow4, 538 typesTableRow5, 539 }, 540 }, doltIndexTestCase{ 541 typesTest.indexName, 542 typesTest.secondValue, 543 []sql.Row{ 544 typesTableRow2, 545 typesTableRow3, 546 typesTableRow4, 547 typesTableRow5, 548 }, 549 }, doltIndexTestCase{ 550 typesTest.indexName, 551 typesTest.thirdValue, 552 []sql.Row{ 553 typesTableRow3, 554 typesTableRow4, 555 typesTableRow5, 556 }, 557 }, doltIndexTestCase{ 558 typesTest.indexName, 559 typesTest.fourthValue, 560 []sql.Row{ 561 typesTableRow4, 562 typesTableRow5, 563 }, 564 }, doltIndexTestCase{ 565 typesTest.indexName, 566 typesTest.fifthValue, 567 []sql.Row{ 568 typesTableRow5, 569 }, 570 }, doltIndexTestCase{ 571 typesTest.indexName, 572 typesTest.abovefifthValue, 573 nil, 574 }) 575 } 576 577 for _, test := range tests { 578 t.Run(fmt.Sprintf("%s|%v", test.indexName, test.keys), func(t *testing.T) { 579 ctx := sql.NewEmptyContext() 580 index, ok := indexMap[test.indexName] 581 require.True(t, ok) 582 testDoltIndex(t, ctx, root, test.keys, test.expectedRows, index, indexComp_GtE) 583 }) 584 } 585 } 586 587 func TestDoltIndexLessThan(t *testing.T) { 588 root, indexMap := doltIndexSetup(t) 589 590 tests := []struct { 591 indexName string 592 keys []interface{} 593 expectedRows []sql.Row 594 }{ 595 { 596 "onepk:primaryKey", 597 []interface{}{1}, 598 nil, 599 }, 600 { 601 "onepk:primaryKey", 602 []interface{}{3}, 603 []sql.Row{{2, 1, 2}, {1, 1, 1}}, 604 }, 605 { 606 "onepk:primaryKey", 607 []interface{}{4}, 608 []sql.Row{{3, 3, 3}, {2, 1, 2}, {1, 1, 1}}, 609 }, 610 { 611 "onepk:idx_v1", 612 []interface{}{1}, 613 nil, 614 }, 615 { 616 "onepk:idx_v1", 617 []interface{}{3}, 618 []sql.Row{{2, 1, 2}, {1, 1, 1}}, 619 }, 620 { 621 "onepk:idx_v1", 622 []interface{}{4}, 623 []sql.Row{{3, 3, 3}, {2, 1, 2}, {1, 1, 1}}, 624 }, 625 { 626 "twopk:primaryKey", 627 []interface{}{1, 1}, 628 nil, 629 }, 630 { 631 "twopk:primaryKey", 632 []interface{}{2, 1}, 633 nil, 634 }, 635 { 636 "twopk:primaryKey", 637 []interface{}{2, 2}, 638 []sql.Row{{1, 1, 3, 3}}, 639 }, 640 { 641 "twopk:primaryKey", 642 []interface{}{2, 3}, 643 []sql.Row{{1, 2, 3, 4}, {1, 1, 3, 3}}, 644 }, 645 { 646 "twopk:idx_v2v1", 647 []interface{}{3, 4}, 648 nil, 649 }, 650 { 651 "twopk:idx_v2v1", 652 []interface{}{4, 3}, 653 nil, 654 }, 655 { 656 "twopk:idx_v2v1", 657 []interface{}{4, 4}, 658 []sql.Row{{1, 1, 3, 3}}, 659 }, 660 //{ 661 // "twopk:idx_v2v1_PARTIAL_1", 662 // []interface{}{3}, 663 // nil, 664 //}, 665 //{ 666 // "twopk:idx_v2v1_PARTIAL_1", 667 // []interface{}{4}, 668 // []sql.Row{{2, 2, 4, 3}, {1, 1, 3, 3}}, 669 //}, 670 } 671 672 for _, typesTest := range typesTests { 673 tests = append(tests, doltIndexTestCase{ 674 typesTest.indexName, 675 typesTest.belowfirstValue, 676 nil, 677 }, doltIndexTestCase{ 678 typesTest.indexName, 679 typesTest.firstValue, 680 nil, 681 }, doltIndexTestCase{ 682 typesTest.indexName, 683 typesTest.secondValue, 684 []sql.Row{ 685 typesTableRow1, 686 }, 687 }, doltIndexTestCase{ 688 typesTest.indexName, 689 typesTest.thirdValue, 690 []sql.Row{ 691 typesTableRow2, 692 typesTableRow1, 693 }, 694 }, doltIndexTestCase{ 695 typesTest.indexName, 696 typesTest.fourthValue, 697 []sql.Row{ 698 typesTableRow3, 699 typesTableRow2, 700 typesTableRow1, 701 }, 702 }, doltIndexTestCase{ 703 typesTest.indexName, 704 typesTest.fifthValue, 705 []sql.Row{ 706 typesTableRow4, 707 typesTableRow3, 708 typesTableRow2, 709 typesTableRow1, 710 }, 711 }, doltIndexTestCase{ 712 typesTest.indexName, 713 typesTest.abovefifthValue, 714 []sql.Row{ 715 typesTableRow5, 716 typesTableRow4, 717 typesTableRow3, 718 typesTableRow2, 719 typesTableRow1, 720 }, 721 }) 722 } 723 724 for _, test := range tests { 725 t.Run(fmt.Sprintf("%s|%v", test.indexName, test.keys), func(t *testing.T) { 726 ctx := sql.NewEmptyContext() 727 index, ok := indexMap[test.indexName] 728 require.True(t, ok) 729 testDoltIndex(t, ctx, root, test.keys, test.expectedRows, index, indexComp_Lt) 730 }) 731 } 732 } 733 734 func TestDoltIndexLessThanOrEqual(t *testing.T) { 735 root, indexMap := doltIndexSetup(t) 736 737 tests := []struct { 738 indexName string 739 keys []interface{} 740 expectedRows []sql.Row 741 }{ 742 { 743 "onepk:primaryKey", 744 []interface{}{1}, 745 []sql.Row{{1, 1, 1}}, 746 }, 747 { 748 "onepk:primaryKey", 749 []interface{}{3}, 750 []sql.Row{{3, 3, 3}, {2, 1, 2}, {1, 1, 1}}, 751 }, 752 { 753 "onepk:primaryKey", 754 []interface{}{4}, 755 []sql.Row{{4, 4, 3}, {3, 3, 3}, {2, 1, 2}, {1, 1, 1}}, 756 }, 757 { 758 "onepk:idx_v1", 759 []interface{}{1}, 760 []sql.Row{{2, 1, 2}, {1, 1, 1}}, 761 }, 762 { 763 "onepk:idx_v1", 764 []interface{}{3}, 765 []sql.Row{{3, 3, 3}, {2, 1, 2}, {1, 1, 1}}, 766 }, 767 { 768 "onepk:idx_v1", 769 []interface{}{4}, 770 []sql.Row{{4, 4, 3}, {3, 3, 3}, {2, 1, 2}, {1, 1, 1}}, 771 }, 772 { 773 "twopk:primaryKey", 774 []interface{}{1, 1}, 775 []sql.Row{{1, 1, 3, 3}}, 776 }, 777 { 778 "twopk:primaryKey", 779 []interface{}{2, 1}, 780 []sql.Row{{2, 1, 4, 4}, {1, 1, 3, 3}}, 781 }, 782 { 783 "twopk:primaryKey", 784 []interface{}{2, 2}, 785 []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}, {2, 1, 4, 4}, {2, 2, 4, 3}}, 786 }, 787 { 788 "twopk:idx_v2v1", 789 []interface{}{3, 4}, 790 []sql.Row{{2, 2, 4, 3}, {1, 1, 3, 3}}, 791 }, 792 { 793 "twopk:idx_v2v1", 794 []interface{}{4, 3}, 795 []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}}, 796 }, 797 { 798 "twopk:idx_v2v1", 799 []interface{}{4, 4}, 800 []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}, {2, 1, 4, 4}, {2, 2, 4, 3}}, 801 }, 802 //{ 803 // "twopk:idx_v2v1_PARTIAL_1", 804 // []interface{}{3}, 805 // []sql.Row{{1, 1, 3, 3}, {2, 2, 4, 3}}, 806 //}, 807 //{ 808 // "twopk:idx_v2v1_PARTIAL_1", 809 // []interface{}{4}, 810 // []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}, {2, 1, 4, 4}, {2, 2, 4, 3}}, 811 //}, 812 } 813 814 for _, typesTest := range typesTests { 815 tests = append(tests, doltIndexTestCase{ 816 typesTest.indexName, 817 typesTest.belowfirstValue, 818 nil, 819 }, doltIndexTestCase{ 820 typesTest.indexName, 821 typesTest.firstValue, 822 []sql.Row{ 823 typesTableRow1, 824 }, 825 }, doltIndexTestCase{ 826 typesTest.indexName, 827 typesTest.secondValue, 828 []sql.Row{ 829 typesTableRow2, 830 typesTableRow1, 831 }, 832 }, doltIndexTestCase{ 833 typesTest.indexName, 834 typesTest.thirdValue, 835 []sql.Row{ 836 typesTableRow3, 837 typesTableRow2, 838 typesTableRow1, 839 }, 840 }, doltIndexTestCase{ 841 typesTest.indexName, 842 typesTest.fourthValue, 843 []sql.Row{ 844 typesTableRow4, 845 typesTableRow3, 846 typesTableRow2, 847 typesTableRow1, 848 }, 849 }, doltIndexTestCase{ 850 typesTest.indexName, 851 typesTest.fifthValue, 852 []sql.Row{ 853 typesTableRow5, 854 typesTableRow4, 855 typesTableRow3, 856 typesTableRow2, 857 typesTableRow1, 858 }, 859 }, doltIndexTestCase{ 860 typesTest.indexName, 861 typesTest.abovefifthValue, 862 []sql.Row{ 863 typesTableRow5, 864 typesTableRow4, 865 typesTableRow3, 866 typesTableRow2, 867 typesTableRow1, 868 }, 869 }) 870 } 871 872 for _, test := range tests { 873 t.Run(fmt.Sprintf("%s|%v", test.indexName, test.keys), func(t *testing.T) { 874 ctx := sql.NewEmptyContext() 875 index, ok := indexMap[test.indexName] 876 require.True(t, ok) 877 testDoltIndex(t, ctx, root, test.keys, test.expectedRows, index, indexComp_LtE) 878 }) 879 } 880 } 881 882 func TestDoltIndexBetween(t *testing.T) { 883 root, indexMap := doltIndexSetup(t) 884 885 tests := []doltIndexBetweenTestCase{ 886 { 887 "onepk:primaryKey", 888 []interface{}{1}, 889 []interface{}{2}, 890 []sql.Row{{1, 1, 1}, {2, 1, 2}}, 891 }, 892 { 893 "onepk:primaryKey", 894 []interface{}{3}, 895 []interface{}{3}, 896 []sql.Row{{3, 3, 3}}, 897 }, 898 { 899 "onepk:primaryKey", 900 []interface{}{4}, 901 []interface{}{6}, 902 []sql.Row{{4, 4, 3}}, 903 }, 904 { 905 "onepk:primaryKey", 906 []interface{}{0}, 907 []interface{}{10}, 908 []sql.Row{{1, 1, 1}, {2, 1, 2}, {3, 3, 3}, {4, 4, 3}}, 909 }, 910 { 911 "onepk:idx_v1", 912 []interface{}{1}, 913 []interface{}{2}, 914 []sql.Row{{1, 1, 1}, {2, 1, 2}}, 915 }, 916 { 917 "onepk:idx_v1", 918 []interface{}{2}, 919 []interface{}{4}, 920 []sql.Row{{3, 3, 3}, {4, 4, 3}}, 921 }, 922 { 923 "onepk:idx_v1", 924 []interface{}{1}, 925 []interface{}{4}, 926 []sql.Row{{1, 1, 1}, {2, 1, 2}, {3, 3, 3}, {4, 4, 3}}, 927 }, 928 { 929 "twopk:primaryKey", 930 []interface{}{1, 1}, 931 []interface{}{1, 1}, 932 []sql.Row{{1, 1, 3, 3}}, 933 }, 934 { 935 "twopk:primaryKey", 936 []interface{}{1, 1}, 937 []interface{}{2, 1}, 938 []sql.Row{{1, 1, 3, 3}, {2, 1, 4, 4}}, 939 }, 940 { 941 "twopk:primaryKey", 942 []interface{}{1, 1}, 943 []interface{}{2, 2}, 944 []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}, {2, 1, 4, 4}, {2, 2, 4, 3}}, 945 }, 946 { 947 "twopk:primaryKey", 948 []interface{}{1, 1}, 949 []interface{}{2, 5}, 950 []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}, {2, 1, 4, 4}, {2, 2, 4, 3}}, 951 }, 952 { 953 "twopk:idx_v2v1", 954 []interface{}{3, 3}, 955 []interface{}{3, 4}, 956 []sql.Row{{1, 1, 3, 3}, {2, 2, 4, 3}}, 957 }, 958 { 959 "twopk:idx_v2v1", 960 []interface{}{3, 4}, 961 []interface{}{4, 4}, 962 []sql.Row{{2, 1, 4, 4}, {2, 2, 4, 3}}, 963 }, 964 { 965 "twopk:idx_v2v1", 966 []interface{}{3, 3}, 967 []interface{}{4, 4}, 968 []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}, {2, 1, 4, 4}, {2, 2, 4, 3}}, 969 }, 970 //{ 971 // "twopk:idx_v2v1_PARTIAL_1", 972 // []interface{}{3}, 973 // []interface{}{3}, 974 // []sql.Row{{1, 1, 3, 3}, {2, 2, 4, 3}}, 975 //}, 976 //{ 977 // "twopk:idx_v2v1_PARTIAL_1", 978 // []interface{}{4}, 979 // []interface{}{4}, 980 // []sql.Row{{1, 2, 3, 4}, {2, 1, 4, 4}}, 981 //}, 982 //{ 983 // "twopk:idx_v2v1_PARTIAL_1", 984 // []interface{}{3}, 985 // []interface{}{4}, 986 // []sql.Row{{1, 1, 3, 3}, {1, 2, 3, 4}, {2, 1, 4, 4}, {2, 2, 4, 3}}, 987 //}, 988 } 989 990 for _, typesTest := range typesTests { 991 tests = append(tests, doltIndexBetweenTestCase{ 992 typesTest.indexName, 993 typesTest.belowfirstValue, 994 typesTest.belowfirstValue, 995 nil, 996 }, doltIndexBetweenTestCase{ 997 typesTest.indexName, 998 typesTest.belowfirstValue, 999 typesTest.firstValue, 1000 []sql.Row{ 1001 typesTableRow1, 1002 }, 1003 }, doltIndexBetweenTestCase{ 1004 typesTest.indexName, 1005 typesTest.belowfirstValue, 1006 typesTest.secondValue, 1007 []sql.Row{ 1008 typesTableRow1, 1009 typesTableRow2, 1010 }, 1011 }, doltIndexBetweenTestCase{ 1012 typesTest.indexName, 1013 typesTest.belowfirstValue, 1014 typesTest.thirdValue, 1015 []sql.Row{ 1016 typesTableRow1, 1017 typesTableRow2, 1018 typesTableRow3, 1019 }, 1020 }, doltIndexBetweenTestCase{ 1021 typesTest.indexName, 1022 typesTest.secondValue, 1023 typesTest.secondValue, 1024 []sql.Row{ 1025 typesTableRow2, 1026 }, 1027 }, doltIndexBetweenTestCase{ 1028 typesTest.indexName, 1029 typesTest.thirdValue, 1030 typesTest.fifthValue, 1031 []sql.Row{ 1032 typesTableRow3, 1033 typesTableRow4, 1034 typesTableRow5, 1035 }, 1036 }, doltIndexBetweenTestCase{ 1037 typesTest.indexName, 1038 typesTest.fifthValue, 1039 typesTest.abovefifthValue, 1040 []sql.Row{ 1041 typesTableRow5, 1042 }, 1043 }, doltIndexBetweenTestCase{ 1044 typesTest.indexName, 1045 typesTest.abovefifthValue, 1046 typesTest.abovefifthValue, 1047 nil, 1048 }) 1049 } 1050 1051 for _, test := range tests { 1052 t.Run(fmt.Sprintf("%s|%v%v", test.indexName, test.greaterThanOrEqual, test.lessThanOrEqual), func(t *testing.T) { 1053 ctx := sql.NewEmptyContext() 1054 1055 idx, ok := indexMap[test.indexName] 1056 require.True(t, ok) 1057 1058 expectedRows := convertSqlRowToInt64(test.expectedRows) 1059 1060 exprs := idx.Expressions() 1061 sqlIndex := sql.NewIndexBuilder(idx) 1062 for i := range test.greaterThanOrEqual { 1063 sqlIndex = sqlIndex.GreaterOrEqual(ctx, exprs[i], test.greaterThanOrEqual[i]).LessOrEqual(ctx, exprs[i], test.lessThanOrEqual[i]) 1064 } 1065 indexLookup, err := sqlIndex.Build(ctx) 1066 require.NoError(t, err) 1067 1068 pkSch, err := sqlutil.FromDoltSchema("", "fake_table", idx.Schema()) 1069 require.NoError(t, err) 1070 1071 dt, ok, err := root.GetTable(ctx, doltdb.TableName{Name: idx.Table()}) 1072 require.NoError(t, err) 1073 require.True(t, ok) 1074 1075 indexIter, err := index.RowIterForIndexLookup(ctx, NoCacheTableable{dt}, indexLookup, pkSch, nil) 1076 require.NoError(t, err) 1077 1078 var readRows []sql.Row 1079 var nextRow sql.Row 1080 for nextRow, err = indexIter.Next(ctx); err == nil; nextRow, err = indexIter.Next(ctx) { 1081 readRows = append(readRows, nextRow) 1082 } 1083 require.Equal(t, io.EOF, err) 1084 1085 requireUnorderedRowsEqual(t, pkSch.Schema, expectedRows, readRows) 1086 }) 1087 } 1088 } 1089 1090 type NoCacheTableable struct { 1091 dt *doltdb.Table 1092 } 1093 1094 func (t NoCacheTableable) DoltTable(ctx *sql.Context) (*doltdb.Table, error) { 1095 return t.dt, nil 1096 } 1097 1098 func (t NoCacheTableable) DataCacheKey(ctx *sql.Context) (doltdb.DataCacheKey, bool, error) { 1099 return doltdb.DataCacheKey{}, false, nil 1100 } 1101 1102 type rowSlice struct { 1103 rows []sql.Row 1104 sortErr error 1105 } 1106 1107 func (r *rowSlice) setSortErr(err error) { 1108 if err == nil || r.sortErr != nil { 1109 return 1110 } 1111 1112 r.sortErr = err 1113 } 1114 1115 func (r *rowSlice) Len() int { 1116 return len(r.rows) 1117 } 1118 1119 func (r *rowSlice) Less(i, j int) bool { 1120 r1 := r.rows[i] 1121 r2 := r.rows[j] 1122 1123 longerLen := len(r1) 1124 if len(r2) > longerLen { 1125 longerLen = len(r2) 1126 } 1127 1128 for pos := 0; pos < longerLen; pos++ { 1129 if pos == len(r1) { 1130 return true 1131 } 1132 1133 if pos == len(r2) { 1134 return false 1135 } 1136 1137 c1, c2 := r1[pos], r2[pos] 1138 1139 var cmp int 1140 var err error 1141 switch typedVal := c1.(type) { 1142 case int: 1143 cmp, err = signedCompare(int64(typedVal), c2) 1144 case int64: 1145 cmp, err = signedCompare(typedVal, c2) 1146 case int32: 1147 cmp, err = signedCompare(int64(typedVal), c2) 1148 case int16: 1149 cmp, err = signedCompare(int64(typedVal), c2) 1150 case int8: 1151 cmp, err = signedCompare(int64(typedVal), c2) 1152 1153 case uint: 1154 cmp, err = unsignedCompare(uint64(typedVal), c2) 1155 case uint64: 1156 cmp, err = unsignedCompare(typedVal, c2) 1157 case uint32: 1158 cmp, err = unsignedCompare(uint64(typedVal), c2) 1159 case uint16: 1160 cmp, err = unsignedCompare(uint64(typedVal), c2) 1161 case uint8: 1162 cmp, err = unsignedCompare(uint64(typedVal), c2) 1163 1164 case float64: 1165 cmp, err = floatCompare(float64(typedVal), c2) 1166 case float32: 1167 cmp, err = floatCompare(float64(typedVal), c2) 1168 1169 case string: 1170 cmp, err = stringCompare(typedVal, c2) 1171 1172 default: 1173 panic("not implemented please add") 1174 } 1175 1176 if err != nil { 1177 r.setSortErr(err) 1178 return false 1179 } 1180 1181 if cmp != 0 { 1182 return cmp < 0 1183 } 1184 } 1185 1186 // equal 1187 return false 1188 } 1189 1190 func (r *rowSlice) equals(other *rowSlice, sch sql.Schema) bool { 1191 if len(r.rows) != len(other.rows) { 1192 return false 1193 } 1194 for i := range r.rows { 1195 ok, err := r.rows[i].Equals(other.rows[i], sch) 1196 if err != nil || !ok { 1197 return false 1198 } 1199 } 1200 return true 1201 } 1202 1203 func signedCompare(n1 int64, c interface{}) (int, error) { 1204 var n2 int64 1205 switch typedVal := c.(type) { 1206 case int: 1207 n2 = int64(typedVal) 1208 case int64: 1209 n2 = typedVal 1210 case int32: 1211 n2 = int64(typedVal) 1212 case int16: 1213 n2 = int64(typedVal) 1214 case int8: 1215 n2 = int64(typedVal) 1216 default: 1217 return 0, errors.New("comparing rows with different schemas") 1218 } 1219 1220 return int(n1 - n2), nil 1221 } 1222 1223 func unsignedCompare(n1 uint64, c interface{}) (int, error) { 1224 var n2 uint64 1225 switch typedVal := c.(type) { 1226 case uint: 1227 n2 = uint64(typedVal) 1228 case uint64: 1229 n2 = typedVal 1230 case uint32: 1231 n2 = uint64(typedVal) 1232 case uint16: 1233 n2 = uint64(typedVal) 1234 case uint8: 1235 n2 = uint64(typedVal) 1236 default: 1237 return 0, errors.New("comparing rows with different schemas") 1238 } 1239 1240 if n1 == n2 { 1241 return 0, nil 1242 } else if n1 < n2 { 1243 return -1, nil 1244 } else { 1245 return 1, nil 1246 } 1247 } 1248 1249 func floatCompare(n1 float64, c interface{}) (int, error) { 1250 var n2 float64 1251 switch typedVal := c.(type) { 1252 case float32: 1253 n2 = float64(typedVal) 1254 case float64: 1255 n2 = typedVal 1256 default: 1257 return 0, errors.New("comparing rows with different schemas") 1258 } 1259 1260 if n1 == n2 { 1261 return 0, nil 1262 } else if n1 < n2 { 1263 return -1, nil 1264 } else { 1265 return 1, nil 1266 } 1267 } 1268 1269 func stringCompare(s1 string, c interface{}) (int, error) { 1270 s2, ok := c.(string) 1271 if !ok { 1272 return 0, errors.New("comparing rows with different schemas") 1273 } 1274 1275 return strings.Compare(s1, s2), nil 1276 } 1277 1278 func (r *rowSlice) Swap(i, j int) { 1279 r.rows[i], r.rows[j] = r.rows[j], r.rows[i] 1280 } 1281 1282 func requireUnorderedRowsEqual(t *testing.T, s sql.Schema, rows1, rows2 []sql.Row) { 1283 slice1 := &rowSlice{rows: rows1} 1284 sort.Stable(slice1) 1285 require.NoError(t, slice1.sortErr) 1286 1287 slice2 := &rowSlice{rows: rows2} 1288 sort.Stable(slice2) 1289 require.NoError(t, slice2.sortErr) 1290 1291 assert.True(t, slice1.equals(slice2, s)) 1292 } 1293 1294 func testDoltIndex(t *testing.T, ctx *sql.Context, root doltdb.RootValue, keys []interface{}, expectedRows []sql.Row, idx index.DoltIndex, cmp indexComp) { 1295 ctx = sql.NewEmptyContext() 1296 exprs := idx.Expressions() 1297 builder := sql.NewIndexBuilder(idx) 1298 for i, key := range keys { 1299 switch cmp { 1300 case indexComp_Eq: 1301 builder = builder.Equals(ctx, exprs[i], key) 1302 case indexComp_NEq: 1303 builder = builder.NotEquals(ctx, exprs[i], key) 1304 case indexComp_Gt: 1305 builder = builder.GreaterThan(ctx, exprs[i], key) 1306 case indexComp_GtE: 1307 builder = builder.GreaterOrEqual(ctx, exprs[i], key) 1308 case indexComp_Lt: 1309 builder = builder.LessThan(ctx, exprs[i], key) 1310 case indexComp_LtE: 1311 builder = builder.LessOrEqual(ctx, exprs[i], key) 1312 default: 1313 panic("should not be hit") 1314 } 1315 } 1316 indexLookup, err := builder.Build(ctx) 1317 require.NoError(t, err) 1318 1319 dt, ok, err := root.GetTable(ctx, doltdb.TableName{Name: idx.Table()}) 1320 require.NoError(t, err) 1321 require.True(t, ok) 1322 1323 pkSch, err := sqlutil.FromDoltSchema("", "fake_table", idx.Schema()) 1324 require.NoError(t, err) 1325 1326 indexIter, err := index.RowIterForIndexLookup(ctx, NoCacheTableable{dt}, indexLookup, pkSch, nil) 1327 require.NoError(t, err) 1328 1329 var readRows []sql.Row 1330 var nextRow sql.Row 1331 for nextRow, err = indexIter.Next(ctx); err == nil; nextRow, err = indexIter.Next(ctx) { 1332 readRows = append(readRows, nextRow) 1333 } 1334 require.Equal(t, io.EOF, err) 1335 1336 requireUnorderedRowsEqual(t, pkSch.Schema, convertSqlRowToInt64(expectedRows), readRows) 1337 } 1338 1339 func doltIndexSetup(t *testing.T) (doltdb.RootValue, map[string]index.DoltIndex) { 1340 ctx := context.Background() 1341 dEnv := dtestutils.CreateTestEnv() 1342 root, err := dEnv.WorkingRoot(ctx) 1343 if err != nil { 1344 panic(err) 1345 } 1346 root, err = sqle.ExecuteSql(dEnv, root, ` 1347 CREATE TABLE onepk ( 1348 pk1 BIGINT PRIMARY KEY, 1349 v1 BIGINT, 1350 v2 BIGINT 1351 ); 1352 CREATE TABLE twopk ( 1353 pk1 BIGINT, 1354 pk2 BIGINT, 1355 v1 BIGINT, 1356 v2 BIGINT, 1357 PRIMARY KEY (pk1,pk2) 1358 ); 1359 CREATE TABLE types ( 1360 pk1 MEDIUMINT PRIMARY KEY, 1361 v1 BIT(4), 1362 v2 DATETIME, 1363 v3 DECIMAL(10, 5), 1364 v4 ENUM('_', 'a', 'b', 'c', 'd', 'e', '.'), 1365 v5 DOUBLE, 1366 v6 SET('a', 'b', 'c'), 1367 v7 TIME, 1368 v8 VARCHAR(2), 1369 v9 YEAR 1370 ); 1371 CREATE INDEX idx_v1 ON onepk(v1); 1372 CREATE INDEX idx_v2v1 ON twopk(v2, v1); 1373 CREATE INDEX idx_bit ON types(v1); 1374 CREATE INDEX idx_datetime ON types(v2); 1375 CREATE INDEX idx_decimal ON types(v3); 1376 CREATE INDEX idx_enum ON types(v4); 1377 CREATE INDEX idx_double ON types(v5); 1378 CREATE INDEX idx_set ON types(v6); 1379 CREATE INDEX idx_time ON types(v7); 1380 CREATE INDEX idx_varchar ON types(v8); 1381 CREATE INDEX idx_year ON types(v9); 1382 INSERT INTO onepk VALUES (1, 1, 1), (2, 1, 2), (3, 3, 3), (4, 4, 3); 1383 INSERT INTO twopk VALUES (1, 1, 3, 3), (1, 2, 3, 4), (2, 1, 4, 4), (2, 2, 4, 3); 1384 INSERT INTO types VALUES (-3, 1, '2020-05-14 12:00:00', -3.3, 'a', -3.3, 'a', '-00:03:03', 'a', 1980); 1385 INSERT INTO types VALUES (3, 5, '2020-05-14 12:00:04', 3.3, 'e', 3.3, 'b,c', '00:03:03', 'e', 2020); 1386 INSERT INTO types VALUES (0, 3, '2020-05-14 12:00:02', 0.0, 'c', 0.0, 'c', '00:00:00', 'c', 2000); 1387 INSERT INTO types VALUES (-1, 2, '2020-05-14 12:00:01', -1.1, 'b', -1.1, 'a,b', '-00:01:01', 'b', 1990); 1388 INSERT INTO types VALUES (1, 4, '2020-05-14 12:00:03', 1.1, 'd', 1.1, 'a,c', '00:01:01', 'd', 2010); 1389 `) 1390 require.NoError(t, err) 1391 1392 indexMap := make(map[string]index.DoltIndex) 1393 1394 dbname := "dolt" 1395 for _, name := range []string{"onepk", "twopk", "types"} { 1396 tbl, ok, err := root.GetTable(ctx, doltdb.TableName{Name: name}) 1397 require.NoError(t, err) 1398 require.True(t, ok) 1399 1400 indexes, err := index.DoltIndexesFromTable(ctx, dbname, name, tbl) 1401 require.NoError(t, err) 1402 1403 pkName := name + ":" + "primaryKey" 1404 indexMap[pkName] = indexes[0].(index.DoltIndex) 1405 1406 for _, idx := range indexes[1:] { 1407 idxName := name + ":" + idx.ID() 1408 indexMap[idxName] = idx.(index.DoltIndex) 1409 } 1410 } 1411 1412 return root, indexMap 1413 } 1414 1415 func mustTime(timeString string) time.Time { 1416 t, err := time.Parse("2006-01-02 15:04:05", timeString) 1417 if err != nil { 1418 panic(err) 1419 } 1420 return t 1421 } 1422 1423 func mustDecimal(s string) decimal.Decimal { 1424 d, err := decimal.NewFromString(s) 1425 if err != nil { 1426 panic(err) 1427 } 1428 return d 1429 } 1430 1431 func convertSqlRowToInt64(sqlRows []sql.Row) []sql.Row { 1432 if sqlRows == nil { 1433 return nil 1434 } 1435 newSqlRows := make([]sql.Row, len(sqlRows)) 1436 for i, sqlRow := range sqlRows { 1437 newSqlRow := make(sql.Row, len(sqlRow)) 1438 for j := range sqlRow { 1439 switch v := sqlRow[j].(type) { 1440 case int: 1441 newSqlRow[j] = int64(v) 1442 case int8: 1443 newSqlRow[j] = int64(v) 1444 case int16: 1445 newSqlRow[j] = int64(v) 1446 case int32: 1447 newSqlRow[j] = int64(v) 1448 case int64: 1449 newSqlRow[j] = v 1450 case nil: 1451 newSqlRow[j] = nil 1452 default: 1453 return sqlRows 1454 } 1455 } 1456 newSqlRows[i] = newSqlRow 1457 } 1458 return newSqlRows 1459 } 1460 1461 func TestSplitNullsFromRange(t *testing.T) { 1462 t.Run("EmptyRange", func(t *testing.T) { 1463 r, err := index.SplitNullsFromRange(sql.Range{}) 1464 assert.NoError(t, err) 1465 assert.NotNil(t, r) 1466 assert.Len(t, r, 1) 1467 assert.Len(t, r[0], 0) 1468 }) 1469 1470 t.Run("ThreeColumnNoNullsRange", func(t *testing.T) { 1471 r := sql.Range{sql.LessThanRangeColumnExpr(10, types.Int8), sql.GreaterThanRangeColumnExpr(16, types.Int8), sql.NotNullRangeColumnExpr(types.Int8)} 1472 rs, err := index.SplitNullsFromRange(r) 1473 assert.NoError(t, err) 1474 assert.NotNil(t, rs) 1475 assert.Len(t, rs, 1) 1476 assert.Len(t, rs[0], 3) 1477 assert.Equal(t, r, rs[0]) 1478 }) 1479 1480 t.Run("LastColumnOnlyNull", func(t *testing.T) { 1481 r := sql.Range{sql.LessThanRangeColumnExpr(10, types.Int8), sql.GreaterThanRangeColumnExpr(16, types.Int8), sql.NullRangeColumnExpr(types.Int8)} 1482 rs, err := index.SplitNullsFromRange(r) 1483 assert.NoError(t, err) 1484 assert.NotNil(t, rs) 1485 assert.Len(t, rs, 1) 1486 assert.Len(t, rs[0], 3) 1487 assert.Equal(t, r, rs[0]) 1488 }) 1489 1490 t.Run("LastColumnAll", func(t *testing.T) { 1491 r := sql.Range{sql.LessThanRangeColumnExpr(10, types.Int8), sql.GreaterThanRangeColumnExpr(16, types.Int8), sql.AllRangeColumnExpr(types.Int8)} 1492 rs, err := index.SplitNullsFromRange(r) 1493 assert.NoError(t, err) 1494 assert.NotNil(t, rs) 1495 assert.Len(t, rs, 2) 1496 assert.Len(t, rs[0], 3) 1497 assert.Len(t, rs[1], 3) 1498 assert.Equal(t, r[:2], rs[0][:2]) 1499 assert.Equal(t, r[:2], rs[1][:2]) 1500 assert.Equal(t, sql.NullRangeColumnExpr(types.Int8), rs[0][2]) 1501 assert.Equal(t, sql.NotNullRangeColumnExpr(types.Int8), rs[1][2]) 1502 }) 1503 1504 t.Run("FirstColumnAll", func(t *testing.T) { 1505 r := sql.Range{sql.AllRangeColumnExpr(types.Int8), sql.LessThanRangeColumnExpr(10, types.Int8), sql.GreaterThanRangeColumnExpr(16, types.Int8)} 1506 rs, err := index.SplitNullsFromRange(r) 1507 assert.NoError(t, err) 1508 assert.NotNil(t, rs) 1509 assert.Len(t, rs, 2) 1510 assert.Len(t, rs[0], 3) 1511 assert.Len(t, rs[1], 3) 1512 assert.Equal(t, r[1:], rs[0][1:]) 1513 assert.Equal(t, r[1:], rs[1][1:]) 1514 assert.Equal(t, sql.NullRangeColumnExpr(types.Int8), rs[0][0]) 1515 assert.Equal(t, sql.NotNullRangeColumnExpr(types.Int8), rs[1][0]) 1516 }) 1517 1518 t.Run("AllColumnAll", func(t *testing.T) { 1519 r := sql.Range{sql.AllRangeColumnExpr(types.Int8), sql.AllRangeColumnExpr(types.Int8), sql.AllRangeColumnExpr(types.Int8)} 1520 rs, err := index.SplitNullsFromRange(r) 1521 assert.NoError(t, err) 1522 assert.NotNil(t, rs) 1523 assert.Len(t, rs, 8) 1524 }) 1525 }