github.com/mithrandie/csvq@v1.18.1/lib/query/reference_scope_test.go (about) 1 package query 2 3 import ( 4 "context" 5 "reflect" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/mithrandie/go-text" 11 12 "github.com/mithrandie/csvq/lib/parser" 13 "github.com/mithrandie/csvq/lib/value" 14 ) 15 16 func TestFieldIndexCache_Get(t *testing.T) { 17 cache := &FieldIndexCache{ 18 limitToUseSlice: 2, 19 m: nil, 20 exprs: []parser.QueryExpression{parser.FieldReference{Column: parser.Identifier{Literal: "c1"}}}, 21 indices: []int{1}, 22 } 23 24 _, ok := cache.Get(parser.FieldReference{Column: parser.Identifier{Literal: "c9"}}) 25 if ok { 26 t.Error("Get() is succeeded, want to be failed") 27 } 28 29 expect := 1 30 idx, ok := cache.Get(parser.FieldReference{Column: parser.Identifier{Literal: "c1"}}) 31 if !ok { 32 t.Error("Get() is failed, want to be succeeded") 33 } 34 if idx != expect { 35 t.Errorf("result = %d, want %d", idx, expect) 36 } 37 38 cache = &FieldIndexCache{ 39 limitToUseSlice: 2, 40 m: map[parser.QueryExpression]int{ 41 parser.FieldReference{Column: parser.Identifier{Literal: "c1"}}: 1, 42 parser.FieldReference{Column: parser.Identifier{Literal: "c2"}}: 2, 43 parser.FieldReference{Column: parser.Identifier{Literal: "c3"}}: 3, 44 }, 45 exprs: nil, 46 indices: nil, 47 } 48 49 _, ok = cache.Get(parser.FieldReference{Column: parser.Identifier{Literal: "c9"}}) 50 if ok { 51 t.Error("Get() is succeeded, want to be failed") 52 } 53 54 expect = 2 55 idx, ok = cache.Get(parser.FieldReference{Column: parser.Identifier{Literal: "c2"}}) 56 if !ok { 57 t.Error("Get() is failed, want to be succeeded") 58 } 59 if idx != expect { 60 t.Errorf("result = %d, want %d", idx, expect) 61 } 62 } 63 64 func TestFieldIndexCache_Add(t *testing.T) { 65 cache := NewFieldIndexCache(1, 2) 66 67 cache.Add(parser.FieldReference{Column: parser.Identifier{Literal: "c1"}}, 1) 68 expect := &FieldIndexCache{ 69 limitToUseSlice: 2, 70 m: nil, 71 exprs: []parser.QueryExpression{parser.FieldReference{Column: parser.Identifier{Literal: "c1"}}}, 72 indices: []int{1}, 73 } 74 75 if !reflect.DeepEqual(cache, expect) { 76 t.Errorf("cache = %v, want %v", cache, expect) 77 } 78 79 cache.Add(parser.FieldReference{Column: parser.Identifier{Literal: "c2"}}, 2) 80 cache.Add(parser.FieldReference{Column: parser.Identifier{Literal: "c3"}}, 3) 81 expect = &FieldIndexCache{ 82 limitToUseSlice: 2, 83 m: map[parser.QueryExpression]int{ 84 parser.FieldReference{Column: parser.Identifier{Literal: "c1"}}: 1, 85 parser.FieldReference{Column: parser.Identifier{Literal: "c2"}}: 2, 86 parser.FieldReference{Column: parser.Identifier{Literal: "c3"}}: 3, 87 }, 88 exprs: nil, 89 indices: nil, 90 } 91 92 if !reflect.DeepEqual(cache, expect) { 93 t.Errorf("cache = %v, want %v", cache, expect) 94 } 95 } 96 97 var testVariablesReferenceScope = GenerateReferenceScope([]map[string]map[string]interface{}{ 98 { 99 scopeNameVariables: { 100 "var1": value.NewInteger(1), 101 }, 102 }, 103 { 104 scopeNameVariables: { 105 "var1": value.NewInteger(2), 106 }, 107 }, 108 }, nil, time.Time{}, nil) 109 110 var testTemporaryTablesReferenceScope = GenerateReferenceScope([]map[string]map[string]interface{}{ 111 { 112 scopeNameTempTables: { 113 "TEMPTABLE1": &View{ 114 Header: NewHeader("temptable1", []string{"column1", "column2"}), 115 RecordSet: []Record{ 116 NewRecord([]value.Primary{ 117 value.NewString("1"), 118 value.NewString("str1"), 119 }), 120 NewRecord([]value.Primary{ 121 value.NewString("2"), 122 value.NewString("str2"), 123 }), 124 }, 125 FileInfo: &FileInfo{ 126 Path: "temptable1", 127 Delimiter: ',', 128 ViewType: ViewTypeTemporaryTable, 129 }, 130 }, 131 }, 132 }, 133 { 134 scopeNameTempTables: { 135 "TEMPTABLE2": &View{ 136 Header: NewHeader("temptable2", []string{"column1", "column2"}), 137 RecordSet: []Record{ 138 NewRecord([]value.Primary{ 139 value.NewString("1"), 140 value.NewString("str1"), 141 }), 142 NewRecord([]value.Primary{ 143 value.NewString("2"), 144 value.NewString("str2"), 145 }), 146 }, 147 FileInfo: &FileInfo{ 148 Path: "temptable2", 149 Delimiter: ',', 150 ViewType: ViewTypeTemporaryTable, 151 }, 152 }, 153 }, 154 }, 155 }, nil, time.Time{}, nil) 156 157 var referenceScopeGetVariableTests = []struct { 158 Name string 159 Expr parser.Variable 160 Result value.Primary 161 Error string 162 }{ 163 { 164 Name: "ReferenceScope GetVariable", 165 Expr: parser.Variable{Name: "var1"}, 166 Result: value.NewInteger(1), 167 }, 168 { 169 Name: "ReferenceScope GetVariable Undeclared Error", 170 Expr: parser.Variable{Name: "undef"}, 171 Error: "variable @undef is undeclared", 172 }, 173 } 174 175 func TestReferenceScope_GetVariable(t *testing.T) { 176 177 for _, v := range referenceScopeGetVariableTests { 178 result, err := testVariablesReferenceScope.GetVariable(v.Expr) 179 if err != nil { 180 if len(v.Error) < 1 { 181 t.Errorf("%s: unexpected error %q", v.Name, err) 182 } else if err.Error() != v.Error { 183 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 184 } 185 continue 186 } 187 if 0 < len(v.Error) { 188 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 189 continue 190 } 191 if !reflect.DeepEqual(result, v.Result) { 192 t.Errorf("%s: result = %s, want %s", v.Name, result, v.Result) 193 } 194 } 195 } 196 197 var referenceScopeSubstituteVariableTests = []struct { 198 Name string 199 Expr parser.VariableSubstitution 200 ResultScope *ReferenceScope 201 Result value.Primary 202 Error string 203 }{ 204 { 205 Name: "ReferenceScope SubstituteVariable", 206 Expr: parser.VariableSubstitution{ 207 Variable: parser.Variable{Name: "var1"}, 208 Value: parser.NewIntegerValue(3), 209 }, 210 ResultScope: GenerateReferenceScope([]map[string]map[string]interface{}{ 211 { 212 scopeNameVariables: { 213 "var1": value.NewInteger(3), 214 }, 215 }, 216 { 217 scopeNameVariables: { 218 "var1": value.NewInteger(2), 219 }, 220 }, 221 }, nil, time.Time{}, nil), 222 Result: value.NewInteger(3), 223 }, 224 { 225 Name: "ReferenceScope SubstituteVariable Undeclared Error", 226 Expr: parser.VariableSubstitution{ 227 Variable: parser.Variable{Name: "var2"}, 228 Value: parser.NewIntegerValue(3), 229 }, 230 Error: "variable @var2 is undeclared", 231 }, 232 } 233 234 func TestReferenceScope_SubstituteVariable(t *testing.T) { 235 for _, v := range referenceScopeSubstituteVariableTests { 236 result, err := testVariablesReferenceScope.SubstituteVariable(context.Background(), v.Expr) 237 if err != nil { 238 if len(v.Error) < 1 { 239 t.Errorf("%s: unexpected error %q", v.Name, err) 240 } else if err.Error() != v.Error { 241 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 242 } 243 continue 244 } 245 if 0 < len(v.Error) { 246 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 247 continue 248 } 249 if !BlockScopeListEqual(testVariablesReferenceScope.Blocks, v.ResultScope.Blocks) { 250 t.Errorf("%s: blocks = %v, want %v", v.Name, testVariablesReferenceScope.Blocks, v.ResultScope.Blocks) 251 } 252 if !reflect.DeepEqual(result, v.Result) { 253 t.Errorf("%s: result = %v, want %v", v.Name, result, v.Result) 254 } 255 } 256 } 257 258 var referenceScopeDisposeVariableTests = []struct { 259 Name string 260 Expr parser.Variable 261 ResultScope *ReferenceScope 262 Error string 263 }{ 264 { 265 Name: "ReferenceScope DisposeVariable", 266 Expr: parser.Variable{Name: "var1"}, 267 ResultScope: GenerateReferenceScope([]map[string]map[string]interface{}{ 268 {}, 269 { 270 scopeNameVariables: { 271 "var1": value.NewInteger(2), 272 }, 273 }, 274 }, nil, time.Time{}, nil), 275 }, 276 { 277 Name: "ReferenceScope DisposeVariable Undeclared Error", 278 Expr: parser.Variable{Name: "undef"}, 279 Error: "variable @undef is undeclared", 280 }, 281 } 282 283 func TestReferenceScope_DisposeVariable(t *testing.T) { 284 for _, v := range referenceScopeDisposeVariableTests { 285 err := testVariablesReferenceScope.DisposeVariable(v.Expr) 286 if err != nil { 287 if len(v.Error) < 1 { 288 t.Errorf("%s: unexpected error %q", v.Name, err) 289 } else if err.Error() != v.Error { 290 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 291 } 292 continue 293 } 294 if 0 < len(v.Error) { 295 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 296 continue 297 } 298 if !BlockScopeListEqual(testVariablesReferenceScope.Blocks, v.ResultScope.Blocks) { 299 t.Errorf("%s: blocks = %v, want %v", v.Name, testVariablesReferenceScope.Blocks, v.ResultScope.Blocks) 300 } 301 } 302 } 303 304 var referenceScopeTemporaryTableExistsTests = []struct { 305 Name string 306 Path string 307 Result bool 308 }{ 309 { 310 Name: "ReferenceScope TemporaryTableExists", 311 Path: "temptable2", 312 Result: true, 313 }, 314 { 315 Name: "ReferenceScope TemporaryTableExists Not Exist", 316 Path: "notexist", 317 Result: false, 318 }, 319 } 320 321 func TestReferenceScope_TemporaryTableExists(t *testing.T) { 322 323 for _, v := range referenceScopeTemporaryTableExistsTests { 324 result := testTemporaryTablesReferenceScope.TemporaryTableExists(v.Path) 325 if result != v.Result { 326 t.Errorf("%s: result = %t, want %t", v.Name, result, v.Result) 327 } 328 } 329 } 330 331 var referenceScopeGetTemporaryTableTests = []struct { 332 Name string 333 Path parser.Identifier 334 Result *View 335 Error string 336 }{ 337 { 338 Name: "ReferenceScope GetTemporaryTable", 339 Path: parser.Identifier{Literal: "temptable2"}, 340 Result: &View{ 341 Header: NewHeader("temptable2", []string{"column1", "column2"}), 342 RecordSet: []Record{ 343 NewRecord([]value.Primary{ 344 value.NewString("1"), 345 value.NewString("str1"), 346 }), 347 NewRecord([]value.Primary{ 348 value.NewString("2"), 349 value.NewString("str2"), 350 }), 351 }, 352 FileInfo: &FileInfo{ 353 Path: "temptable2", 354 Delimiter: ',', 355 ViewType: ViewTypeTemporaryTable, 356 }, 357 }, 358 }, 359 { 360 Name: "ReferenceScope GetTemporaryTable Not Loaded Error", 361 Path: parser.Identifier{Literal: "/path/to/table9.csv"}, 362 Error: "view /path/to/table9.csv is undeclared", 363 }, 364 } 365 366 func TestReferenceScope_GetTemporaryTable(t *testing.T) { 367 for _, v := range referenceScopeGetTemporaryTableTests { 368 view, err := testTemporaryTablesReferenceScope.GetTemporaryTable(v.Path) 369 if err != nil { 370 if len(v.Error) < 1 { 371 t.Errorf("%s: unexpected error %q", v.Name, err) 372 } else if err.Error() != v.Error { 373 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 374 } 375 continue 376 } 377 if 0 < len(v.Error) { 378 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 379 continue 380 } 381 if !reflect.DeepEqual(view, v.Result) { 382 t.Errorf("%s: view = %v, want %v", v.Name, view, v.Result) 383 } 384 } 385 } 386 387 var referenceScopeGetTemporaryTableWithInternalIdTests = []struct { 388 Name string 389 Path parser.Identifier 390 Result *View 391 Error string 392 }{ 393 { 394 Name: "ReferenceScope GetTemporaryTableWithInternalId", 395 Path: parser.Identifier{Literal: "temptable2"}, 396 Result: &View{ 397 Header: NewHeaderWithId("temptable2", []string{"column1", "column2"}), 398 RecordSet: []Record{ 399 NewRecordWithId(0, []value.Primary{ 400 value.NewString("1"), 401 value.NewString("str1"), 402 }), 403 NewRecordWithId(1, []value.Primary{ 404 value.NewString("2"), 405 value.NewString("str2"), 406 }), 407 }, 408 FileInfo: &FileInfo{ 409 Path: "temptable2", 410 Delimiter: ',', 411 ViewType: ViewTypeTemporaryTable, 412 }, 413 }, 414 }, 415 { 416 Name: "ReferenceScope GetTemporaryTableWithInternalId Not Loaded Error", 417 Path: parser.Identifier{Literal: "/path/to/table9.csv"}, 418 Error: "view /path/to/table9.csv is undeclared", 419 }, 420 } 421 422 func TestTemporaryViewScopes_GetWithInternalId(t *testing.T) { 423 for _, v := range referenceScopeGetTemporaryTableWithInternalIdTests { 424 view, err := testTemporaryTablesReferenceScope.GetTemporaryTableWithInternalId(context.Background(), v.Path, TestTx.Flags) 425 if err != nil { 426 if len(v.Error) < 1 { 427 t.Errorf("%s: unexpected error %q", v.Name, err) 428 } else if err.Error() != v.Error { 429 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 430 } 431 continue 432 } 433 if 0 < len(v.Error) { 434 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 435 continue 436 } 437 if !reflect.DeepEqual(view, v.Result) { 438 t.Errorf("%s: view = %v, want %v", v.Name, view, v.Result) 439 } 440 } 441 } 442 443 var referenceScopeSetTemporaryTableTests = []struct { 444 Name string 445 SetView *View 446 Result *ReferenceScope 447 }{ 448 { 449 Name: "ReferenceScope SetTemporaryTable", 450 SetView: &View{ 451 Header: NewHeader("tempview3", []string{"column1", "column2"}), 452 RecordSet: []Record{ 453 NewRecord([]value.Primary{ 454 value.NewString("1"), 455 value.NewString("str1"), 456 }), 457 NewRecord([]value.Primary{ 458 value.NewString("2"), 459 value.NewString("str2"), 460 }), 461 }, 462 FileInfo: &FileInfo{ 463 Path: "tempview3", 464 Delimiter: ',', 465 ViewType: ViewTypeTemporaryTable, 466 }, 467 }, 468 Result: GenerateReferenceScope([]map[string]map[string]interface{}{ 469 { 470 scopeNameTempTables: { 471 "TEMPTABLE1": &View{ 472 Header: NewHeader("temptable1", []string{"column1", "column2"}), 473 RecordSet: []Record{ 474 NewRecord([]value.Primary{ 475 value.NewString("1"), 476 value.NewString("str1"), 477 }), 478 NewRecord([]value.Primary{ 479 value.NewString("2"), 480 value.NewString("str2"), 481 }), 482 }, 483 FileInfo: &FileInfo{ 484 Path: "temptable1", 485 Delimiter: ',', 486 ViewType: ViewTypeTemporaryTable, 487 }, 488 }, 489 "TEMPTABLE3": &View{ 490 Header: NewHeader("tempview3", []string{"column1", "column2"}), 491 RecordSet: []Record{ 492 NewRecord([]value.Primary{ 493 value.NewString("1"), 494 value.NewString("str1"), 495 }), 496 NewRecord([]value.Primary{ 497 value.NewString("2"), 498 value.NewString("str2"), 499 }), 500 }, 501 FileInfo: &FileInfo{ 502 Path: "tempview3", 503 Delimiter: ',', 504 ViewType: ViewTypeTemporaryTable, 505 }, 506 }, 507 }, 508 }, 509 { 510 scopeNameTempTables: { 511 "TEMPTABLE2": &View{ 512 Header: NewHeader("temptable2", []string{"column1", "column2"}), 513 RecordSet: []Record{ 514 NewRecord([]value.Primary{ 515 value.NewString("1"), 516 value.NewString("str1"), 517 }), 518 NewRecord([]value.Primary{ 519 value.NewString("2"), 520 value.NewString("str2"), 521 }), 522 }, 523 FileInfo: &FileInfo{ 524 Path: "temptable2", 525 Delimiter: ',', 526 ViewType: ViewTypeTemporaryTable, 527 }, 528 }, 529 }, 530 }, 531 }, nil, time.Time{}, nil), 532 }, 533 } 534 535 func TestReferenceScope_SetTemporaryTable(t *testing.T) { 536 for _, v := range referenceScopeSetTemporaryTableTests { 537 testTemporaryTablesReferenceScope.SetTemporaryTable(v.SetView) 538 if !BlockScopeListEqual(testTemporaryTablesReferenceScope.Blocks, v.Result.Blocks) { 539 t.Errorf("%s: blocks = %v, want %v", v.Name, testTemporaryTablesReferenceScope.Blocks, v.Result.Blocks) 540 } 541 } 542 } 543 544 var referenceScopeReplaceTemporaryTableTests = []struct { 545 Name string 546 SetView *View 547 Result *ReferenceScope 548 Error string 549 }{ 550 { 551 Name: "ReferenceScope ReplaceTemporaryTable", 552 SetView: &View{ 553 Header: NewHeader("temptable2", []string{"column1", "column2"}), 554 RecordSet: []Record{ 555 NewRecord([]value.Primary{ 556 value.NewString("1"), 557 value.NewString("updated"), 558 }), 559 NewRecord([]value.Primary{ 560 value.NewString("2"), 561 value.NewString("updated"), 562 }), 563 }, 564 FileInfo: &FileInfo{ 565 Path: "temptable2", 566 Delimiter: ',', 567 ViewType: ViewTypeTemporaryTable, 568 }, 569 }, 570 Result: GenerateReferenceScope([]map[string]map[string]interface{}{ 571 { 572 scopeNameTempTables: { 573 "TEMPTABLE1": &View{ 574 Header: NewHeader("temptable1", []string{"column1", "column2"}), 575 RecordSet: []Record{ 576 NewRecord([]value.Primary{ 577 value.NewString("1"), 578 value.NewString("str1"), 579 }), 580 NewRecord([]value.Primary{ 581 value.NewString("2"), 582 value.NewString("str2"), 583 }), 584 }, 585 FileInfo: &FileInfo{ 586 Path: "temptable1", 587 Delimiter: ',', 588 ViewType: ViewTypeTemporaryTable, 589 }, 590 }, 591 "TEMPTABLE3": &View{ 592 Header: NewHeader("tempview3", []string{"column1", "column2"}), 593 RecordSet: []Record{ 594 NewRecord([]value.Primary{ 595 value.NewString("1"), 596 value.NewString("str1"), 597 }), 598 NewRecord([]value.Primary{ 599 value.NewString("2"), 600 value.NewString("str2"), 601 }), 602 }, 603 FileInfo: &FileInfo{ 604 Path: "tempview3", 605 Delimiter: ',', 606 ViewType: ViewTypeTemporaryTable, 607 }, 608 }, 609 }, 610 }, 611 { 612 scopeNameTempTables: { 613 "TEMPTABLE2": &View{ 614 Header: NewHeader("temptable2", []string{"column1", "column2"}), 615 RecordSet: []Record{ 616 NewRecord([]value.Primary{ 617 value.NewString("1"), 618 value.NewString("updated"), 619 }), 620 NewRecord([]value.Primary{ 621 value.NewString("2"), 622 value.NewString("updated"), 623 }), 624 }, 625 FileInfo: &FileInfo{ 626 Path: "temptable2", 627 Delimiter: ',', 628 ViewType: ViewTypeTemporaryTable, 629 }, 630 }, 631 }, 632 }, 633 }, nil, time.Time{}, nil), 634 }, 635 } 636 637 func TestReferenceScope_ReplaceTemporaryTable(t *testing.T) { 638 for _, v := range referenceScopeReplaceTemporaryTableTests { 639 testTemporaryTablesReferenceScope.ReplaceTemporaryTable(v.SetView) 640 if !BlockScopeListEqual(testTemporaryTablesReferenceScope.Blocks, v.Result.Blocks) { 641 t.Errorf("%s: blocks = %v, want %v", v.Name, testTemporaryTablesReferenceScope.Blocks, v.Result.Blocks) 642 } 643 } 644 } 645 646 var referenceScopesDisposeTemporaryTableTests = []struct { 647 Name string 648 Path parser.Identifier 649 Result *ReferenceScope 650 Error string 651 }{ 652 { 653 Name: "ReferenceScope DisposeTemporaryTable", 654 Path: parser.Identifier{Literal: "temptable1"}, 655 Result: GenerateReferenceScope([]map[string]map[string]interface{}{ 656 { 657 scopeNameTempTables: { 658 "TEMPTABLE3": &View{ 659 Header: NewHeader("tempview3", []string{"column1", "column2"}), 660 RecordSet: []Record{ 661 NewRecord([]value.Primary{ 662 value.NewString("1"), 663 value.NewString("str1"), 664 }), 665 NewRecord([]value.Primary{ 666 value.NewString("2"), 667 value.NewString("str2"), 668 }), 669 }, 670 FileInfo: &FileInfo{ 671 Path: "tempview3", 672 Delimiter: ',', 673 ViewType: ViewTypeTemporaryTable, 674 }, 675 }, 676 }, 677 }, 678 { 679 scopeNameTempTables: { 680 "TEMPTABLE2": &View{ 681 Header: NewHeader("temptable2", []string{"column1", "column2"}), 682 RecordSet: []Record{ 683 NewRecord([]value.Primary{ 684 value.NewString("1"), 685 value.NewString("updated"), 686 }), 687 NewRecord([]value.Primary{ 688 value.NewString("2"), 689 value.NewString("updated"), 690 }), 691 }, 692 FileInfo: &FileInfo{ 693 Path: "temptable2", 694 Delimiter: ',', 695 ViewType: ViewTypeTemporaryTable, 696 }, 697 }, 698 }, 699 }, 700 }, nil, time.Time{}, nil), 701 }, 702 { 703 Name: "ReferenceScope DisposeTemporaryTable Not Loaded Error", 704 Path: parser.Identifier{Literal: "/path/to/table9.csv"}, 705 Error: "view /path/to/table9.csv is undeclared", 706 }, 707 } 708 709 func TestReferenceScope_DisposeTemporaryTable(t *testing.T) { 710 for _, v := range referenceScopesDisposeTemporaryTableTests { 711 err := testTemporaryTablesReferenceScope.DisposeTemporaryTable(v.Path) 712 if err != nil { 713 if len(v.Error) < 1 { 714 t.Errorf("%s: unexpected error %q", v.Name, err) 715 } else if err.Error() != v.Error { 716 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 717 } 718 continue 719 } 720 if 0 < len(v.Error) { 721 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 722 continue 723 } 724 if !BlockScopeListEqual(testTemporaryTablesReferenceScope.Blocks, v.Result.Blocks) { 725 t.Errorf("%s: blocks = %v, want %v", v.Name, testTemporaryTablesReferenceScope.Blocks, v.Result.Blocks) 726 } 727 } 728 } 729 730 func TestReferenceScope_StoreTemporaryTable(t *testing.T) { 731 scope := GenerateReferenceScope([]map[string]map[string]interface{}{ 732 { 733 scopeNameTempTables: { 734 "TEMPTABLE3": &View{ 735 Header: NewHeader("tempview3", []string{"column1", "column2"}), 736 RecordSet: []Record{ 737 NewRecord([]value.Primary{ 738 value.NewString("1"), 739 value.NewString("str1"), 740 }), 741 NewRecord([]value.Primary{ 742 value.NewString("2"), 743 value.NewString("str2"), 744 }), 745 }, 746 FileInfo: &FileInfo{ 747 Path: "tempview3", 748 Delimiter: ',', 749 ViewType: ViewTypeTemporaryTable, 750 }, 751 }, 752 }, 753 }, 754 { 755 scopeNameTempTables: { 756 "TEMPTABLE2": &View{ 757 Header: NewHeader("temptable2", []string{"column1", "column2"}), 758 RecordSet: []Record{ 759 NewRecord([]value.Primary{ 760 value.NewString("1"), 761 value.NewString("updated"), 762 }), 763 NewRecord([]value.Primary{ 764 value.NewString("2"), 765 value.NewString("updated"), 766 }), 767 }, 768 FileInfo: &FileInfo{ 769 Path: "temptable2", 770 Delimiter: ',', 771 ViewType: ViewTypeTemporaryTable, 772 restorePointHeader: NewHeader("table2", []string{"column1", "column2"}), 773 restorePointRecordSet: RecordSet{}, 774 }, 775 }, 776 }, 777 }, 778 }, nil, time.Time{}, nil) 779 780 expect := GenerateReferenceScope([]map[string]map[string]interface{}{ 781 { 782 scopeNameTempTables: { 783 "TEMPTABLE3": &View{ 784 Header: NewHeader("tempview3", []string{"column1", "column2"}), 785 RecordSet: []Record{ 786 NewRecord([]value.Primary{ 787 value.NewString("1"), 788 value.NewString("str1"), 789 }), 790 NewRecord([]value.Primary{ 791 value.NewString("2"), 792 value.NewString("str2"), 793 }), 794 }, 795 FileInfo: &FileInfo{ 796 Path: "tempview3", 797 Delimiter: ',', 798 ViewType: ViewTypeTemporaryTable, 799 }, 800 }, 801 }, 802 }, 803 { 804 scopeNameTempTables: { 805 "TEMPTABLE2": &View{ 806 Header: NewHeader("temptable2", []string{"column1", "column2"}), 807 RecordSet: []Record{ 808 NewRecord([]value.Primary{ 809 value.NewString("1"), 810 value.NewString("updated"), 811 }), 812 NewRecord([]value.Primary{ 813 value.NewString("2"), 814 value.NewString("updated"), 815 }), 816 }, 817 FileInfo: &FileInfo{ 818 Path: "temptable2", 819 Delimiter: ',', 820 ViewType: ViewTypeTemporaryTable, 821 restorePointHeader: NewHeader("temptable2", []string{"column1", "column2"}), 822 restorePointRecordSet: []Record{ 823 NewRecord([]value.Primary{ 824 value.NewString("1"), 825 value.NewString("updated"), 826 }), 827 NewRecord([]value.Primary{ 828 value.NewString("2"), 829 value.NewString("updated"), 830 }), 831 }, 832 }, 833 }, 834 }, 835 }, 836 }, nil, time.Time{}, nil) 837 838 expectOut := []string{"Commit: restore point of view \"temptable2\" is created.\n"} 839 840 UncommittedViews := map[string]*FileInfo{ 841 "TEMPTABLE2": nil, 842 } 843 844 log := scope.StoreTemporaryTable(TestTx.Session, UncommittedViews) 845 846 if !BlockScopeListEqual(scope.Blocks, expect.Blocks) { 847 t.Errorf("Store: blocks = %v, want %v", scope.Blocks, expect.Blocks) 848 } 849 850 if reflect.DeepEqual(log, expectOut) { 851 t.Errorf("Store: log = %s, want %s", log, expectOut) 852 } 853 } 854 855 func TestReferenceScope_RestoreTemporaryTable(t *testing.T) { 856 scope := GenerateReferenceScope([]map[string]map[string]interface{}{ 857 { 858 scopeNameTempTables: { 859 "TEMPTABLE3": &View{ 860 Header: NewHeader("tempview3", []string{"column1", "column2"}), 861 RecordSet: []Record{ 862 NewRecord([]value.Primary{ 863 value.NewString("1"), 864 value.NewString("str1"), 865 }), 866 NewRecord([]value.Primary{ 867 value.NewString("2"), 868 value.NewString("str2"), 869 }), 870 }, 871 FileInfo: &FileInfo{ 872 Path: "tempview3", 873 Delimiter: ',', 874 ViewType: ViewTypeTemporaryTable, 875 }, 876 }, 877 }, 878 }, 879 { 880 scopeNameTempTables: { 881 "TEMPTABLE2": &View{ 882 Header: NewHeader("temptable2", []string{"column1", "column2"}), 883 RecordSet: []Record{ 884 NewRecord([]value.Primary{ 885 value.NewString("1"), 886 value.NewString("updated"), 887 }), 888 NewRecord([]value.Primary{ 889 value.NewString("2"), 890 value.NewString("updated"), 891 }), 892 }, 893 FileInfo: &FileInfo{ 894 Path: "temptable2", 895 Delimiter: ',', 896 ViewType: ViewTypeTemporaryTable, 897 restorePointHeader: NewHeader("temptable2", []string{"column1", "column2"}), 898 restorePointRecordSet: []Record{ 899 NewRecord([]value.Primary{ 900 value.NewString("1"), 901 value.NewString("str1"), 902 }), 903 NewRecord([]value.Primary{ 904 value.NewString("2"), 905 value.NewString("str2"), 906 }), 907 }, 908 }, 909 }, 910 }, 911 }, 912 }, nil, time.Time{}, nil) 913 914 expect := GenerateReferenceScope([]map[string]map[string]interface{}{ 915 { 916 scopeNameTempTables: { 917 "TEMPTABLE3": &View{ 918 Header: NewHeader("tempview3", []string{"column1", "column2"}), 919 RecordSet: []Record{ 920 NewRecord([]value.Primary{ 921 value.NewString("1"), 922 value.NewString("str1"), 923 }), 924 NewRecord([]value.Primary{ 925 value.NewString("2"), 926 value.NewString("str2"), 927 }), 928 }, 929 FileInfo: &FileInfo{ 930 Path: "tempview3", 931 Delimiter: ',', 932 ViewType: ViewTypeTemporaryTable, 933 }, 934 }, 935 }, 936 }, 937 { 938 scopeNameTempTables: { 939 "TEMPTABLE2": &View{ 940 Header: NewHeader("temptable2", []string{"column1", "column2"}), 941 RecordSet: []Record{ 942 NewRecord([]value.Primary{ 943 value.NewString("1"), 944 value.NewString("str1"), 945 }), 946 NewRecord([]value.Primary{ 947 value.NewString("2"), 948 value.NewString("str2"), 949 }), 950 }, 951 FileInfo: &FileInfo{ 952 Path: "temptable2", 953 Delimiter: ',', 954 ViewType: ViewTypeTemporaryTable, 955 restorePointHeader: NewHeader("temptable2", []string{"column1", "column2"}), 956 restorePointRecordSet: []Record{ 957 NewRecord([]value.Primary{ 958 value.NewString("1"), 959 value.NewString("str1"), 960 }), 961 NewRecord([]value.Primary{ 962 value.NewString("2"), 963 value.NewString("str2"), 964 }), 965 }, 966 }, 967 }, 968 }, 969 }, 970 }, nil, time.Time{}, nil) 971 expectOut := []string{"Rollback: view \"tempview2\" is restored.\n"} 972 973 UncommittedViews := map[string]*FileInfo{ 974 "TEMPTABLE2": nil, 975 } 976 977 log := scope.RestoreTemporaryTable(UncommittedViews) 978 979 if !BlockScopeListEqual(scope.Blocks, expect.Blocks) { 980 t.Errorf("Restore: blocks = %v, want %v", scope.Blocks, expect.Blocks) 981 } 982 983 if reflect.DeepEqual(log, expectOut) { 984 t.Errorf("Restore: log = %s, want %s", log, expectOut) 985 } 986 } 987 988 var referenceScopeDisposeCursorTests = []struct { 989 Name string 990 CurName parser.Identifier 991 Result *ReferenceScope 992 Error string 993 }{ 994 { 995 Name: "ReferenceScope DisposeCursor", 996 CurName: parser.Identifier{Literal: "cur"}, 997 Result: GenerateReferenceScope([]map[string]map[string]interface{}{ 998 { 999 scopeNameCursors: { 1000 "PCUR": &Cursor{ 1001 view: &View{ 1002 Header: NewHeader("", []string{"c1"}), 1003 RecordSet: RecordSet{ 1004 NewRecord([]value.Primary{value.NewInteger(1)}), 1005 NewRecord([]value.Primary{value.NewInteger(2)}), 1006 }, 1007 }, 1008 index: -1, 1009 isPseudo: true, 1010 mtx: &sync.Mutex{}, 1011 }, 1012 }, 1013 }, 1014 }, nil, time.Time{}, nil), 1015 }, 1016 { 1017 Name: "ReferenceScope DisposeCursor Pseudo Cursor Error", 1018 CurName: parser.Identifier{Literal: "pcur"}, 1019 Error: "cursor pcur is a pseudo cursor", 1020 }, 1021 { 1022 Name: "ReferenceScope DisposeCursor Undeclared Error", 1023 CurName: parser.Identifier{Literal: "notexist"}, 1024 Error: "cursor notexist is undeclared", 1025 }, 1026 } 1027 1028 func TestReferenceScope_DisposeCursor(t *testing.T) { 1029 scope := GenerateReferenceScope([]map[string]map[string]interface{}{ 1030 { 1031 scopeNameCursors: { 1032 "PCUR": &Cursor{ 1033 view: &View{ 1034 Header: NewHeader("", []string{"c1"}), 1035 RecordSet: RecordSet{ 1036 NewRecord([]value.Primary{value.NewInteger(1)}), 1037 NewRecord([]value.Primary{value.NewInteger(2)}), 1038 }, 1039 }, 1040 index: -1, 1041 isPseudo: true, 1042 mtx: &sync.Mutex{}, 1043 }, 1044 "CUR": &Cursor{ 1045 query: selectQueryForCursorTest, 1046 mtx: &sync.Mutex{}, 1047 }, 1048 }, 1049 }, 1050 }, nil, time.Time{}, nil) 1051 1052 for _, v := range referenceScopeDisposeCursorTests { 1053 err := scope.DisposeCursor(v.CurName) 1054 if err != nil { 1055 if len(v.Error) < 1 { 1056 t.Errorf("%s: unexpected error %q", v.Name, err) 1057 } else if err.Error() != v.Error { 1058 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 1059 } 1060 continue 1061 } 1062 if 0 < len(v.Error) { 1063 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 1064 continue 1065 } 1066 if !BlockScopeListEqual(scope.Blocks, v.Result.Blocks) { 1067 t.Errorf("%s: blocks = %v, want %v", v.Name, scope.Blocks, v.Result.Blocks) 1068 } 1069 } 1070 } 1071 1072 var referenceScopeOpenCursorTests = []struct { 1073 Name string 1074 CurName parser.Identifier 1075 CurValues []parser.ReplaceValue 1076 Result *ReferenceScope 1077 Error string 1078 }{ 1079 { 1080 Name: "ReferenceScope OpenCursor", 1081 CurName: parser.Identifier{Literal: "cur"}, 1082 Result: GenerateReferenceScope([]map[string]map[string]interface{}{ 1083 { 1084 scopeNameCursors: { 1085 "PCUR": &Cursor{ 1086 view: &View{ 1087 Header: NewHeader("", []string{"c1"}), 1088 RecordSet: RecordSet{ 1089 NewRecord([]value.Primary{value.NewInteger(1)}), 1090 NewRecord([]value.Primary{value.NewInteger(2)}), 1091 }, 1092 }, 1093 index: -1, 1094 isPseudo: true, 1095 mtx: &sync.Mutex{}, 1096 }, 1097 "CUR": &Cursor{ 1098 query: selectQueryForCursorTest, 1099 view: &View{ 1100 Header: NewHeader("table1", []string{"column1", "column2"}), 1101 RecordSet: []Record{ 1102 NewRecord([]value.Primary{ 1103 value.NewString("1"), 1104 value.NewString("str1"), 1105 }), 1106 NewRecord([]value.Primary{ 1107 value.NewString("2"), 1108 value.NewString("str2"), 1109 }), 1110 NewRecord([]value.Primary{ 1111 value.NewString("3"), 1112 value.NewString("str3"), 1113 }), 1114 }, 1115 FileInfo: &FileInfo{ 1116 Path: GetTestFilePath("table1.csv"), 1117 Delimiter: ',', 1118 NoHeader: false, 1119 Encoding: text.UTF8, 1120 LineBreak: text.LF, 1121 }, 1122 }, 1123 index: -1, 1124 mtx: &sync.Mutex{}, 1125 }, 1126 }, 1127 }, 1128 }, nil, time.Time{}, nil), 1129 }, 1130 { 1131 Name: "ReferenceScope OpenCursor Undeclared Error", 1132 CurName: parser.Identifier{Literal: "notexist"}, 1133 Error: "cursor notexist is undeclared", 1134 }, 1135 { 1136 Name: "ReferenceScope OpenCursor Open Error", 1137 CurName: parser.Identifier{Literal: "cur"}, 1138 Error: "cursor cur is already open", 1139 }, 1140 { 1141 Name: "ReferenceScope OpenCursor Pseudo Cursor Error", 1142 CurName: parser.Identifier{Literal: "pcur"}, 1143 Error: "cursor pcur is a pseudo cursor", 1144 }, 1145 } 1146 1147 func TestReferenceScope_OpenCursor(t *testing.T) { 1148 defer func() { 1149 _ = TestTx.CachedViews.Clean(TestTx.FileContainer) 1150 initFlag(TestTx.Flags) 1151 }() 1152 1153 TestTx.Flags.Repository = TestDir 1154 1155 scope := GenerateReferenceScope([]map[string]map[string]interface{}{ 1156 { 1157 scopeNameCursors: { 1158 "PCUR": &Cursor{ 1159 view: &View{ 1160 Header: NewHeader("", []string{"c1"}), 1161 RecordSet: RecordSet{ 1162 NewRecord([]value.Primary{value.NewInteger(1)}), 1163 NewRecord([]value.Primary{value.NewInteger(2)}), 1164 }, 1165 }, 1166 index: -1, 1167 isPseudo: true, 1168 mtx: &sync.Mutex{}, 1169 }, 1170 "CUR": &Cursor{ 1171 query: selectQueryForCursorTest, 1172 mtx: &sync.Mutex{}, 1173 }, 1174 }, 1175 }, 1176 }, nil, time.Time{}, nil) 1177 1178 for _, v := range referenceScopeOpenCursorTests { 1179 _ = TestTx.CachedViews.Clean(TestTx.FileContainer) 1180 1181 err := scope.OpenCursor(context.Background(), v.CurName, v.CurValues) 1182 if err != nil { 1183 if len(v.Error) < 1 { 1184 t.Errorf("%s: unexpected error %q", v.Name, err) 1185 } else if err.Error() != v.Error { 1186 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 1187 } 1188 continue 1189 } 1190 if 0 < len(v.Error) { 1191 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 1192 continue 1193 } 1194 if !BlockScopeListEqual(scope.Blocks, v.Result.Blocks) { 1195 t.Errorf("%s: blocks = %v, want %v", v.Name, scope.Blocks, v.Result.Blocks) 1196 } 1197 } 1198 } 1199 1200 var referenceScopeCloseCursorTests = []struct { 1201 Name string 1202 CurName parser.Identifier 1203 Result *ReferenceScope 1204 Error string 1205 }{ 1206 { 1207 Name: "ReferenceScope CloseCursor", 1208 CurName: parser.Identifier{Literal: "cur"}, 1209 Result: GenerateReferenceScope([]map[string]map[string]interface{}{ 1210 { 1211 scopeNameCursors: { 1212 "PCUR": &Cursor{ 1213 view: &View{ 1214 Header: NewHeader("", []string{"c1"}), 1215 RecordSet: RecordSet{ 1216 NewRecord([]value.Primary{value.NewInteger(1)}), 1217 NewRecord([]value.Primary{value.NewInteger(2)}), 1218 }, 1219 }, 1220 index: -1, 1221 isPseudo: true, 1222 mtx: &sync.Mutex{}, 1223 }, 1224 "CUR": &Cursor{ 1225 query: selectQueryForCursorTest, 1226 mtx: &sync.Mutex{}, 1227 }, 1228 }, 1229 }, 1230 }, nil, time.Time{}, nil), 1231 }, 1232 { 1233 Name: "ReferenceScope CloseCursor Pseudo Cursor Error", 1234 CurName: parser.Identifier{Literal: "pcur"}, 1235 Error: "cursor pcur is a pseudo cursor", 1236 }, 1237 { 1238 Name: "ReferenceScope CloseCursor Undeclared Error", 1239 CurName: parser.Identifier{Literal: "notexist"}, 1240 Error: "cursor notexist is undeclared", 1241 }, 1242 } 1243 1244 func TestReferenceScope_CloseCursor(t *testing.T) { 1245 defer func() { 1246 _ = TestTx.CachedViews.Clean(TestTx.FileContainer) 1247 initFlag(TestTx.Flags) 1248 }() 1249 1250 TestTx.Flags.Repository = TestDir 1251 1252 scope := GenerateReferenceScope([]map[string]map[string]interface{}{ 1253 { 1254 scopeNameCursors: { 1255 "PCUR": &Cursor{ 1256 view: &View{ 1257 Header: NewHeader("", []string{"c1"}), 1258 RecordSet: RecordSet{ 1259 NewRecord([]value.Primary{value.NewInteger(1)}), 1260 NewRecord([]value.Primary{value.NewInteger(2)}), 1261 }, 1262 }, 1263 index: -1, 1264 isPseudo: true, 1265 mtx: &sync.Mutex{}, 1266 }, 1267 "CUR": &Cursor{ 1268 query: selectQueryForCursorTest, 1269 view: &View{ 1270 Header: NewHeader("table1", []string{"column1", "column2"}), 1271 RecordSet: []Record{ 1272 NewRecord([]value.Primary{ 1273 value.NewString("1"), 1274 value.NewString("str1"), 1275 }), 1276 NewRecord([]value.Primary{ 1277 value.NewString("2"), 1278 value.NewString("str2"), 1279 }), 1280 NewRecord([]value.Primary{ 1281 value.NewString("3"), 1282 value.NewString("str3"), 1283 }), 1284 }, 1285 FileInfo: &FileInfo{ 1286 Path: GetTestFilePath("table1.csv"), 1287 Delimiter: ',', 1288 NoHeader: false, 1289 Encoding: text.UTF8, 1290 LineBreak: text.LF, 1291 }, 1292 }, 1293 index: -1, 1294 mtx: &sync.Mutex{}, 1295 }, 1296 }, 1297 }, 1298 }, nil, time.Time{}, nil) 1299 1300 for _, v := range referenceScopeCloseCursorTests { 1301 err := scope.CloseCursor(v.CurName) 1302 if err != nil { 1303 if len(v.Error) < 1 { 1304 t.Errorf("%s: unexpected error %q", v.Name, err) 1305 } else if err.Error() != v.Error { 1306 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 1307 } 1308 continue 1309 } 1310 if 0 < len(v.Error) { 1311 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 1312 continue 1313 } 1314 if !BlockScopeListEqual(scope.Blocks, v.Result.Blocks) { 1315 t.Errorf("%s: blocks = %v, want %v", v.Name, scope.Blocks, v.Result.Blocks) 1316 } 1317 } 1318 }