github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/partition_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 plan 16 17 import ( 18 "context" 19 "testing" 20 21 "github.com/matrixorigin/matrixone/pkg/container/types" 22 "github.com/matrixorigin/matrixone/pkg/pb/plan" 23 "github.com/matrixorigin/matrixone/pkg/sql/parsers" 24 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" 25 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" 26 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 27 "github.com/stretchr/testify/require" 28 ) 29 30 func TestSingleDDLPartition(t *testing.T) { 31 //sql := `CREATE TABLE k1 ( 32 // id INT NOT NULL PRIMARY KEY, 33 // name VARCHAR(20) 34 // ) 35 // PARTITION BY KEY() 36 // PARTITIONS 2;` 37 38 //sql := `CREATE TABLE k1 ( 39 // id INT NOT NULL, 40 // name VARCHAR(20), 41 // sal DOUBLE, 42 // PRIMARY KEY (id, name) 43 // ) 44 // PARTITION BY KEY() 45 // PARTITIONS 2;` 46 47 sql := `CREATE TABLE k1 ( 48 id INT NOT NULL, 49 name VARCHAR(20), 50 UNIQUE KEY (id) 51 ) 52 PARTITION BY KEY() 53 PARTITIONS 2;` 54 55 //sql := `CREATE TABLE quarterly_report_status ( 56 // report_id INT NOT NULL, 57 // report_status VARCHAR(20) NOT NULL, 58 // report_updated TIMESTAMP NOT NULL 59 // ) 60 // PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) ( 61 // PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ), 62 // PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ), 63 // PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ), 64 // PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ), 65 // PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ), 66 // PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ), 67 // PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ), 68 // PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ), 69 // PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ), 70 // PARTITION p9 VALUES LESS THAN (MAXVALUE) 71 // );` 72 73 mock := NewMockOptimizer(false) 74 logicPlan, err := buildSingleStmt(mock, t, sql) 75 if err != nil { 76 t.Fatalf("%+v", err) 77 } 78 outPutPlan(logicPlan, true, t) 79 } 80 81 func TestPartitionError(t *testing.T) { 82 sqls := []string{ 83 `create temporary table p_table_non(col1 int,col2 varchar(25))partition by key(col2)partitions 4;`, 84 } 85 86 mock := NewMockOptimizer(false) 87 for _, sql := range sqls { 88 _, err := buildSingleStmt(mock, t, sql) 89 t.Log(sql) 90 t.Log(err) 91 if err == nil { 92 t.Fatalf("%+v", err) 93 } 94 } 95 } 96 97 func TestPartitioningKeysUniqueKeys(t *testing.T) { 98 sqls := []string{ 99 `CREATE TABLE t1 ( 100 col1 INT NOT NULL, 101 col2 DATE NOT NULL, 102 col3 INT NOT NULL, 103 col4 INT NOT NULL, 104 UNIQUE KEY (col1, col2) 105 ) 106 PARTITION BY KEY() 107 PARTITIONS 4;`, 108 109 `CREATE TABLE t1 ( 110 col1 INT NOT NULL, 111 col2 DATE NOT NULL, 112 col3 INT NOT NULL, 113 col4 INT NOT NULL, 114 UNIQUE KEY (col1, col2, col3) 115 ) 116 PARTITION BY HASH(col3) 117 PARTITIONS 4;`, 118 119 `CREATE TABLE t2 ( 120 col1 INT NOT NULL, 121 col2 DATE NOT NULL, 122 col3 INT NOT NULL, 123 col4 INT NOT NULL, 124 UNIQUE KEY (col1, col3) 125 ) 126 PARTITION BY HASH(col1 + col3) 127 PARTITIONS 4;`, 128 129 `CREATE TABLE t1 ( 130 col1 INT NOT NULL, 131 col2 DATE NOT NULL, 132 col3 INT NOT NULL, 133 col4 INT NOT NULL, 134 UNIQUE KEY (col1, col2, col3) 135 ) 136 PARTITION BY KEY(col3) 137 PARTITIONS 4;`, 138 139 `CREATE TABLE t2 ( 140 col1 INT NOT NULL, 141 col2 DATE NOT NULL, 142 col3 INT NOT NULL, 143 col4 INT NOT NULL, 144 UNIQUE KEY (col1, col3) 145 ) 146 PARTITION BY KEY(col1,col3) 147 PARTITIONS 4;`, 148 149 `CREATE TABLE t3 ( 150 col1 INT NOT NULL, 151 col2 DATE NOT NULL, 152 col3 INT NOT NULL, 153 col4 INT NOT NULL, 154 UNIQUE KEY (col1, col2, col3), 155 UNIQUE KEY (col3) 156 ) 157 PARTITION BY HASH(col3) 158 PARTITIONS 4;`, 159 160 `CREATE TABLE t3 ( 161 col1 INT NOT NULL, 162 col2 DATE NOT NULL, 163 col3 INT NOT NULL, 164 col4 INT NOT NULL, 165 UNIQUE KEY (col1, col2, col3), 166 UNIQUE KEY (col3) 167 ) 168 PARTITION BY KEY(col3) 169 PARTITIONS 4;`, 170 171 `CREATE TABLE t4 ( 172 col1 INT NOT NULL, 173 col2 DATE NOT NULL, 174 col3 INT NOT NULL UNIQUE, 175 col4 INT NOT NULL 176 ) 177 PARTITION BY KEY(col3) 178 PARTITIONS 4;`, 179 } 180 181 mock := NewMockOptimizer(false) 182 for _, sql := range sqls { 183 t.Log(sql) 184 logicPlan, err := buildSingleStmt(mock, t, sql) 185 if err != nil { 186 t.Fatalf("%+v", err) 187 } 188 outPutPlan(logicPlan, true, t) 189 } 190 } 191 192 func TestPartitioningKeysUniqueKeysError(t *testing.T) { 193 sqls := []string{ 194 `CREATE TABLE t1 ( 195 col1 INT NOT NULL, 196 col2 DATE NOT NULL, 197 col3 INT NOT NULL, 198 col4 INT NOT NULL, 199 UNIQUE KEY (col1, col2) 200 ) 201 PARTITION BY HASH(col3) 202 PARTITIONS 4;`, 203 204 `CREATE TABLE t2 ( 205 col1 INT NOT NULL, 206 col2 DATE NOT NULL, 207 col3 INT NOT NULL, 208 col4 INT NOT NULL, 209 UNIQUE KEY (col1), 210 UNIQUE KEY (col3) 211 ) 212 PARTITION BY HASH(col1 + col3) 213 PARTITIONS 4;`, 214 215 `CREATE TABLE t1 ( 216 col1 INT UNIQUE NOT NULL, 217 col2 DATE NOT NULL, 218 col3 INT NOT NULL, 219 col4 INT NOT NULL 220 ) 221 PARTITION BY HASH(col3) 222 PARTITIONS 4;`, 223 224 `CREATE TABLE t2 ( 225 col1 INT NOT NULL, 226 col2 DATE NOT NULL, 227 col3 INT NOT NULL, 228 col4 INT NOT NULL, 229 UNIQUE KEY (col1), 230 UNIQUE KEY (col3) 231 ) 232 PARTITION BY KEY(col1,col3) 233 PARTITIONS 4;`, 234 235 `CREATE TABLE t3 ( 236 col1 INT NOT NULL, 237 col2 DATE NOT NULL, 238 col3 INT NOT NULL, 239 col4 INT NOT NULL, 240 UNIQUE KEY (col1, col2), 241 UNIQUE KEY (col3) 242 ) 243 PARTITION BY HASH(col1 + col3) 244 PARTITIONS 4;`, 245 246 `CREATE TABLE t3 ( 247 col1 INT NOT NULL, 248 col2 DATE NOT NULL, 249 col3 INT NOT NULL, 250 col4 INT NOT NULL, 251 UNIQUE KEY (col1, col2), 252 UNIQUE KEY (col3) 253 ) 254 PARTITION BY KEY(col1, col3) 255 PARTITIONS 4;`, 256 // should show error:Field in list of fields for partition function not found in table 257 `CREATE TABLE k1 ( 258 id INT NOT NULL, 259 name VARCHAR(20), 260 sal DOUBLE 261 ) 262 PARTITION BY KEY() 263 PARTITIONS 2;`, 264 265 `CREATE TABLE t6 ( 266 col1 INT NOT NULL, 267 col2 DATE NOT NULL, 268 col3 INT NOT NULL UNIQUE, 269 col4 INT NOT NULL 270 ) 271 PARTITION BY KEY(col1) 272 PARTITIONS 4;`, 273 274 `CREATE TABLE t7 ( 275 col1 INT NOT NULL, 276 col2 DATE NOT NULL, 277 col3 INT NOT NULL UNIQUE, 278 col4 INT NOT NULL 279 ) 280 PARTITION BY HASH(col4) 281 PARTITIONS 4;`, 282 } 283 284 mock := NewMockOptimizer(false) 285 for _, sql := range sqls { 286 _, err := buildSingleStmt(mock, t, sql) 287 t.Log(sql) 288 t.Log(err) 289 if err == nil { 290 t.Fatalf("%+v", err) 291 } 292 } 293 } 294 295 func TestPartitioningKeysPrimaryKeys(t *testing.T) { 296 sqls := []string{ 297 `CREATE TABLE t7 ( 298 col1 INT NOT NULL, 299 col2 DATE NOT NULL, 300 col3 INT NOT NULL, 301 col4 INT NOT NULL, 302 PRIMARY KEY(col1, col2) 303 ) 304 PARTITION BY HASH(col1 + YEAR(col2)) 305 PARTITIONS 4;`, 306 307 `CREATE TABLE t8 ( 308 col1 INT NOT NULL, 309 col2 DATE NOT NULL, 310 col3 INT NOT NULL, 311 col4 INT NOT NULL, 312 PRIMARY KEY(col1, col2, col4), 313 UNIQUE KEY(col2, col1) 314 ) 315 PARTITION BY HASH(col1 + YEAR(col2)) 316 PARTITIONS 4;`, 317 318 `CREATE TABLE t7 ( 319 col1 INT NOT NULL, 320 col2 DATE NOT NULL, 321 col3 INT NOT NULL, 322 col4 INT NOT NULL, 323 PRIMARY KEY(col1, col2) 324 ) 325 PARTITION BY KEY(col1,col2) 326 PARTITIONS 4;`, 327 328 `CREATE TABLE t8 ( 329 col1 INT NOT NULL, 330 col2 DATE NOT NULL, 331 col3 INT NOT NULL, 332 col4 INT NOT NULL, 333 PRIMARY KEY(col1, col2, col4), 334 UNIQUE KEY(col2, col1) 335 ) 336 PARTITION BY KEY(col1,col2) 337 PARTITIONS 4;`, 338 339 `CREATE TABLE k1 ( 340 id INT NOT NULL, 341 name VARCHAR(20), 342 sal DOUBLE, 343 PRIMARY KEY (id, name), 344 unique key (id) 345 ) 346 PARTITION BY KEY(id) 347 PARTITIONS 2;`, 348 } 349 350 mock := NewMockOptimizer(false) 351 for _, sql := range sqls { 352 t.Log(sql) 353 logicPlan, err := buildSingleStmt(mock, t, sql) 354 if err != nil { 355 t.Fatalf("%+v", err) 356 } 357 outPutPlan(logicPlan, true, t) 358 } 359 } 360 361 func TestPartitioningKeysPrimaryKeysError(t *testing.T) { 362 sqls := []string{ 363 `CREATE TABLE t5 ( 364 col1 INT NOT NULL, 365 col2 DATE NOT NULL, 366 col3 INT NOT NULL, 367 col4 INT NOT NULL, 368 PRIMARY KEY(col1, col2) 369 ) 370 PARTITION BY HASH(col3) 371 PARTITIONS 4;`, 372 373 `CREATE TABLE t6 ( 374 col1 INT NOT NULL, 375 col2 DATE NOT NULL, 376 col3 INT NOT NULL, 377 col4 INT NOT NULL, 378 PRIMARY KEY(col1, col3), 379 UNIQUE KEY(col2) 380 ) 381 PARTITION BY HASH( YEAR(col2) ) 382 PARTITIONS 4;`, 383 384 `CREATE TABLE t5 ( 385 col1 INT NOT NULL, 386 col2 DATE NOT NULL, 387 col3 INT NOT NULL, 388 col4 INT NOT NULL, 389 PRIMARY KEY(col1, col2) 390 ) 391 PARTITION BY KEY(col3) 392 PARTITIONS 4;`, 393 394 `CREATE TABLE t6 ( 395 col1 INT NOT NULL, 396 col2 DATE NOT NULL, 397 col3 INT NOT NULL, 398 col4 INT NOT NULL, 399 PRIMARY KEY(col1, col3), 400 UNIQUE KEY(col2) 401 ) 402 PARTITION BY KEY(col2) 403 PARTITIONS 4;`, 404 } 405 406 mock := NewMockOptimizer(false) 407 for _, sql := range sqls { 408 _, err := buildSingleStmt(mock, t, sql) 409 t.Log(sql) 410 t.Log(err) 411 if err == nil { 412 t.Fatalf("%+v", err) 413 } 414 } 415 } 416 417 // A UNIQUE INDEX must include all columns in the table's partitioning function 418 func TestPartitionKeysShouldShowError(t *testing.T) { 419 sqls := []string{ 420 `CREATE TABLE t4 ( 421 col1 INT NOT NULL, 422 col2 INT NOT NULL, 423 col3 INT NOT NULL, 424 col4 INT NOT NULL, 425 UNIQUE KEY (col1, col3), 426 UNIQUE KEY (col2, col4) 427 ) 428 PARTITION BY KEY(col1, col3) 429 PARTITIONS 2;`, 430 431 `CREATE TABLE t4 ( 432 col1 INT NOT NULL, 433 col2 INT NOT NULL, 434 col3 INT NOT NULL, 435 col4 INT NOT NULL, 436 UNIQUE KEY (col1, col3), 437 UNIQUE KEY (col2, col4) 438 ) 439 PARTITION BY HASH(col1 + col3) 440 PARTITIONS 2;`, 441 442 `CREATE TABLE t4 ( 443 col1 INT NOT NULL, 444 col2 INT NOT NULL, 445 col3 INT NOT NULL, 446 col4 INT NOT NULL, 447 UNIQUE KEY (col1, col3), 448 UNIQUE KEY (col2, col4) 449 ) 450 PARTITION BY RANGE (col1 + col3) ( 451 PARTITION p0 VALUES LESS THAN (6), 452 PARTITION p1 VALUES LESS THAN (11), 453 PARTITION p2 VALUES LESS THAN (16), 454 PARTITION p3 VALUES LESS THAN (21) 455 );`, 456 457 `CREATE TABLE t4 ( 458 col1 INT NOT NULL, 459 col2 INT NOT NULL, 460 col3 INT NOT NULL, 461 col4 INT NOT NULL, 462 UNIQUE KEY (col1, col3), 463 UNIQUE KEY (col2, col4) 464 ) 465 PARTITION BY RANGE COLUMNS(col1, col3) PARTITIONS 4 ( 466 PARTITION p0 VALUES LESS THAN (10,5), 467 PARTITION p1 VALUES LESS THAN (20,10), 468 PARTITION p2 VALUES LESS THAN (50,20), 469 PARTITION p3 VALUES LESS THAN (65,30) 470 );`, 471 472 `CREATE TABLE t4 ( 473 col1 INT NOT NULL, 474 col2 INT NOT NULL, 475 col3 INT NOT NULL, 476 col4 INT NOT NULL, 477 UNIQUE KEY (col1), 478 UNIQUE KEY (col2, col4) 479 ) 480 PARTITION BY LIST (col1) ( 481 PARTITION r0 VALUES IN (1, 5, 9, 13, 17, 21), 482 PARTITION r1 VALUES IN (2, 6, 10, 14, 18, 22), 483 PARTITION r2 VALUES IN (3, 7, 11, 15, 19, 23), 484 PARTITION r3 VALUES IN (4, 8, 12, 16, 20, 24) 485 );`, 486 487 `CREATE TABLE t4 ( 488 col1 INT NOT NULL, 489 col2 INT NOT NULL, 490 col3 INT NOT NULL, 491 col4 INT NOT NULL, 492 UNIQUE KEY (col1, col3), 493 UNIQUE KEY (col2, col4) 494 ) 495 PARTITION BY LIST COLUMNS(col1, col3) ( 496 PARTITION p0 VALUES IN( (0,0), (NULL,NULL) ), 497 PARTITION p1 VALUES IN( (0,1), (0,2), (0,3), (1,1), (1,2) ), 498 PARTITION p2 VALUES IN( (1,0), (2,0), (2,1), (3,0), (3,1) ), 499 PARTITION p3 VALUES IN( (1,3), (2,2), (2,3), (3,2), (3,3) ) 500 );`, 501 } 502 mock := NewMockOptimizer(false) 503 for _, sql := range sqls { 504 _, err := buildSingleStmt(mock, t, sql) 505 t.Log(sql) 506 t.Log(err) 507 if err == nil { 508 t.Fatalf("%+v", err) 509 } 510 } 511 } 512 513 func buildSingleStmt(opt Optimizer, t *testing.T, sql string) (*Plan, error) { 514 statements, err := mysql.Parse(opt.CurrentContext().GetContext(), sql, 1, 0) 515 if err != nil { 516 return nil, err 517 } 518 // this sql always return single statement 519 context := opt.CurrentContext() 520 plan, err := BuildPlan(context, statements[0], false) 521 if plan != nil { 522 testDeepCopy(plan) 523 } 524 return plan, err 525 } 526 527 func Test_checkUniqueKeyIncludePartKey(t *testing.T) { 528 partKeys := map[string]int{ 529 "a": 0, 530 "b": 0, 531 "c": 0, 532 } 533 534 partKeys2 := map[string]int{ 535 "a": 0, 536 "b": 0, 537 "e": 0, 538 } 539 540 uniqueKeys := map[string]int{ 541 "a": 0, 542 "b": 0, 543 "c": 0, 544 "d": 0, 545 } 546 547 r1 := checkUniqueKeyIncludePartKey(partKeys, uniqueKeys) 548 require.True(t, r1) 549 r2 := checkUniqueKeyIncludePartKey(partKeys2, uniqueKeys) 550 require.False(t, r2) 551 552 r3 := findColumnInIndexCols("a", uniqueKeys) 553 require.True(t, r3) 554 555 r4 := findColumnInIndexCols("e", uniqueKeys) 556 require.False(t, r4) 557 558 x := make(map[string]int) 559 r5 := findColumnInIndexCols("e", x) 560 require.False(t, r5) 561 562 x["e"] = 0 563 r6 := findColumnInIndexCols("e", x) 564 require.True(t, r6) 565 } 566 567 func mockPartitionBinder(tableDef *plan.TableDef) (*PartitionBinder, error) { 568 mock := NewMockOptimizer(false) 569 builder := NewQueryBuilder(plan.Query_SELECT, mock.CurrentContext(), false) 570 bindContext := NewBindContext(builder, nil) 571 nodeID := builder.appendNode(&plan.Node{ 572 NodeType: plan.Node_TABLE_SCAN, 573 Stats: nil, 574 ObjRef: nil, 575 TableDef: tableDef, 576 BindingTags: []int32{builder.genNewTag()}, 577 }, bindContext) 578 579 err := builder.addBinding(nodeID, tree.AliasClause{}, bindContext) 580 if err != nil { 581 return nil, err 582 } 583 return NewPartitionBinder(builder, bindContext), err 584 } 585 586 func mockExpr(t *testing.T, s string) (tree.Expr, error) { 587 selStr := "select " + s 588 one, err := parsers.ParseOne(context.TODO(), dialect.MYSQL, selStr, 1, 0) 589 require.Nil(t, err) 590 return one.(*tree.Select).Select.(*tree.SelectClause).Exprs[0].Expr, err 591 } 592 593 func Test_checkPartitionKeys(t *testing.T) { 594 addCol := func(tableDef *TableDef, col *ColDef) { 595 tableDef.Cols = append(tableDef.Cols, col) 596 } 597 598 /* 599 table test: 600 col1 int32 pk 601 col2 int32 602 */ 603 tableDef := &plan.TableDef{ 604 Name: "test", 605 Pkey: &plan.PrimaryKeyDef{ 606 Names: []string{"col1"}, 607 }, 608 } 609 610 addCol(tableDef, &ColDef{ 611 Name: "col1", 612 Typ: plan.Type{ 613 Id: int32(types.T_int8), 614 }, 615 }) 616 addCol(tableDef, &ColDef{ 617 Name: "col2", 618 Typ: plan.Type{ 619 Id: int32(types.T_int8), 620 }, 621 }) 622 623 /* 624 table test2: 625 col1 int32 pk 626 col2 int32 pk 627 col3 int32 628 629 */ 630 tableDef2 := &plan.TableDef{ 631 Name: "test2", 632 Pkey: &plan.PrimaryKeyDef{ 633 Names: []string{"col1", "col2"}, 634 }, 635 } 636 637 addCol(tableDef2, &ColDef{ 638 Name: "col1", 639 Typ: plan.Type{ 640 Id: int32(types.T_int8), 641 }, 642 }) 643 addCol(tableDef2, &ColDef{ 644 Name: "col2", 645 Typ: plan.Type{ 646 Id: int32(types.T_int8), 647 }, 648 }) 649 addCol(tableDef2, &ColDef{ 650 Name: "col3", 651 Typ: plan.Type{ 652 Id: int32(types.T_int8), 653 }, 654 }) 655 656 addIndex := func(tableDef *TableDef, index string, names ...string) { 657 tableDef.Indexes = append(tableDef.Indexes, &IndexDef{ 658 Unique: true, 659 Parts: names, 660 }) 661 } 662 663 addIndex(tableDef2, "index1", "col1", "col2") 664 665 { 666 //partition keys [col1,col2] error 667 pb, err := mockPartitionBinder(tableDef) 668 require.Nil(t, err) 669 670 astExpr, err := mockExpr(t, "col1+1+col2") 671 require.Nil(t, err) 672 673 expr, err := pb.BindExpr(astExpr, 0, true) 674 require.Nil(t, err) 675 676 partDef := &PartitionByDef{} 677 partDef.PartitionExpr = &plan.PartitionExpr{ 678 Expr: expr, 679 } 680 681 err = checkPartitionKeys(context.TODO(), pb.builder.nameByColRef, tableDef, partDef) 682 require.NotNil(t, err) 683 } 684 { 685 //partition keys [col1] 686 pb, err := mockPartitionBinder(tableDef) 687 require.Nil(t, err) 688 689 astExpr, err := mockExpr(t, "col1+1") 690 require.Nil(t, err) 691 692 expr, err := pb.BindExpr(astExpr, 0, true) 693 require.Nil(t, err) 694 695 partDef := &PartitionByDef{} 696 partDef.PartitionExpr = &plan.PartitionExpr{ 697 Expr: expr, 698 } 699 700 err = checkPartitionKeys(context.TODO(), pb.builder.nameByColRef, tableDef, partDef) 701 require.Nil(t, err) 702 } 703 { 704 //partition keys [] 705 pb, err := mockPartitionBinder(tableDef) 706 require.Nil(t, err) 707 708 astExpr, err := mockExpr(t, "1") 709 require.Nil(t, err) 710 711 expr, err := pb.BindExpr(astExpr, 0, true) 712 require.Nil(t, err) 713 714 partDef := &PartitionByDef{} 715 partDef.PartitionExpr = &plan.PartitionExpr{ 716 Expr: expr, 717 } 718 719 err = checkPartitionKeys(context.TODO(), pb.builder.nameByColRef, tableDef, partDef) 720 require.Nil(t, err) 721 } 722 { 723 //partition keys [col1,col2] 724 pb, err := mockPartitionBinder(tableDef2) 725 require.Nil(t, err) 726 727 astExpr, err := mockExpr(t, "col1+1+col2") 728 require.Nil(t, err) 729 730 expr, err := pb.BindExpr(astExpr, 0, true) 731 require.Nil(t, err) 732 733 partDef := &PartitionByDef{} 734 partDef.PartitionExpr = &plan.PartitionExpr{ 735 Expr: expr, 736 } 737 738 err = checkPartitionKeys(context.TODO(), pb.builder.nameByColRef, tableDef2, partDef) 739 require.Nil(t, err) 740 } 741 addIndex(tableDef2, "index2", "col1") 742 { 743 //partition keys [col1,col2] 744 pb, err := mockPartitionBinder(tableDef2) 745 require.Nil(t, err) 746 747 astExpr, err := mockExpr(t, "col1+1+col2") 748 require.Nil(t, err) 749 750 expr, err := pb.BindExpr(astExpr, 0, true) 751 require.Nil(t, err) 752 753 partDef := &PartitionByDef{} 754 partDef.PartitionExpr = &plan.PartitionExpr{ 755 Expr: expr, 756 } 757 758 err = checkPartitionKeys(context.TODO(), pb.builder.nameByColRef, tableDef2, partDef) 759 require.NotNil(t, err) 760 } 761 { 762 //partition keys [col2] 763 pb, err := mockPartitionBinder(tableDef2) 764 require.Nil(t, err) 765 766 astExpr, err := mockExpr(t, "col2") 767 require.Nil(t, err) 768 769 expr, err := pb.BindExpr(astExpr, 0, true) 770 require.Nil(t, err) 771 772 partDef := &PartitionByDef{} 773 partDef.PartitionExpr = &plan.PartitionExpr{ 774 Expr: expr, 775 } 776 777 err = checkPartitionKeys(context.TODO(), pb.builder.nameByColRef, tableDef2, partDef) 778 require.NotNil(t, err) 779 } 780 { 781 //partition columns [col1] 782 partDef := &PartitionByDef{} 783 partDef.PartitionColumns = &plan.PartitionColumns{ 784 PartitionColumns: []string{"col1"}, 785 } 786 787 err := checkPartitionKeys(context.TODO(), nil, tableDef2, partDef) 788 require.Nil(t, err) 789 } 790 { 791 //partition columns [col1,col1] 792 partDef := &PartitionByDef{} 793 partDef.PartitionColumns = &plan.PartitionColumns{ 794 PartitionColumns: []string{"col1", "col1"}, 795 } 796 797 err := checkPartitionKeys(context.TODO(), nil, tableDef2, partDef) 798 require.NotNil(t, err) 799 } 800 { 801 //partition columns [col1] 802 partDef := &PartitionByDef{} 803 partDef.PartitionColumns = &plan.PartitionColumns{ 804 PartitionColumns: []string{"col1"}, 805 } 806 tableDef2.Pkey = &PrimaryKeyDef{ 807 Names: []string{"col1", "col1"}, 808 } 809 err := checkPartitionKeys(context.TODO(), nil, tableDef2, partDef) 810 require.NotNil(t, err) 811 } 812 { 813 //partition columns [col1] 814 partDef := &PartitionByDef{} 815 partDef.PartitionColumns = &plan.PartitionColumns{ 816 PartitionColumns: []string{"col1"}, 817 } 818 tableDef2.Indexes[0].Parts = []string{ 819 "col1", "col1", 820 } 821 err := checkPartitionKeys(context.TODO(), nil, tableDef2, partDef) 822 require.NotNil(t, err) 823 } 824 } 825 826 func addCol(tableDef *TableDef, col *ColDef) { 827 tableDef.Cols = append(tableDef.Cols, col) 828 } 829 830 func Test_checkPartitionExprType(t *testing.T) { 831 /* 832 table test: 833 col1 int32 pk 834 col2 int32 835 */ 836 tableDef := &plan.TableDef{ 837 Name: "test", 838 Pkey: &plan.PrimaryKeyDef{ 839 Names: []string{"col1"}, 840 }, 841 } 842 843 addCol(tableDef, &ColDef{ 844 Name: "col1", 845 Typ: plan.Type{ 846 Id: int32(types.T_int8), 847 }, 848 }) 849 addCol(tableDef, &ColDef{ 850 Name: "col2", 851 Typ: plan.Type{ 852 Id: int32(types.T_int8), 853 }, 854 }) 855 856 { 857 //partition keys [col1] 858 pb, err := mockPartitionBinder(tableDef) 859 require.Nil(t, err) 860 861 astExpr, err := mockExpr(t, "col1") 862 require.Nil(t, err) 863 864 expr, err := pb.BindExpr(astExpr, 0, true) 865 require.Nil(t, err) 866 867 partDef := &PartitionByDef{} 868 partDef.PartitionExpr = &plan.PartitionExpr{ 869 Expr: expr, 870 } 871 872 err = checkPartitionExprType(context.TODO(), nil, nil, partDef) 873 require.Nil(t, err) 874 } 875 { 876 //partition keys [col1] 877 pb, err := mockPartitionBinder(tableDef) 878 require.Nil(t, err) 879 880 astExpr, err := mockExpr(t, "col1 / 3") 881 require.Nil(t, err) 882 883 expr, err := pb.BindExpr(astExpr, 0, true) 884 require.NotNil(t, err) 885 require.Nil(t, expr) 886 887 } 888 } 889 890 func Test_stringSliceToMap(t *testing.T) { 891 smap := make(map[string]int) 892 r1, _ := stringSliceToMap(nil, smap) 893 require.False(t, r1) 894 895 smap2 := make(map[string]int) 896 r2, _ := stringSliceToMap([]string{"a1", "a2"}, smap2) 897 require.False(t, r2) 898 899 smap3 := make(map[string]int) 900 r3, r31 := stringSliceToMap([]string{"a1", "a1"}, smap3) 901 require.True(t, r3) 902 require.Equal(t, r31, "a1") 903 904 smap4 := make(map[string]int) 905 r4, r41 := stringSliceToMap([]string{"", ""}, smap4) 906 require.True(t, r4) 907 require.Equal(t, r41, "") 908 } 909 910 func Test_checkDuplicatePartitionName(t *testing.T) { 911 { 912 partDef1 := &PartitionByDef{ 913 Partitions: []*plan.PartitionItem{ 914 {PartitionName: "p0"}, 915 {PartitionName: "p2"}, 916 }, 917 } 918 919 err := checkPartitionNameUnique(context.TODO(), partDef1) 920 require.Nil(t, err) 921 } 922 { 923 partDef1 := &PartitionByDef{ 924 Partitions: []*plan.PartitionItem{ 925 {PartitionName: "p0"}, 926 {PartitionName: "p0"}, 927 }, 928 } 929 930 err := checkPartitionNameUnique(context.TODO(), partDef1) 931 require.NotNil(t, err) 932 } 933 } 934 935 func Test_checkPartitionCount(t *testing.T) { 936 { 937 err := checkPartitionCount(context.TODO(), PartitionCountLimit-10) 938 require.Nil(t, err) 939 } 940 { 941 err := checkPartitionCount(context.TODO(), PartitionCountLimit+10) 942 require.NotNil(t, err) 943 } 944 } 945 946 func Test_checkDuplicatePartitionColumns(t *testing.T) { 947 { 948 partDef := &PartitionByDef{ 949 PartitionColumns: &plan.PartitionColumns{ 950 PartitionColumns: []string{}, 951 }, 952 } 953 err := checkPartitionColumnsUnique(context.TODO(), partDef) 954 require.Nil(t, err) 955 } 956 { 957 partDef := &PartitionByDef{} 958 err := checkPartitionColumnsUnique(context.TODO(), partDef) 959 require.Nil(t, err) 960 } 961 { 962 partDef := &PartitionByDef{ 963 PartitionColumns: &plan.PartitionColumns{ 964 PartitionColumns: []string{"a"}, 965 }, 966 } 967 err := checkPartitionColumnsUnique(context.TODO(), partDef) 968 require.Nil(t, err) 969 } 970 { 971 partDef := &PartitionByDef{ 972 PartitionColumns: &plan.PartitionColumns{ 973 PartitionColumns: []string{"a", "a"}, 974 }, 975 } 976 err := checkPartitionColumnsUnique(context.TODO(), partDef) 977 require.NotNil(t, err) 978 } 979 { 980 partDef := &PartitionByDef{ 981 PartitionColumns: &plan.PartitionColumns{ 982 PartitionColumns: []string{"a", "b"}, 983 }, 984 } 985 err := checkPartitionColumnsUnique(context.TODO(), partDef) 986 require.Nil(t, err) 987 } 988 } 989 990 func TestCheckPartitionFuncValid(t *testing.T) { 991 /* 992 create table test( 993 col1 int8, 994 col2 int8, 995 col3 date, 996 PRIMARY KEY(col1, col2, col3) 997 ); 998 */ 999 tableDef := &plan.TableDef{ 1000 Name: "test", 1001 Pkey: &plan.PrimaryKeyDef{ 1002 Names: []string{"col1", "col2", "col3"}, 1003 }, 1004 } 1005 1006 addCol(tableDef, &ColDef{ 1007 Name: "col1", 1008 Typ: plan.Type{ 1009 Id: int32(types.T_int8), 1010 }, 1011 }) 1012 addCol(tableDef, &ColDef{ 1013 Name: "col2", 1014 Typ: plan.Type{ 1015 Id: int32(types.T_int8), 1016 }, 1017 }) 1018 addCol(tableDef, &ColDef{ 1019 Name: "col3", 1020 Typ: plan.Type{ 1021 Id: int32(types.T_date), 1022 }, 1023 }) 1024 1025 type kase struct { 1026 s string 1027 wantPartitionFuncErr bool 1028 wantPartitionExprTypeErr bool 1029 } 1030 1031 checkFunc := func(k kase) { 1032 //fmt.Println(k.s) 1033 pb, err := mockPartitionBinder(tableDef) 1034 require.Nil(t, err) 1035 1036 astExpr, err := mockExpr(t, k.s) 1037 require.Nil(t, err) 1038 1039 partitionDef := &PartitionByDef{ 1040 Type: plan.PartitionType_HASH, 1041 } 1042 1043 err = buildPartitionExpr(context.TODO(), tableDef, pb, partitionDef, astExpr) 1044 if !k.wantPartitionFuncErr { 1045 require.Nil(t, err) 1046 require.NotNil(t, partitionDef.PartitionExpr.Expr) 1047 1048 err = checkPartitionExprType(context.TODO(), nil, nil, partitionDef) 1049 if !k.wantPartitionExprTypeErr { 1050 require.Nil(t, err) 1051 } else { 1052 require.NotNil(t, err) 1053 } 1054 } else { 1055 require.NotNil(t, err) 1056 } 1057 } 1058 1059 //--------------------------------------------------------------------------------- 1060 rightCases := []kase{ 1061 {"col1", false, false}, 1062 {"col1 + col2", false, false}, 1063 {"col1 - col2", false, false}, 1064 {"col1 * col2", false, false}, 1065 {"col1 div col2", false, false}, 1066 } 1067 1068 for _, k := range rightCases { 1069 checkFunc(k) 1070 } 1071 1072 //-------------------------------------------------------------------------------- 1073 wrongCases := []kase{ 1074 {"col1 / 3", true, false}, 1075 {"col1 / col2", true, false}, 1076 {"col1 | col2", true, false}, 1077 {"col1 & col2", true, false}, 1078 {"col1 ^ col2", true, false}, 1079 {"col1 << col2", true, false}, 1080 {"col1 >> col2", true, false}, 1081 {"~col2", true, false}, 1082 } 1083 for _, k := range wrongCases { 1084 checkFunc(k) 1085 } 1086 1087 //-------------------------------------------------------------------------------- 1088 supportedFuncCases := []kase{ 1089 {"abs(col1)", false, false}, 1090 {"abs(-1)", true, false}, 1091 {"ceiling(col1)", false, false}, 1092 {"ceiling(0.1)", true, false}, 1093 {"datediff('2007-12-31 23:59:59','2007-12-30')", true, false}, // XXX: should fold datediff and then report error 1094 {"datediff(col3,'2007-12-30')", false, false}, // re check it 1095 {"day(col3)", false, false}, 1096 {"dayofyear(col3)", false, false}, 1097 {"extract(year from col3)", false, false}, 1098 {"extract(year_month from col3)", false, false}, 1099 {"floor(col1)", false, false}, 1100 {"floor(0.1)", true, false}, 1101 {"hour(col3)", true, false}, 1102 {"minute(col3)", true, false}, 1103 {"mod(col1,3)", false, false}, 1104 {"month(col3)", false, false}, 1105 {"second(col3)", true, false}, 1106 {"unix_timestamp(col3)", true, false}, 1107 {"weekday(col3)", false, false}, 1108 {"year(col3)", false, false}, 1109 {"to_days(col3)", false, false}, 1110 {"to_seconds(col3)", false, false}, 1111 } 1112 for _, k := range supportedFuncCases { 1113 checkFunc(k) 1114 } 1115 1116 //------------------------------------------------------------------------------------- 1117 unsupportedFuncCases := []kase{ 1118 {"dayofmonth(col3)", true, false}, //unimplement builtin function 1119 {"dayofweek(col3)", true, false}, //unimplement builtin function 1120 {"microsecond(col3)", true, false}, //unimplement builtin function 1121 {"quarter(col3)", true, false}, //unimplement builtin function 1122 {"time_to_sec(col3)", true, false}, //unimplement builtin function 1123 {"yearweek(col3)", true, false}, //unimplement builtin function 1124 } 1125 for _, k := range unsupportedFuncCases { 1126 checkFunc(k) 1127 } 1128 }