github.com/mithrandie/csvq@v1.18.1/lib/query/built_in_command_test.go (about) 1 package query 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path/filepath" 8 "reflect" 9 "runtime" 10 "strconv" 11 "strings" 12 "sync" 13 "testing" 14 "time" 15 16 "github.com/mithrandie/csvq/lib/option" 17 "github.com/mithrandie/csvq/lib/parser" 18 "github.com/mithrandie/csvq/lib/syntax" 19 "github.com/mithrandie/csvq/lib/value" 20 21 "github.com/mithrandie/go-text" 22 "github.com/mithrandie/go-text/fixedlen" 23 "github.com/mithrandie/go-text/json" 24 ) 25 26 var echoTests = []struct { 27 Name string 28 Expr parser.Echo 29 Result string 30 Error string 31 }{ 32 { 33 Name: "Echo", 34 Expr: parser.Echo{ 35 Value: parser.NewStringValue("var"), 36 }, 37 Result: "var", 38 }, 39 { 40 Name: "Echo Evaluate Error", 41 Expr: parser.Echo{ 42 Value: parser.Variable{ 43 Name: "var", 44 }, 45 }, 46 Error: "variable @var is undeclared", 47 }, 48 } 49 50 func TestEcho(t *testing.T) { 51 scope := NewReferenceScope(TestTx) 52 53 for _, v := range echoTests { 54 result, err := Echo(context.Background(), scope, v.Expr) 55 if err != nil { 56 if len(v.Error) < 1 { 57 t.Errorf("%s: unexpected error %q", v.Name, err) 58 } else if err.Error() != v.Error { 59 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 60 } 61 continue 62 } 63 if 0 < len(v.Error) { 64 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 65 continue 66 } 67 if result != v.Result { 68 t.Errorf("%s: result = %q, want %q", v.Name, result, v.Result) 69 } 70 } 71 } 72 73 var printTests = []struct { 74 Name string 75 Expr parser.Print 76 Result string 77 Error string 78 }{ 79 { 80 Name: "Print", 81 Expr: parser.Print{ 82 Value: parser.NewStringValue("foo"), 83 }, 84 Result: "'foo'", 85 }, 86 { 87 Name: "Print Error", 88 Expr: parser.Print{ 89 Value: parser.Variable{ 90 Name: "var", 91 }, 92 }, 93 Error: "variable @var is undeclared", 94 }, 95 } 96 97 func TestPrint(t *testing.T) { 98 scope := NewReferenceScope(TestTx) 99 100 for _, v := range printTests { 101 result, err := Print(context.Background(), scope, v.Expr) 102 if err != nil { 103 if len(v.Error) < 1 { 104 t.Errorf("%s: unexpected error %q", v.Name, err) 105 } else if err.Error() != v.Error { 106 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 107 } 108 continue 109 } 110 if 0 < len(v.Error) { 111 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 112 continue 113 } 114 if result != v.Result { 115 t.Errorf("%s: result = %q, want %q", v.Name, result, v.Result) 116 } 117 } 118 } 119 120 var printfTests = []struct { 121 Name string 122 Expr parser.Printf 123 Result string 124 Error string 125 }{ 126 { 127 Name: "Printf", 128 Expr: parser.Printf{ 129 Format: parser.NewStringValue("printf test: value1 %q, value2 %q"), 130 Values: []parser.QueryExpression{ 131 parser.NewStringValue("str"), 132 parser.NewIntegerValue(1), 133 }, 134 }, 135 Result: "printf test: value1 'str', value2 '1'", 136 }, 137 { 138 Name: "Printf Format Error", 139 Expr: parser.Printf{ 140 Format: parser.Variable{Name: "var"}, 141 Values: []parser.QueryExpression{ 142 parser.NewStringValue("str"), 143 parser.NewIntegerValue(1), 144 }, 145 }, 146 Error: "variable @var is undeclared", 147 }, 148 { 149 Name: "Printf Evaluate Error", 150 Expr: parser.Printf{ 151 Format: parser.NewStringValue("printf test: value1 %s"), 152 Values: []parser.QueryExpression{ 153 parser.Variable{ 154 Name: "var", 155 }, 156 }, 157 }, 158 Error: "variable @var is undeclared", 159 }, 160 { 161 Name: "Printf Less Values Error", 162 Expr: parser.Printf{ 163 Format: parser.NewStringValue("printf test: value1 %s, value2 %s %%"), 164 Values: []parser.QueryExpression{ 165 parser.NewStringValue("str"), 166 }, 167 }, 168 Error: "number of replace values does not match", 169 }, 170 { 171 Name: "Printf Greater Values Error", 172 Expr: parser.Printf{ 173 Format: parser.NewStringValue("printf test: value1 %s, value2 %s %%"), 174 Values: []parser.QueryExpression{ 175 parser.NewStringValue("str"), 176 parser.NewIntegerValue(1), 177 parser.NewIntegerValue(2), 178 }, 179 }, 180 Error: "number of replace values does not match", 181 }, 182 } 183 184 func TestPrintf(t *testing.T) { 185 scope := NewReferenceScope(TestTx) 186 187 for _, v := range printfTests { 188 result, err := Printf(context.Background(), scope, v.Expr) 189 if err != nil { 190 if len(v.Error) < 1 { 191 t.Errorf("%s: unexpected error %q", v.Name, err) 192 } else if err.Error() != v.Error { 193 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 194 } 195 continue 196 } 197 if 0 < len(v.Error) { 198 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 199 continue 200 } 201 if result != v.Result { 202 t.Errorf("%s: result = %q, want %q", v.Name, result, v.Result) 203 } 204 } 205 } 206 207 var sourceTests = []struct { 208 Name string 209 Expr parser.Source 210 Result []parser.Statement 211 Error string 212 }{ 213 { 214 Name: "Source", 215 Expr: parser.Source{ 216 FilePath: parser.NewStringValue(GetTestFilePath("source.sql")), 217 }, 218 Result: []parser.Statement{ 219 parser.Print{ 220 Value: parser.NewStringValue("external executable file"), 221 }, 222 }, 223 }, 224 { 225 Name: "Source from an identifier", 226 Expr: parser.Source{ 227 FilePath: parser.Identifier{Literal: GetTestFilePath("source.sql")}, 228 }, 229 Result: []parser.Statement{ 230 parser.Print{ 231 Value: parser.NewStringValue("external executable file"), 232 }, 233 }, 234 }, 235 { 236 Name: "Source File Argument Evaluation Error", 237 Expr: parser.Source{ 238 FilePath: parser.FieldReference{Column: parser.Identifier{Literal: "ident"}}, 239 }, 240 Error: "field ident does not exist", 241 }, 242 { 243 Name: "Source File Invalid File Path Error", 244 Expr: parser.Source{ 245 FilePath: parser.NewNullValue(), 246 }, 247 Error: "NULL is a invalid file path", 248 }, 249 { 250 Name: "Source File Empty File Path Error", 251 Expr: parser.Source{ 252 FilePath: parser.Identifier{Literal: "", Quoted: true}, 253 }, 254 Error: "`` is a invalid file path", 255 }, 256 { 257 Name: "Source File Not Exist Error", 258 Expr: parser.Source{ 259 FilePath: parser.NewStringValue(GetTestFilePath("notexist.sql")), 260 }, 261 Error: fmt.Sprintf("file %s does not exist", GetTestFilePath("notexist.sql")), 262 }, 263 { 264 Name: "Source Syntax Error", 265 Expr: parser.Source{ 266 FilePath: parser.NewStringValue(GetTestFilePath("source_syntaxerror.sql")), 267 }, 268 Error: fmt.Sprintf("%s [L:1 C:34] syntax error: unexpected token \"wrong argument\"", GetTestFilePath("source_syntaxerror.sql")), 269 }, 270 } 271 272 func TestSource(t *testing.T) { 273 scope := NewReferenceScope(TestTx) 274 275 for _, v := range sourceTests { 276 result, err := Source(context.Background(), scope, v.Expr) 277 if err != nil { 278 if len(v.Error) < 1 { 279 t.Errorf("%s: unexpected error %q", v.Name, err) 280 } else if err.Error() != v.Error { 281 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 282 } 283 continue 284 } 285 if 0 < len(v.Error) { 286 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 287 continue 288 } 289 if !reflect.DeepEqual(result, v.Result) { 290 t.Errorf("%s: result = %q, want %q", v.Name, result, v.Result) 291 } 292 } 293 } 294 295 var parseExecuteStatementsTests = []struct { 296 Name string 297 Expr parser.Execute 298 Result []parser.Statement 299 Error string 300 }{ 301 { 302 Name: "ParseExecuteStatements", 303 Expr: parser.Execute{ 304 BaseExpr: parser.NewBaseExpr(parser.Token{}), 305 Statements: parser.NewStringValue("print %q;"), 306 Values: []parser.QueryExpression{ 307 parser.NewStringValue("executable string"), 308 }, 309 }, 310 Result: []parser.Statement{ 311 parser.Print{ 312 Value: parser.NewStringValue("executable string"), 313 }, 314 }, 315 }, 316 { 317 Name: "ParseExecuteStatements String Evaluation Error", 318 Expr: parser.Execute{ 319 BaseExpr: parser.NewBaseExpr(parser.Token{}), 320 Statements: parser.FieldReference{Column: parser.Identifier{Literal: "notexist"}}, 321 Values: []parser.QueryExpression{ 322 parser.NewStringValue("executable string"), 323 }, 324 }, 325 Error: "field notexist does not exist", 326 }, 327 { 328 Name: "ParseExecuteStatements Format Error", 329 Expr: parser.Execute{ 330 BaseExpr: parser.NewBaseExpr(parser.Token{}), 331 Statements: parser.NewStringValue("print %q;"), 332 }, 333 Error: "number of replace values does not match", 334 }, 335 { 336 Name: "ParseExecuteStatements Replace Value Error", 337 Expr: parser.Execute{ 338 BaseExpr: parser.NewBaseExpr(parser.Token{}), 339 Statements: parser.NewStringValue("print %q;"), 340 Values: []parser.QueryExpression{ 341 parser.FieldReference{Column: parser.Identifier{Literal: "notexist"}}, 342 }, 343 }, 344 Error: "field notexist does not exist", 345 }, 346 { 347 Name: "ParseExecuteStatements Parsing Error", 348 Expr: parser.Execute{ 349 BaseExpr: parser.NewBaseExpr(parser.Token{}), 350 Statements: parser.NewStringValue("print;"), 351 }, 352 Error: "(L:0 C:0) EXECUTE [L:1 C:6] syntax error: unexpected token \";\"", 353 }, 354 } 355 356 func TestParseExecuteStatements(t *testing.T) { 357 scope := NewReferenceScope(TestTx) 358 359 for _, v := range parseExecuteStatementsTests { 360 result, err := ParseExecuteStatements(context.Background(), scope, v.Expr) 361 if err != nil { 362 if len(v.Error) < 1 { 363 t.Errorf("%s: unexpected error %q", v.Name, err) 364 } else if err.Error() != v.Error { 365 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 366 } 367 continue 368 } 369 if 0 < len(v.Error) { 370 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 371 continue 372 } 373 if !reflect.DeepEqual(result, v.Result) { 374 t.Errorf("%s: result = %q, want %q", v.Name, result, v.Result) 375 } 376 } 377 } 378 379 var setFlagTests = []struct { 380 Name string 381 Expr parser.SetFlag 382 Error string 383 }{ 384 { 385 Name: "Set Repository", 386 Expr: parser.SetFlag{ 387 Flag: parser.Flag{Name: "repository"}, 388 Value: parser.NewStringValue(TestDir), 389 }, 390 }, 391 { 392 Name: "Set Timezone", 393 Expr: parser.SetFlag{ 394 Flag: parser.Flag{Name: "timezone"}, 395 Value: parser.NewStringValue("utc"), 396 }, 397 }, 398 { 399 Name: "Set DatetimeFormat", 400 Expr: parser.SetFlag{ 401 Flag: parser.Flag{Name: "datetime_format"}, 402 Value: parser.NewStringValue("%Y%m%d"), 403 }, 404 }, 405 { 406 Name: "Set AnsiQuotes", 407 Expr: parser.SetFlag{ 408 Flag: parser.Flag{Name: "ansi_quotes"}, 409 Value: parser.NewTernaryValueFromString("true"), 410 }, 411 }, 412 { 413 Name: "Set StrictEqual", 414 Expr: parser.SetFlag{ 415 Flag: parser.Flag{Name: "strict_equal"}, 416 Value: parser.NewTernaryValueFromString("true"), 417 }, 418 }, 419 { 420 Name: "Set WaitTimeout", 421 Expr: parser.SetFlag{ 422 Flag: parser.Flag{Name: "wait_timeout"}, 423 Value: parser.NewFloatValue(15), 424 }, 425 }, 426 { 427 Name: "Set Delimiter", 428 Expr: parser.SetFlag{ 429 Flag: parser.Flag{Name: "delimiter"}, 430 Value: parser.NewStringValue("\\t"), 431 }, 432 }, 433 { 434 Name: "Set AllowUnevenFields", 435 Expr: parser.SetFlag{ 436 Flag: parser.Flag{Name: "allow_uneven_fields"}, 437 Value: parser.NewTernaryValueFromString("true"), 438 }, 439 }, 440 { 441 Name: "Set JsonQuery", 442 Expr: parser.SetFlag{ 443 Flag: parser.Flag{Name: "json_query"}, 444 Value: parser.NewStringValue("{}"), 445 }, 446 }, 447 { 448 Name: "Set Encoding", 449 Expr: parser.SetFlag{ 450 Flag: parser.Flag{Name: "encoding"}, 451 Value: parser.NewStringValue("SJIS"), 452 }, 453 }, 454 { 455 Name: "Set NoHeader", 456 Expr: parser.SetFlag{ 457 Flag: parser.Flag{Name: "no_header"}, 458 Value: parser.NewTernaryValueFromString("true"), 459 }, 460 }, 461 { 462 Name: "Set WithoutNull", 463 Expr: parser.SetFlag{ 464 Flag: parser.Flag{Name: "without_null"}, 465 Value: parser.NewTernaryValueFromString("true"), 466 }, 467 }, 468 { 469 Name: "Set Format", 470 Expr: parser.SetFlag{ 471 Flag: parser.Flag{Name: "format"}, 472 Value: parser.NewStringValue("json"), 473 }, 474 }, 475 { 476 Name: "Set WriteEncoding", 477 Expr: parser.SetFlag{ 478 Flag: parser.Flag{Name: "write_encoding"}, 479 Value: parser.NewStringValue("SJIS"), 480 }, 481 }, 482 { 483 Name: "Set WriteDelimiter", 484 Expr: parser.SetFlag{ 485 Flag: parser.Flag{Name: "write_delimiter"}, 486 Value: parser.NewStringValue("\\t"), 487 }, 488 }, 489 { 490 Name: "Set WithoutHeader", 491 Expr: parser.SetFlag{ 492 Flag: parser.Flag{Name: "without_header"}, 493 Value: parser.NewTernaryValueFromString("true"), 494 }, 495 }, 496 { 497 Name: "Set lineBreak", 498 Expr: parser.SetFlag{ 499 Flag: parser.Flag{Name: "line_break"}, 500 Value: parser.NewStringValue("CRLF"), 501 }, 502 }, 503 { 504 Name: "Set EncloseAll", 505 Expr: parser.SetFlag{ 506 Flag: parser.Flag{Name: "enclose_all"}, 507 Value: parser.NewTernaryValueFromString("true"), 508 }, 509 }, 510 { 511 Name: "Set JsonEscape", 512 Expr: parser.SetFlag{ 513 Flag: parser.Flag{Name: "json_escape"}, 514 Value: parser.NewStringValue("hex"), 515 }, 516 }, 517 { 518 Name: "Set PrettyPrint", 519 Expr: parser.SetFlag{ 520 Flag: parser.Flag{Name: "pretty_print"}, 521 Value: parser.NewTernaryValueFromString("true"), 522 }, 523 }, 524 { 525 Name: "Set Scientific Notation", 526 Expr: parser.SetFlag{ 527 Flag: parser.Flag{Name: "scientific_notation"}, 528 Value: parser.NewTernaryValueFromString("true"), 529 }, 530 }, 531 { 532 Name: "Set Strip Ending Line Break", 533 Expr: parser.SetFlag{ 534 Flag: parser.Flag{Name: "strip_ending_line_break"}, 535 Value: parser.NewTernaryValueFromString("true"), 536 }, 537 }, 538 { 539 Name: "Set EastAsianEncoding", 540 Expr: parser.SetFlag{ 541 Flag: parser.Flag{Name: "east_asian_encoding"}, 542 Value: parser.NewTernaryValueFromString("true"), 543 }, 544 }, 545 { 546 Name: "Set CountDiacriticalSign", 547 Expr: parser.SetFlag{ 548 Flag: parser.Flag{Name: "count_diacritical_sign"}, 549 Value: parser.NewTernaryValueFromString("true"), 550 }, 551 }, 552 { 553 Name: "Set CountFormatCode", 554 Expr: parser.SetFlag{ 555 Flag: parser.Flag{Name: "count_format_code"}, 556 Value: parser.NewTernaryValueFromString("true"), 557 }, 558 }, 559 { 560 Name: "Set Color", 561 Expr: parser.SetFlag{ 562 Flag: parser.Flag{Name: "color"}, 563 Value: parser.NewTernaryValueFromString("true"), 564 }, 565 }, 566 { 567 Name: "Set Quiet", 568 Expr: parser.SetFlag{ 569 Flag: parser.Flag{Name: "quiet"}, 570 Value: parser.NewTernaryValueFromString("true"), 571 }, 572 }, 573 { 574 Name: "Set LimitRecursion", 575 Expr: parser.SetFlag{ 576 Flag: parser.Flag{Name: "limit_recursion"}, 577 Value: parser.NewIntegerValue(int64(10)), 578 }, 579 }, 580 { 581 Name: "Set CPU", 582 Expr: parser.SetFlag{ 583 Flag: parser.Flag{Name: "cpu"}, 584 Value: parser.NewIntegerValue(int64(runtime.NumCPU())), 585 }, 586 }, 587 { 588 Name: "Set Stats", 589 Expr: parser.SetFlag{ 590 Flag: parser.Flag{Name: "stats"}, 591 Value: parser.NewTernaryValueFromString("true"), 592 }, 593 }, 594 { 595 Name: "Set Encoding with Identifier", 596 Expr: parser.SetFlag{ 597 Flag: parser.Flag{Name: "encoding"}, 598 Value: parser.Identifier{Literal: "sjis"}, 599 }, 600 }, 601 { 602 Name: "Set Delimiter Evaluation Error", 603 Expr: parser.SetFlag{ 604 Flag: parser.Flag{Name: "delimiter"}, 605 Value: parser.FieldReference{Column: parser.Identifier{Literal: "err"}}, 606 }, 607 Error: "field err does not exist", 608 }, 609 { 610 Name: "Set Delimiter Value Error", 611 Expr: parser.SetFlag{ 612 Flag: parser.Flag{Name: "delimiter"}, 613 Value: parser.NewTernaryValueFromString("true"), 614 }, 615 Error: "TRUE for @@DELIMITER is not allowed", 616 }, 617 { 618 Name: "Set WaitTimeout Value Error", 619 Expr: parser.SetFlag{ 620 Flag: parser.Flag{Name: "wait_timeout"}, 621 Value: parser.NewTernaryValueFromString("true"), 622 }, 623 Error: "TRUE for @@WAIT_TIMEOUT is not allowed", 624 }, 625 { 626 Name: "Set WithoutNull Value Error", 627 Expr: parser.SetFlag{ 628 Flag: parser.Flag{Name: "without_null"}, 629 Value: parser.NewStringValue("string"), 630 }, 631 Error: "'string' for @@WITHOUT_NULL is not allowed", 632 }, 633 { 634 Name: "Set CPU Value Error", 635 Expr: parser.SetFlag{ 636 Flag: parser.Flag{Name: "cpu"}, 637 Value: parser.NewStringValue("invalid"), 638 }, 639 Error: "'invalid' for @@CPU is not allowed", 640 }, 641 { 642 Name: "Invalid Flag Name Error", 643 Expr: parser.SetFlag{ 644 Flag: parser.Flag{Name: "invalid"}, 645 Value: parser.NewStringValue("string"), 646 }, 647 Error: "@@INVALID is an unknown flag", 648 }, 649 { 650 Name: "Invalid Flag Value Error", 651 Expr: parser.SetFlag{ 652 Flag: parser.Flag{Name: "line_break"}, 653 Value: parser.NewStringValue("invalid"), 654 }, 655 Error: "line-break must be one of CRLF|CR|LF", 656 }, 657 } 658 659 func TestSetFlag(t *testing.T) { 660 defer initFlag(TestTx.Flags) 661 662 ctx := context.Background() 663 scope := NewReferenceScope(TestTx) 664 665 for _, v := range setFlagTests { 666 initFlag(TestTx.Flags) 667 err := SetFlag(ctx, scope, v.Expr) 668 if err != nil { 669 if len(v.Error) < 1 { 670 t.Errorf("%s: unexpected error %q", v.Name, err) 671 } else if err.Error() != v.Error { 672 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 673 } 674 continue 675 } 676 if 0 < len(v.Error) { 677 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 678 continue 679 } 680 } 681 } 682 683 var addFlagElementTests = []struct { 684 Name string 685 Expr parser.AddFlagElement 686 Init func(*option.Flags) 687 Expect func() *option.Flags 688 Error string 689 }{ 690 { 691 Name: "Add Element To DatetimeFormat", 692 Expr: parser.AddFlagElement{ 693 Flag: parser.Flag{Name: "datetime_format"}, 694 Value: parser.NewStringValue("%Y%m%d"), 695 }, 696 Init: func(flags *option.Flags) { 697 flags.DatetimeFormat = []string{"%Y:%m:%d"} 698 }, 699 Expect: func() *option.Flags { 700 expect := new(option.Flags) 701 initFlag(expect) 702 expect.DatetimeFormat = []string{"%Y:%m:%d", "%Y%m%d"} 703 return expect 704 }, 705 }, 706 { 707 Name: "Add Element Unsupported Flag Name", 708 Expr: parser.AddFlagElement{ 709 Flag: parser.Flag{Name: "format"}, 710 Value: parser.NewStringValue("%Y%m%d"), 711 }, 712 Init: func(flags *option.Flags) { 713 flags.DatetimeFormat = []string{"%Y:%m:%d"} 714 }, 715 Error: "add flag element syntax does not support @@FORMAT", 716 }, 717 { 718 Name: "Add Element Invalid Flag Name", 719 Expr: parser.AddFlagElement{ 720 Flag: parser.Flag{Name: "invalid"}, 721 Value: parser.NewStringValue("%Y%m%d"), 722 }, 723 Init: func(flags *option.Flags) { 724 flags.DatetimeFormat = []string{"%Y:%m:%d"} 725 }, 726 Error: "@@INVALID is an unknown flag", 727 }, 728 } 729 730 func TestAddFlagElement(t *testing.T) { 731 defer initFlag(TestTx.Flags) 732 733 ctx := context.Background() 734 scope := NewReferenceScope(TestTx) 735 736 for _, v := range addFlagElementTests { 737 initFlag(TestTx.Flags) 738 v.Init(TestTx.Flags) 739 740 err := AddFlagElement(ctx, scope, v.Expr) 741 if err != nil { 742 if len(v.Error) < 1 { 743 t.Errorf("%s: unexpected error %q", v.Name, err) 744 } else if err.Error() != v.Error { 745 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 746 } 747 continue 748 } 749 if 0 < len(v.Error) { 750 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 751 continue 752 } 753 754 expect := v.Expect() 755 if !reflect.DeepEqual(TestTx.Flags, expect) { 756 t.Errorf("%s: result = %v, want %v", v.Name, TestTx.Flags, expect) 757 } 758 } 759 } 760 761 var removeFlagElementTests = []struct { 762 Name string 763 Expr parser.RemoveFlagElement 764 Init func(*option.Flags) 765 Expect func() *option.Flags 766 Error string 767 }{ 768 { 769 Name: "Remove Element from DatetimeFormat", 770 Expr: parser.RemoveFlagElement{ 771 Flag: parser.Flag{Name: "datetime_format"}, 772 Value: parser.NewStringValue("%Y%m%d"), 773 }, 774 Init: func(flags *option.Flags) { 775 flags.DatetimeFormat = []string{"%Y%m%d", "%Y:%m:%d"} 776 }, 777 Expect: func() *option.Flags { 778 expect := new(option.Flags) 779 initFlag(expect) 780 expect.DatetimeFormat = []string{"%Y:%m:%d"} 781 return expect 782 }, 783 }, 784 { 785 Name: "Remove Element from DatetimeFormat with List Index", 786 Expr: parser.RemoveFlagElement{ 787 Flag: parser.Flag{Name: "datetime_format"}, 788 Value: parser.NewIntegerValue(1), 789 }, 790 Init: func(flags *option.Flags) { 791 flags.DatetimeFormat = []string{"%Y%m%d", "%Y:%m:%d"} 792 }, 793 Expect: func() *option.Flags { 794 expect := new(option.Flags) 795 initFlag(expect) 796 expect.DatetimeFormat = []string{"%Y%m%d"} 797 return expect 798 }, 799 }, 800 { 801 Name: "Remove Element Invalid Flag Value", 802 Expr: parser.RemoveFlagElement{ 803 Flag: parser.Flag{Name: "datetime_format"}, 804 Value: parser.NewNullValue(), 805 }, 806 Init: func(flags *option.Flags) {}, 807 Error: "NULL is an invalid value for @@DATETIME_FORMAT to specify the element", 808 }, 809 { 810 Name: "Remove Element Evaluation Error", 811 Expr: parser.RemoveFlagElement{ 812 Flag: parser.Flag{Name: "format"}, 813 Value: parser.FieldReference{Column: parser.Identifier{Literal: "err"}}, 814 }, 815 Init: func(flags *option.Flags) {}, 816 Error: "field err does not exist", 817 }, 818 { 819 Name: "Remove Element Unsupported Flag Name", 820 Expr: parser.RemoveFlagElement{ 821 Flag: parser.Flag{Name: "format"}, 822 Value: parser.NewIntegerValue(1), 823 }, 824 Init: func(flags *option.Flags) {}, 825 Error: "remove flag element syntax does not support @@FORMAT", 826 }, 827 { 828 Name: "Remove Element Invalid Flag Name", 829 Expr: parser.RemoveFlagElement{ 830 Flag: parser.Flag{Name: "invalid"}, 831 Value: parser.NewIntegerValue(1), 832 }, 833 Init: func(flags *option.Flags) {}, 834 Error: "@@INVALID is an unknown flag", 835 }, 836 } 837 838 func TestRemoveFlagElement(t *testing.T) { 839 defer initFlag(TestTx.Flags) 840 841 ctx := context.Background() 842 scope := NewReferenceScope(TestTx) 843 844 for _, v := range removeFlagElementTests { 845 initFlag(TestTx.Flags) 846 v.Init(TestTx.Flags) 847 848 err := RemoveFlagElement(ctx, scope, v.Expr) 849 if err != nil { 850 if len(v.Error) < 1 { 851 t.Errorf("%s: unexpected error %q", v.Name, err) 852 } else if err.Error() != v.Error { 853 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 854 } 855 continue 856 } 857 if 0 < len(v.Error) { 858 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 859 continue 860 } 861 862 expect := v.Expect() 863 if !reflect.DeepEqual(TestTx.Flags, expect) { 864 t.Errorf("%s: result = %v, want %v", v.Name, TestTx.Flags, expect) 865 } 866 } 867 } 868 869 var showFlagTests = []struct { 870 Name string 871 Expr parser.ShowFlag 872 SetExprs []parser.SetFlag 873 Result string 874 Error string 875 }{ 876 { 877 Name: "Show Repository", 878 Expr: parser.ShowFlag{ 879 Flag: parser.Flag{Name: "repository"}, 880 }, 881 SetExprs: []parser.SetFlag{ 882 { 883 Flag: parser.Flag{Name: "repository"}, 884 Value: parser.NewStringValue(TestDir), 885 }, 886 }, 887 Result: "\033[34;1m@@REPOSITORY:\033[0m \033[32m" + TestDir + "\033[0m", 888 }, 889 { 890 Name: "Show Repository Not Set", 891 Expr: parser.ShowFlag{ 892 Flag: parser.Flag{Name: "repository"}, 893 }, 894 SetExprs: []parser.SetFlag{ 895 { 896 Flag: parser.Flag{Name: "repository"}, 897 Value: parser.NewStringValue(""), 898 }, 899 }, 900 Result: "\033[34;1m@@REPOSITORY:\033[0m \033[90m(current dir: " + GetWD() + ")\033[0m", 901 }, 902 { 903 Name: "Show Timezone", 904 Expr: parser.ShowFlag{ 905 Flag: parser.Flag{Name: "timezone"}, 906 }, 907 SetExprs: []parser.SetFlag{ 908 { 909 Flag: parser.Flag{Name: "timezone"}, 910 Value: parser.NewStringValue("UTC"), 911 }, 912 }, 913 Result: "\033[34;1m@@TIMEZONE:\033[0m \033[32mUTC\033[0m", 914 }, 915 { 916 Name: "Show DatetimeFormat Not Set", 917 Expr: parser.ShowFlag{ 918 Flag: parser.Flag{Name: "datetime_format"}, 919 }, 920 Result: "\033[34;1m@@DATETIME_FORMAT:\033[0m \033[90m(not set)\033[0m", 921 }, 922 { 923 Name: "Show DatetimeFormat", 924 Expr: parser.ShowFlag{ 925 Flag: parser.Flag{Name: "datetime_format"}, 926 }, 927 SetExprs: []parser.SetFlag{ 928 { 929 Flag: parser.Flag{Name: "datetime_format"}, 930 Value: parser.NewStringValue("[\"%Y%m%d\", \"%Y%m%d %H%i%s\"]"), 931 }, 932 }, 933 Result: "\033[34;1m@@DATETIME_FORMAT:\033[0m \033[32m[\"%Y%m%d\", \"%Y%m%d %H%i%s\"]\033[0m", 934 }, 935 { 936 Name: "Show AnsiQuotes", 937 Expr: parser.ShowFlag{ 938 Flag: parser.Flag{Name: "ansi_quotes"}, 939 }, 940 SetExprs: []parser.SetFlag{ 941 { 942 Flag: parser.Flag{Name: "ansi_quotes"}, 943 Value: parser.NewTernaryValueFromString("true"), 944 }, 945 }, 946 Result: "\033[34;1m@@ANSI_QUOTES:\033[0m \033[33;1mtrue\033[0m", 947 }, 948 { 949 Name: "Show StrictEqual", 950 Expr: parser.ShowFlag{ 951 Flag: parser.Flag{Name: "strict_equal"}, 952 }, 953 SetExprs: []parser.SetFlag{ 954 { 955 Flag: parser.Flag{Name: "strict_equal"}, 956 Value: parser.NewTernaryValueFromString("true"), 957 }, 958 }, 959 Result: "\033[34;1m@@STRICT_EQUAL:\033[0m \033[33;1mtrue\033[0m", 960 }, 961 { 962 Name: "Show WaitTimeout", 963 Expr: parser.ShowFlag{ 964 Flag: parser.Flag{Name: "wait_timeout"}, 965 }, 966 SetExprs: []parser.SetFlag{ 967 { 968 Flag: parser.Flag{Name: "wait_timeout"}, 969 Value: parser.NewFloatValue(15), 970 }, 971 }, 972 Result: "\033[34;1m@@WAIT_TIMEOUT:\033[0m \033[35m15\033[0m", 973 }, 974 { 975 Name: "Show Import Format", 976 Expr: parser.ShowFlag{ 977 Flag: parser.Flag{Name: "import_format"}, 978 }, 979 SetExprs: []parser.SetFlag{ 980 { 981 Flag: parser.Flag{Name: "import_format"}, 982 Value: parser.NewStringValue("tsv"), 983 }, 984 }, 985 Result: "\033[34;1m@@IMPORT_FORMAT:\033[0m \033[32mTSV\033[0m", 986 }, 987 { 988 Name: "Show Delimiter", 989 Expr: parser.ShowFlag{ 990 Flag: parser.Flag{Name: "delimiter"}, 991 }, 992 SetExprs: []parser.SetFlag{ 993 { 994 Flag: parser.Flag{Name: "delimiter"}, 995 Value: parser.NewStringValue("\t"), 996 }, 997 }, 998 Result: "\033[34;1m@@DELIMITER:\033[0m \033[32m'\\t'\033[0m", 999 }, 1000 { 1001 Name: "Show AllowUnevenFields", 1002 Expr: parser.ShowFlag{ 1003 Flag: parser.Flag{Name: "allow_uneven_fields"}, 1004 }, 1005 SetExprs: []parser.SetFlag{ 1006 { 1007 Flag: parser.Flag{Name: "allow_uneven_fields"}, 1008 Value: parser.NewTernaryValueFromString("true"), 1009 }, 1010 }, 1011 Result: "\033[34;1m@@ALLOW_UNEVEN_FIELDS:\033[0m \033[33;1mtrue\033[0m", 1012 }, 1013 { 1014 Name: "Show Delimiter Positions", 1015 Expr: parser.ShowFlag{ 1016 Flag: parser.Flag{Name: "delimiter_positions"}, 1017 }, 1018 SetExprs: []parser.SetFlag{ 1019 { 1020 Flag: parser.Flag{Name: "delimiter_positions"}, 1021 Value: parser.NewStringValue("s[2, 5, 10]"), 1022 }, 1023 }, 1024 Result: "\033[34;1m@@DELIMITER_POSITIONS:\033[0m \033[32mS[2, 5, 10]\033[0m", 1025 }, 1026 { 1027 Name: "Show Delimiter Positions as spaces", 1028 Expr: parser.ShowFlag{ 1029 Flag: parser.Flag{Name: "delimiter_positions"}, 1030 }, 1031 SetExprs: []parser.SetFlag{ 1032 { 1033 Flag: parser.Flag{Name: "delimiter_positions"}, 1034 Value: parser.NewStringValue("SPACES"), 1035 }, 1036 }, 1037 Result: "\033[34;1m@@DELIMITER_POSITIONS:\033[0m \033[32mSPACES\033[0m", 1038 }, 1039 { 1040 Name: "Show JsonQuery", 1041 Expr: parser.ShowFlag{ 1042 Flag: parser.Flag{Name: "json_query"}, 1043 }, 1044 SetExprs: []parser.SetFlag{ 1045 { 1046 Flag: parser.Flag{Name: "json_query"}, 1047 Value: parser.NewStringValue("{}"), 1048 }, 1049 }, 1050 Result: "\033[34;1m@@JSON_QUERY:\033[0m \033[32m{}\033[0m", 1051 }, 1052 { 1053 Name: "Show JsonQuery Empty", 1054 Expr: parser.ShowFlag{ 1055 Flag: parser.Flag{Name: "json_query"}, 1056 }, 1057 SetExprs: []parser.SetFlag{}, 1058 Result: "\033[34;1m@@JSON_QUERY:\033[0m \033[90m(empty)\033[0m", 1059 }, 1060 { 1061 Name: "Show Encoding", 1062 Expr: parser.ShowFlag{ 1063 Flag: parser.Flag{Name: "encoding"}, 1064 }, 1065 SetExprs: []parser.SetFlag{ 1066 { 1067 Flag: parser.Flag{Name: "encoding"}, 1068 Value: parser.NewStringValue("SJIS"), 1069 }, 1070 }, 1071 Result: "\033[34;1m@@ENCODING:\033[0m \033[32mSJIS\033[0m", 1072 }, 1073 { 1074 Name: "Show NoHeader", 1075 Expr: parser.ShowFlag{ 1076 Flag: parser.Flag{Name: "no_header"}, 1077 }, 1078 SetExprs: []parser.SetFlag{ 1079 { 1080 Flag: parser.Flag{Name: "no_header"}, 1081 Value: parser.NewTernaryValueFromString("true"), 1082 }, 1083 }, 1084 Result: "\033[34;1m@@NO_HEADER:\033[0m \033[33;1mtrue\033[0m", 1085 }, 1086 { 1087 Name: "Show WithoutNull", 1088 Expr: parser.ShowFlag{ 1089 Flag: parser.Flag{Name: "without_null"}, 1090 }, 1091 SetExprs: []parser.SetFlag{ 1092 { 1093 Flag: parser.Flag{Name: "without_null"}, 1094 Value: parser.NewTernaryValueFromString("true"), 1095 }, 1096 }, 1097 Result: "\033[34;1m@@WITHOUT_NULL:\033[0m \033[33;1mtrue\033[0m", 1098 }, 1099 { 1100 Name: "Show Format", 1101 Expr: parser.ShowFlag{ 1102 Flag: parser.Flag{Name: "format"}, 1103 }, 1104 SetExprs: []parser.SetFlag{ 1105 { 1106 Flag: parser.Flag{Name: "format"}, 1107 Value: parser.NewStringValue("json"), 1108 }, 1109 }, 1110 Result: "\033[34;1m@@FORMAT:\033[0m \033[32mJSON\033[0m", 1111 }, 1112 { 1113 Name: "Show WriteEncoding", 1114 Expr: parser.ShowFlag{ 1115 Flag: parser.Flag{Name: "write_encoding"}, 1116 }, 1117 SetExprs: []parser.SetFlag{ 1118 { 1119 Flag: parser.Flag{Name: "write_encoding"}, 1120 Value: parser.NewStringValue("SJIS"), 1121 }, 1122 }, 1123 Result: "\033[34;1m@@WRITE_ENCODING:\033[0m \033[32mSJIS\033[0m", 1124 }, 1125 { 1126 Name: "Show WriteEncoding Ignored", 1127 Expr: parser.ShowFlag{ 1128 Flag: parser.Flag{Name: "write_encoding"}, 1129 }, 1130 SetExprs: []parser.SetFlag{ 1131 { 1132 Flag: parser.Flag{Name: "write_encoding"}, 1133 Value: parser.NewStringValue("SJIS"), 1134 }, 1135 { 1136 Flag: parser.Flag{Name: "format"}, 1137 Value: parser.NewStringValue("JSON"), 1138 }, 1139 }, 1140 Result: "\033[34;1m@@WRITE_ENCODING:\033[0m \033[90m(ignored) SJIS\033[0m", 1141 }, 1142 { 1143 Name: "Show WriteDelimiter", 1144 Expr: parser.ShowFlag{ 1145 Flag: parser.Flag{Name: "write_delimiter"}, 1146 }, 1147 SetExprs: []parser.SetFlag{ 1148 { 1149 Flag: parser.Flag{Name: "write_delimiter"}, 1150 Value: parser.NewStringValue("\t"), 1151 }, 1152 { 1153 Flag: parser.Flag{Name: "format"}, 1154 Value: parser.NewStringValue("CSV"), 1155 }, 1156 }, 1157 Result: "\033[34;1m@@WRITE_DELIMITER:\033[0m \033[32m'\\t'\033[0m", 1158 }, 1159 { 1160 Name: "Show WriteDelimiter Ignored", 1161 Expr: parser.ShowFlag{ 1162 Flag: parser.Flag{Name: "write_delimiter"}, 1163 }, 1164 SetExprs: []parser.SetFlag{ 1165 { 1166 Flag: parser.Flag{Name: "write_delimiter"}, 1167 Value: parser.NewStringValue("\t"), 1168 }, 1169 { 1170 Flag: parser.Flag{Name: "format"}, 1171 Value: parser.NewStringValue("JSON"), 1172 }, 1173 }, 1174 Result: "\033[34;1m@@WRITE_DELIMITER:\033[0m \033[90m(ignored) '\\t'\033[0m", 1175 }, 1176 { 1177 Name: "Show WriteDelimiterPositions for Single-Line FIXED", 1178 Expr: parser.ShowFlag{ 1179 Flag: parser.Flag{Name: "write_delimiter_positions"}, 1180 }, 1181 SetExprs: []parser.SetFlag{ 1182 { 1183 Flag: parser.Flag{Name: "write_delimiter_positions"}, 1184 Value: parser.NewStringValue("s[2, 5, 10]"), 1185 }, 1186 { 1187 Flag: parser.Flag{Name: "format"}, 1188 Value: parser.NewStringValue("FIXED"), 1189 }, 1190 }, 1191 Result: "\033[34;1m@@WRITE_DELIMITER_POSITIONS:\033[0m \033[32mS[2, 5, 10]\033[0m", 1192 }, 1193 { 1194 Name: "Show WriteDelimiterPositions for FIXED", 1195 Expr: parser.ShowFlag{ 1196 Flag: parser.Flag{Name: "write_delimiter_positions"}, 1197 }, 1198 SetExprs: []parser.SetFlag{ 1199 { 1200 Flag: parser.Flag{Name: "write_delimiter_positions"}, 1201 Value: parser.NewStringValue("spaces"), 1202 }, 1203 { 1204 Flag: parser.Flag{Name: "format"}, 1205 Value: parser.NewStringValue("FIXED"), 1206 }, 1207 }, 1208 Result: "\033[34;1m@@WRITE_DELIMITER_POSITIONS:\033[0m \033[32mSPACES\033[0m", 1209 }, 1210 { 1211 Name: "Show WriteDelimiterPositions Ignored", 1212 Expr: parser.ShowFlag{ 1213 Flag: parser.Flag{Name: "write_delimiter_positions"}, 1214 }, 1215 SetExprs: []parser.SetFlag{ 1216 { 1217 Flag: parser.Flag{Name: "write_delimiter_positions"}, 1218 Value: parser.NewStringValue("spaces"), 1219 }, 1220 { 1221 Flag: parser.Flag{Name: "format"}, 1222 Value: parser.NewStringValue("JSON"), 1223 }, 1224 }, 1225 Result: "\033[34;1m@@WRITE_DELIMITER_POSITIONS:\033[0m \033[90m(ignored) SPACES\033[0m", 1226 }, 1227 { 1228 Name: "Show WithoutHeader", 1229 Expr: parser.ShowFlag{ 1230 Flag: parser.Flag{Name: "without_header"}, 1231 }, 1232 SetExprs: []parser.SetFlag{ 1233 { 1234 Flag: parser.Flag{Name: "without_header"}, 1235 Value: parser.NewTernaryValueFromString("true"), 1236 }, 1237 { 1238 Flag: parser.Flag{Name: "format"}, 1239 Value: parser.NewStringValue("CSV"), 1240 }, 1241 }, 1242 Result: "\033[34;1m@@WITHOUT_HEADER:\033[0m \033[33;1mtrue\033[0m", 1243 }, 1244 { 1245 Name: "Show WithoutHeader Ignored", 1246 Expr: parser.ShowFlag{ 1247 Flag: parser.Flag{Name: "without_header"}, 1248 }, 1249 SetExprs: []parser.SetFlag{ 1250 { 1251 Flag: parser.Flag{Name: "without_header"}, 1252 Value: parser.NewTernaryValueFromString("true"), 1253 }, 1254 { 1255 Flag: parser.Flag{Name: "format"}, 1256 Value: parser.NewStringValue("JSON"), 1257 }, 1258 }, 1259 Result: "\033[34;1m@@WITHOUT_HEADER:\033[0m \033[90m(ignored) true\033[0m", 1260 }, 1261 { 1262 Name: "Show WithoutHeader with Single-Line Fixed-Length", 1263 Expr: parser.ShowFlag{ 1264 Flag: parser.Flag{Name: "without_header"}, 1265 }, 1266 SetExprs: []parser.SetFlag{ 1267 { 1268 Flag: parser.Flag{Name: "format"}, 1269 Value: parser.NewStringValue("fixed"), 1270 }, 1271 { 1272 Flag: parser.Flag{Name: "write_delimiter_positions"}, 1273 Value: parser.NewStringValue("s[2, 5, 10]"), 1274 }, 1275 { 1276 Flag: parser.Flag{Name: "without_header"}, 1277 Value: parser.NewTernaryValueFromString("true"), 1278 }, 1279 }, 1280 Result: "\033[34;1m@@WITHOUT_HEADER:\033[0m \033[90m(ignored) true\033[0m", 1281 }, 1282 { 1283 Name: "Show lineBreak", 1284 Expr: parser.ShowFlag{ 1285 Flag: parser.Flag{Name: "line_break"}, 1286 }, 1287 SetExprs: []parser.SetFlag{ 1288 { 1289 Flag: parser.Flag{Name: "line_break"}, 1290 Value: parser.NewStringValue("CRLF"), 1291 }, 1292 }, 1293 Result: "\033[34;1m@@LINE_BREAK:\033[0m \033[32mCRLF\033[0m", 1294 }, 1295 { 1296 Name: "Show lineBreak with Single-Line Fixed-Length", 1297 Expr: parser.ShowFlag{ 1298 Flag: parser.Flag{Name: "line_break"}, 1299 }, 1300 SetExprs: []parser.SetFlag{ 1301 { 1302 Flag: parser.Flag{Name: "format"}, 1303 Value: parser.NewStringValue("fixed"), 1304 }, 1305 { 1306 Flag: parser.Flag{Name: "write_delimiter_positions"}, 1307 Value: parser.NewStringValue("s[2, 5, 10]"), 1308 }, 1309 { 1310 Flag: parser.Flag{Name: "line_break"}, 1311 Value: parser.NewStringValue("CRLF"), 1312 }, 1313 }, 1314 Result: "\033[34;1m@@LINE_BREAK:\033[0m \033[90m(ignored) CRLF\033[0m", 1315 }, 1316 { 1317 Name: "Show EncloseAll", 1318 Expr: parser.ShowFlag{ 1319 Flag: parser.Flag{Name: "enclose_all"}, 1320 }, 1321 SetExprs: []parser.SetFlag{ 1322 { 1323 Flag: parser.Flag{Name: "enclose_all"}, 1324 Value: parser.NewTernaryValueFromString("true"), 1325 }, 1326 { 1327 Flag: parser.Flag{Name: "format"}, 1328 Value: parser.NewStringValue("CSV"), 1329 }, 1330 }, 1331 Result: "\033[34;1m@@ENCLOSE_ALL:\033[0m \033[33;1mtrue\033[0m", 1332 }, 1333 { 1334 Name: "Show EncloseAll Ignored", 1335 Expr: parser.ShowFlag{ 1336 Flag: parser.Flag{Name: "enclose_all"}, 1337 }, 1338 SetExprs: []parser.SetFlag{ 1339 { 1340 Flag: parser.Flag{Name: "enclose_all"}, 1341 Value: parser.NewTernaryValueFromString("true"), 1342 }, 1343 { 1344 Flag: parser.Flag{Name: "format"}, 1345 Value: parser.NewStringValue("JSON"), 1346 }, 1347 }, 1348 Result: "\033[34;1m@@ENCLOSE_ALL:\033[0m \033[90m(ignored) true\033[0m", 1349 }, 1350 { 1351 Name: "Show JsonEscape", 1352 Expr: parser.ShowFlag{ 1353 Flag: parser.Flag{Name: "json_escape"}, 1354 }, 1355 SetExprs: []parser.SetFlag{ 1356 { 1357 Flag: parser.Flag{Name: "json_escape"}, 1358 Value: parser.NewStringValue("HEXALL"), 1359 }, 1360 { 1361 Flag: parser.Flag{Name: "format"}, 1362 Value: parser.NewStringValue("JSON"), 1363 }, 1364 }, 1365 Result: "\033[34;1m@@JSON_ESCAPE:\033[0m \033[32mHEXALL\033[0m", 1366 }, 1367 { 1368 Name: "Show JsonEscape Ignored", 1369 Expr: parser.ShowFlag{ 1370 Flag: parser.Flag{Name: "json_escape"}, 1371 }, 1372 SetExprs: []parser.SetFlag{ 1373 { 1374 Flag: parser.Flag{Name: "json_escape"}, 1375 Value: parser.NewStringValue("BACKSLASH"), 1376 }, 1377 { 1378 Flag: parser.Flag{Name: "format"}, 1379 Value: parser.NewStringValue("CSV"), 1380 }, 1381 }, 1382 Result: "\033[34;1m@@JSON_ESCAPE:\033[0m \033[90m(ignored) BACKSLASH\033[0m", 1383 }, 1384 { 1385 Name: "Show PrettyPrint", 1386 Expr: parser.ShowFlag{ 1387 Flag: parser.Flag{Name: "pretty_print"}, 1388 }, 1389 SetExprs: []parser.SetFlag{ 1390 { 1391 Flag: parser.Flag{Name: "pretty_print"}, 1392 Value: parser.NewTernaryValueFromString("true"), 1393 }, 1394 { 1395 Flag: parser.Flag{Name: "format"}, 1396 Value: parser.NewStringValue("JSON"), 1397 }, 1398 }, 1399 Result: "\033[34;1m@@PRETTY_PRINT:\033[0m \033[33;1mtrue\033[0m", 1400 }, 1401 { 1402 Name: "Show Scientific Notation", 1403 Expr: parser.ShowFlag{ 1404 Flag: parser.Flag{Name: "scientific_notation"}, 1405 }, 1406 SetExprs: []parser.SetFlag{ 1407 { 1408 Flag: parser.Flag{Name: "scientific_notation"}, 1409 Value: parser.NewTernaryValueFromString("true"), 1410 }, 1411 }, 1412 Result: "\033[34;1m@@SCIENTIFIC_NOTATION:\033[0m \033[33;1mtrue\033[0m", 1413 }, 1414 { 1415 Name: "Show StripEndingLineBreak", 1416 Expr: parser.ShowFlag{ 1417 Flag: parser.Flag{Name: "strip_ending_line_break"}, 1418 }, 1419 SetExprs: []parser.SetFlag{ 1420 { 1421 Flag: parser.Flag{Name: "strip_ending_line_break"}, 1422 Value: parser.NewTernaryValueFromString("true"), 1423 }, 1424 }, 1425 Result: "\033[34;1m@@STRIP_ENDING_LINE_BREAK:\033[0m \033[33;1mtrue\033[0m", 1426 }, 1427 { 1428 Name: "Show PrettyPrint Ignored", 1429 Expr: parser.ShowFlag{ 1430 Flag: parser.Flag{Name: "pretty_print"}, 1431 }, 1432 SetExprs: []parser.SetFlag{ 1433 { 1434 Flag: parser.Flag{Name: "pretty_print"}, 1435 Value: parser.NewTernaryValueFromString("true"), 1436 }, 1437 }, 1438 Result: "\033[34;1m@@PRETTY_PRINT:\033[0m \033[90m(ignored) true\033[0m", 1439 }, 1440 { 1441 Name: "Show EastAsianEncoding", 1442 Expr: parser.ShowFlag{ 1443 Flag: parser.Flag{Name: "east_asian_encoding"}, 1444 }, 1445 SetExprs: []parser.SetFlag{ 1446 { 1447 Flag: parser.Flag{Name: "east_asian_encoding"}, 1448 Value: parser.NewTernaryValueFromString("true"), 1449 }, 1450 { 1451 Flag: parser.Flag{Name: "format"}, 1452 Value: parser.NewStringValue("TEXT"), 1453 }, 1454 }, 1455 Result: "\033[34;1m@@EAST_ASIAN_ENCODING:\033[0m \033[33;1mtrue\033[0m", 1456 }, 1457 { 1458 Name: "Show EastAsianEncoding Ignored", 1459 Expr: parser.ShowFlag{ 1460 Flag: parser.Flag{Name: "east_asian_encoding"}, 1461 }, 1462 SetExprs: []parser.SetFlag{ 1463 { 1464 Flag: parser.Flag{Name: "east_asian_encoding"}, 1465 Value: parser.NewTernaryValueFromString("true"), 1466 }, 1467 { 1468 Flag: parser.Flag{Name: "format"}, 1469 Value: parser.NewStringValue("JSON"), 1470 }, 1471 }, 1472 Result: "\033[34;1m@@EAST_ASIAN_ENCODING:\033[0m \033[90m(ignored) true\033[0m", 1473 }, 1474 { 1475 Name: "Show CountDiacriticalSign", 1476 Expr: parser.ShowFlag{ 1477 Flag: parser.Flag{Name: "count_diacritical_sign"}, 1478 }, 1479 SetExprs: []parser.SetFlag{ 1480 { 1481 Flag: parser.Flag{Name: "count_diacritical_sign"}, 1482 Value: parser.NewTernaryValueFromString("true"), 1483 }, 1484 { 1485 Flag: parser.Flag{Name: "format"}, 1486 Value: parser.NewStringValue("TEXT"), 1487 }, 1488 }, 1489 Result: "\033[34;1m@@COUNT_DIACRITICAL_SIGN:\033[0m \033[33;1mtrue\033[0m", 1490 }, 1491 { 1492 Name: "Show CountDiacriticalSign Ignored", 1493 Expr: parser.ShowFlag{ 1494 Flag: parser.Flag{Name: "count_diacritical_sign"}, 1495 }, 1496 SetExprs: []parser.SetFlag{ 1497 { 1498 Flag: parser.Flag{Name: "count_diacritical_sign"}, 1499 Value: parser.NewTernaryValueFromString("true"), 1500 }, 1501 { 1502 Flag: parser.Flag{Name: "format"}, 1503 Value: parser.NewStringValue("JSON"), 1504 }, 1505 }, 1506 Result: "\033[34;1m@@COUNT_DIACRITICAL_SIGN:\033[0m \033[90m(ignored) true\033[0m", 1507 }, 1508 { 1509 Name: "Show CountFormatCode", 1510 Expr: parser.ShowFlag{ 1511 Flag: parser.Flag{Name: "count_format_code"}, 1512 }, 1513 SetExprs: []parser.SetFlag{ 1514 { 1515 Flag: parser.Flag{Name: "count_format_code"}, 1516 Value: parser.NewTernaryValueFromString("true"), 1517 }, 1518 { 1519 Flag: parser.Flag{Name: "format"}, 1520 Value: parser.NewStringValue("TEXT"), 1521 }, 1522 }, 1523 Result: "\033[34;1m@@COUNT_FORMAT_CODE:\033[0m \033[33;1mtrue\033[0m", 1524 }, 1525 { 1526 Name: "Show CountFormatCode Ignored", 1527 Expr: parser.ShowFlag{ 1528 Flag: parser.Flag{Name: "count_format_code"}, 1529 }, 1530 SetExprs: []parser.SetFlag{ 1531 { 1532 Flag: parser.Flag{Name: "count_format_code"}, 1533 Value: parser.NewTernaryValueFromString("true"), 1534 }, 1535 { 1536 Flag: parser.Flag{Name: "format"}, 1537 Value: parser.NewStringValue("JSON"), 1538 }, 1539 }, 1540 Result: "\033[34;1m@@COUNT_FORMAT_CODE:\033[0m \033[90m(ignored) true\033[0m", 1541 }, 1542 { 1543 Name: "Show Color", 1544 Expr: parser.ShowFlag{ 1545 Flag: parser.Flag{Name: "color"}, 1546 }, 1547 SetExprs: []parser.SetFlag{ 1548 { 1549 Flag: parser.Flag{Name: "color"}, 1550 Value: parser.NewTernaryValueFromString("true"), 1551 }, 1552 }, 1553 Result: "\033[34;1m@@COLOR:\033[0m \033[33;1mtrue\033[0m", 1554 }, 1555 { 1556 Name: "Show Quiet", 1557 Expr: parser.ShowFlag{ 1558 Flag: parser.Flag{Name: "quiet"}, 1559 }, 1560 SetExprs: []parser.SetFlag{ 1561 { 1562 Flag: parser.Flag{Name: "quiet"}, 1563 Value: parser.NewTernaryValueFromString("true"), 1564 }, 1565 }, 1566 Result: "\033[34;1m@@QUIET:\033[0m \033[33;1mtrue\033[0m", 1567 }, 1568 { 1569 Name: "Show LimitRecursion", 1570 Expr: parser.ShowFlag{ 1571 Flag: parser.Flag{Name: "limit_recursion"}, 1572 }, 1573 SetExprs: []parser.SetFlag{ 1574 { 1575 Flag: parser.Flag{Name: "limit_recursion"}, 1576 Value: parser.NewIntegerValue(3), 1577 }, 1578 }, 1579 Result: "\033[34;1m@@LIMIT_RECURSION:\033[0m \033[35m3\033[0m", 1580 }, 1581 { 1582 Name: "Show LimitRecursion No Limit", 1583 Expr: parser.ShowFlag{ 1584 Flag: parser.Flag{Name: "limit_recursion"}, 1585 }, 1586 SetExprs: []parser.SetFlag{ 1587 { 1588 Flag: parser.Flag{Name: "limit_recursion"}, 1589 Value: parser.NewIntegerValue(-100), 1590 }, 1591 }, 1592 Result: "\033[34;1m@@LIMIT_RECURSION:\033[0m \033[90m(no limit)\033[0m", 1593 }, 1594 { 1595 Name: "Show CPU", 1596 Expr: parser.ShowFlag{ 1597 Flag: parser.Flag{Name: "cpu"}, 1598 }, 1599 SetExprs: []parser.SetFlag{ 1600 { 1601 Flag: parser.Flag{Name: "cpu"}, 1602 Value: parser.NewIntegerValue(1), 1603 }, 1604 }, 1605 Result: "\033[34;1m@@CPU:\033[0m \033[35m1\033[0m", 1606 }, 1607 { 1608 Name: "Show Stats", 1609 Expr: parser.ShowFlag{ 1610 Flag: parser.Flag{Name: "stats"}, 1611 }, 1612 SetExprs: []parser.SetFlag{ 1613 { 1614 Flag: parser.Flag{Name: "stats"}, 1615 Value: parser.NewTernaryValueFromString("true"), 1616 }, 1617 }, 1618 Result: "\033[34;1m@@STATS:\033[0m \033[33;1mtrue\033[0m", 1619 }, 1620 { 1621 Name: "Invalid Flag Name Error", 1622 Expr: parser.ShowFlag{ 1623 Flag: parser.Flag{Name: "invalid"}, 1624 }, 1625 Error: "@@INVALID is an unknown flag", 1626 }, 1627 } 1628 1629 func TestShowFlag(t *testing.T) { 1630 defer func() { 1631 TestTx.UseColor(false) 1632 initFlag(TestTx.Flags) 1633 }() 1634 1635 TestTx.UseColor(true) 1636 ctx := context.Background() 1637 scope := NewReferenceScope(TestTx) 1638 1639 for _, v := range showFlagTests { 1640 initFlag(TestTx.Flags) 1641 TestTx.UseColor(true) 1642 for _, expr := range v.SetExprs { 1643 _ = SetFlag(ctx, scope, expr) 1644 } 1645 result, err := ShowFlag(TestTx, v.Expr) 1646 if err != nil { 1647 if len(v.Error) < 1 { 1648 t.Errorf("%s: unexpected error %q", v.Name, err) 1649 } else if err.Error() != v.Error { 1650 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 1651 } 1652 continue 1653 } 1654 if 0 < len(v.Error) { 1655 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 1656 continue 1657 } 1658 if result != v.Result { 1659 t.Errorf("%s: result = %s, want %s", v.Name, result, v.Result) 1660 } 1661 } 1662 } 1663 1664 var showObjectsTests = []struct { 1665 Name string 1666 Expr parser.ShowObjects 1667 Scope *ReferenceScope 1668 PreparedStatements PreparedStatementMap 1669 ImportFormat option.Format 1670 Delimiter rune 1671 AllowUnevenFields bool 1672 DelimiterPositions fixedlen.DelimiterPositions 1673 SingleLine bool 1674 JsonQuery string 1675 Repository string 1676 Format option.Format 1677 WriteDelimiter rune 1678 WriteDelimiterPositions fixedlen.DelimiterPositions 1679 WriteAsSingleLine bool 1680 ViewCache ViewMap 1681 UncommittedViews UncommittedViews 1682 Expect string 1683 Error string 1684 }{ 1685 { 1686 Name: "ShowObjects Tables", 1687 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "tables"}}, 1688 ViewCache: GenerateViewMap([]*View{ 1689 { 1690 Header: NewHeader("table1", []string{"col1", "col2"}), 1691 FileInfo: &FileInfo{ 1692 Path: "table1.csv", 1693 Delimiter: '\t', 1694 Format: option.CSV, 1695 Encoding: text.SJIS, 1696 LineBreak: text.CRLF, 1697 NoHeader: true, 1698 }, 1699 }, 1700 { 1701 Header: NewHeader("table1", []string{"col1", "col2"}), 1702 FileInfo: &FileInfo{ 1703 Path: "table1.tsv", 1704 Delimiter: '\t', 1705 Format: option.TSV, 1706 Encoding: text.UTF8, 1707 LineBreak: text.LF, 1708 NoHeader: false, 1709 }, 1710 }, 1711 { 1712 Header: NewHeader("table1", []string{"col1", "col2"}), 1713 FileInfo: &FileInfo{ 1714 Path: "table1.json", 1715 JsonQuery: "{}", 1716 Format: option.JSON, 1717 Encoding: text.UTF8, 1718 LineBreak: text.LF, 1719 PrettyPrint: false, 1720 }, 1721 }, 1722 { 1723 Header: NewHeader("table2", []string{"col1", "col2"}), 1724 FileInfo: &FileInfo{ 1725 Path: "table2.json", 1726 JsonQuery: "", 1727 Format: option.JSON, 1728 Encoding: text.UTF8, 1729 LineBreak: text.LF, 1730 JsonEscape: json.HexDigits, 1731 PrettyPrint: false, 1732 }, 1733 }, 1734 { 1735 Header: NewHeader("table1", []string{"col1", "col2"}), 1736 FileInfo: &FileInfo{ 1737 Path: "table1.jsonl", 1738 JsonQuery: "{}", 1739 Format: option.JSONL, 1740 Encoding: text.UTF8, 1741 LineBreak: text.LF, 1742 PrettyPrint: false, 1743 }, 1744 }, 1745 { 1746 Header: NewHeader("table2", []string{"col1", "col2"}), 1747 FileInfo: &FileInfo{ 1748 Path: "table2.jsonl", 1749 JsonQuery: "", 1750 Format: option.JSONL, 1751 Encoding: text.UTF8, 1752 LineBreak: text.LF, 1753 JsonEscape: json.HexDigits, 1754 PrettyPrint: false, 1755 }, 1756 }, 1757 { 1758 Header: NewHeader("table1", []string{"col1", "col2"}), 1759 FileInfo: &FileInfo{ 1760 Path: "table1.txt", 1761 DelimiterPositions: []int{3, 12}, 1762 Format: option.FIXED, 1763 Encoding: text.UTF8, 1764 LineBreak: text.LF, 1765 NoHeader: false, 1766 }, 1767 }, 1768 { 1769 Header: NewHeader("table2", []string{"col1", "col2"}), 1770 FileInfo: &FileInfo{ 1771 Path: "table2.txt", 1772 DelimiterPositions: []int{3, 12}, 1773 SingleLine: true, 1774 Format: option.FIXED, 1775 Encoding: text.UTF8, 1776 LineBreak: text.LF, 1777 NoHeader: false, 1778 }, 1779 }, 1780 }), 1781 Expect: "\n" + 1782 " Loaded Tables\n" + 1783 "----------------------------------------------------------\n" + 1784 " table1.csv\n" + 1785 " Fields: col1, col2\n" + 1786 " Format: CSV Delimiter: '\\t' Enclose All: false\n" + 1787 " Encoding: SJIS LineBreak: CRLF Header: false\n" + 1788 " table1.json\n" + 1789 " Fields: col1, col2\n" + 1790 " Format: JSON Escape: BACKSLASH Query: {}\n" + 1791 " Encoding: UTF8 LineBreak: LF Pretty Print: false\n" + 1792 " table1.jsonl\n" + 1793 " Fields: col1, col2\n" + 1794 " Format: JSONL Escape: BACKSLASH Query: {}\n" + 1795 " Encoding: UTF8 LineBreak: LF Pretty Print: false\n" + 1796 " table1.tsv\n" + 1797 " Fields: col1, col2\n" + 1798 " Format: TSV Delimiter: '\\t' Enclose All: false\n" + 1799 " Encoding: UTF8 LineBreak: LF Header: true\n" + 1800 " table1.txt\n" + 1801 " Fields: col1, col2\n" + 1802 " Format: FIXED Delimiter Positions: [3, 12]\n" + 1803 " Encoding: UTF8 LineBreak: LF Header: true\n" + 1804 " table2.json\n" + 1805 " Fields: col1, col2\n" + 1806 " Format: JSON Escape: HEX Query: (empty)\n" + 1807 " Encoding: UTF8 LineBreak: LF Pretty Print: false\n" + 1808 " table2.jsonl\n" + 1809 " Fields: col1, col2\n" + 1810 " Format: JSONL Escape: HEX Query: (empty)\n" + 1811 " Encoding: UTF8 LineBreak: LF Pretty Print: false\n" + 1812 " table2.txt\n" + 1813 " Fields: col1, col2\n" + 1814 " Format: FIXED Delimiter Positions: S[3, 12]\n" + 1815 " Encoding: UTF8\n" + 1816 "\n", 1817 }, 1818 { 1819 Name: "ShowObjects Tables Uncommitted", 1820 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "tables"}}, 1821 ViewCache: GenerateViewMap([]*View{ 1822 { 1823 Header: NewHeader("table1", []string{"col1", "col2"}), 1824 FileInfo: &FileInfo{ 1825 Path: "table1.csv", 1826 Delimiter: '\t', 1827 Format: option.CSV, 1828 Encoding: text.SJIS, 1829 LineBreak: text.CRLF, 1830 NoHeader: true, 1831 }, 1832 }, 1833 { 1834 Header: NewHeader("table1", []string{"col1", "col2"}), 1835 FileInfo: &FileInfo{ 1836 Path: "table1.tsv", 1837 Delimiter: '\t', 1838 Format: option.TSV, 1839 Encoding: text.UTF8, 1840 LineBreak: text.LF, 1841 NoHeader: false, 1842 }, 1843 }, 1844 { 1845 Header: NewHeader("table1", []string{"col1", "col2"}), 1846 FileInfo: &FileInfo{ 1847 Path: "table1.json", 1848 JsonQuery: "{}", 1849 Format: option.JSON, 1850 Encoding: text.UTF8, 1851 LineBreak: text.LF, 1852 PrettyPrint: false, 1853 }, 1854 }, 1855 { 1856 Header: NewHeader("table1", []string{"col1", "col2"}), 1857 FileInfo: &FileInfo{ 1858 Path: "table1.jsonl", 1859 JsonQuery: "{}", 1860 Format: option.JSONL, 1861 Encoding: text.UTF8, 1862 LineBreak: text.LF, 1863 PrettyPrint: false, 1864 }, 1865 }, 1866 { 1867 Header: NewHeader("table2", []string{"col1", "col2"}), 1868 FileInfo: &FileInfo{ 1869 Path: "table2.json", 1870 JsonQuery: "", 1871 Format: option.JSON, 1872 Encoding: text.UTF8, 1873 LineBreak: text.LF, 1874 PrettyPrint: false, 1875 }, 1876 }, 1877 { 1878 Header: NewHeader("table1", []string{"col1", "col2"}), 1879 FileInfo: &FileInfo{ 1880 Path: "table1.txt", 1881 DelimiterPositions: []int{3, 12}, 1882 Format: option.FIXED, 1883 Encoding: text.UTF8, 1884 LineBreak: text.LF, 1885 NoHeader: false, 1886 }, 1887 }, 1888 { 1889 Header: NewHeader("table2", []string{"col1", "col2"}), 1890 FileInfo: &FileInfo{ 1891 Path: "table2.txt", 1892 DelimiterPositions: []int{3, 12}, 1893 Format: option.FIXED, 1894 Encoding: text.UTF8, 1895 LineBreak: text.LF, 1896 NoHeader: false, 1897 SingleLine: true, 1898 }, 1899 }, 1900 }), 1901 UncommittedViews: UncommittedViews{ 1902 mtx: &sync.RWMutex{}, 1903 Created: map[string]*FileInfo{ 1904 "TABLE1.TSV": {Path: "table1.tsv"}, 1905 }, 1906 Updated: map[string]*FileInfo{ 1907 "TABLE2.JSON": {Path: "table2.json"}, 1908 }, 1909 }, 1910 Expect: "\n" + 1911 " Loaded Tables (Uncommitted: 2 Tables)\n" + 1912 "----------------------------------------------------------\n" + 1913 " table1.csv\n" + 1914 " Fields: col1, col2\n" + 1915 " Format: CSV Delimiter: '\\t' Enclose All: false\n" + 1916 " Encoding: SJIS LineBreak: CRLF Header: false\n" + 1917 " table1.json\n" + 1918 " Fields: col1, col2\n" + 1919 " Format: JSON Escape: BACKSLASH Query: {}\n" + 1920 " Encoding: UTF8 LineBreak: LF Pretty Print: false\n" + 1921 " table1.jsonl\n" + 1922 " Fields: col1, col2\n" + 1923 " Format: JSONL Escape: BACKSLASH Query: {}\n" + 1924 " Encoding: UTF8 LineBreak: LF Pretty Print: false\n" + 1925 " *Created* table1.tsv\n" + 1926 " Fields: col1, col2\n" + 1927 " Format: TSV Delimiter: '\\t' Enclose All: false\n" + 1928 " Encoding: UTF8 LineBreak: LF Header: true\n" + 1929 " table1.txt\n" + 1930 " Fields: col1, col2\n" + 1931 " Format: FIXED Delimiter Positions: [3, 12]\n" + 1932 " Encoding: UTF8 LineBreak: LF Header: true\n" + 1933 " *Updated* table2.json\n" + 1934 " Fields: col1, col2\n" + 1935 " Format: JSON Escape: BACKSLASH Query: (empty)\n" + 1936 " Encoding: UTF8 LineBreak: LF Pretty Print: false\n" + 1937 " table2.txt\n" + 1938 " Fields: col1, col2\n" + 1939 " Format: FIXED Delimiter Positions: S[3, 12]\n" + 1940 " Encoding: UTF8\n" + 1941 "\n", 1942 }, 1943 { 1944 Name: "ShowObjects Tables Long Fields", 1945 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "tables"}}, 1946 ViewCache: GenerateViewMap([]*View{ 1947 { 1948 Header: NewHeader("table1", []string{"colabcdef1", "colabcdef2", "colabcdef3", "colabcdef4", "colabcdef5", "colabcdef6", "colabcdef7"}), 1949 FileInfo: &FileInfo{ 1950 Path: "table1.csv", 1951 Delimiter: '\t', 1952 Format: option.CSV, 1953 Encoding: text.SJIS, 1954 LineBreak: text.CRLF, 1955 NoHeader: true, 1956 }, 1957 }, 1958 }), 1959 Expect: "\n" + 1960 " Loaded Tables\n" + 1961 "--------------------------------------------------------------\n" + 1962 " table1.csv\n" + 1963 " Fields: colabcdef1, colabcdef2, colabcdef3, colabcdef4, \n" + 1964 " colabcdef5, colabcdef6, colabcdef7\n" + 1965 " Format: CSV Delimiter: '\\t' Enclose All: false\n" + 1966 " Encoding: SJIS LineBreak: CRLF Header: false\n" + 1967 "\n", 1968 }, 1969 { 1970 Name: "ShowObjects No Table is Loaded", 1971 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "tables"}}, 1972 Repository: filepath.Join(TestDir, "test_show_objects_empty"), 1973 Expect: "No table is loaded", 1974 }, 1975 { 1976 Name: "ShowObjects Views", 1977 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "views"}}, 1978 Scope: GenerateReferenceScope([]map[string]map[string]interface{}{ 1979 { 1980 scopeNameTempTables: { 1981 "VIEW1": &View{ 1982 FileInfo: &FileInfo{ 1983 Path: "view1", 1984 ViewType: ViewTypeTemporaryTable, 1985 }, 1986 Header: NewHeader("view1", []string{"column1", "column2"}), 1987 }, 1988 }, 1989 }, 1990 { 1991 scopeNameTempTables: { 1992 "VIEW1": &View{ 1993 FileInfo: &FileInfo{ 1994 Path: "view1", 1995 ViewType: ViewTypeTemporaryTable, 1996 }, 1997 Header: NewHeader("view1", []string{"column1", "column2", "column3"}), 1998 }, 1999 "VIEW2": &View{ 2000 FileInfo: &FileInfo{ 2001 Path: "view2", 2002 ViewType: ViewTypeTemporaryTable, 2003 }, 2004 Header: NewHeader("view2", []string{"column1", "column2"}), 2005 }, 2006 }, 2007 }, 2008 }, nil, time.Time{}, nil), 2009 UncommittedViews: UncommittedViews{ 2010 mtx: &sync.RWMutex{}, 2011 Created: map[string]*FileInfo{}, 2012 Updated: map[string]*FileInfo{ 2013 "VIEW2": { 2014 Path: "view2", 2015 ViewType: ViewTypeTemporaryTable, 2016 }, 2017 }, 2018 }, 2019 Expect: "\n" + 2020 " Views (Uncommitted: 1 View)\n" + 2021 "------------------------------\n" + 2022 " view1\n" + 2023 " Fields: column1, column2\n" + 2024 " *Updated* view2\n" + 2025 " Fields: column1, column2\n" + 2026 "\n", 2027 }, 2028 { 2029 Name: "ShowObjects Views Empty", 2030 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "views"}}, 2031 Expect: "No view is declared", 2032 }, 2033 { 2034 Name: "ShowObjects Cursors", 2035 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "cursors"}}, 2036 Scope: GenerateReferenceScope([]map[string]map[string]interface{}{ 2037 { 2038 scopeNameCursors: { 2039 "CUR": &Cursor{ 2040 Name: "cur", 2041 query: selectQueryForCursorTest, 2042 }, 2043 "CUR2": &Cursor{ 2044 Name: "cur2", 2045 query: selectQueryForCursorTest, 2046 view: &View{ 2047 RecordSet: RecordSet{ 2048 NewRecord([]value.Primary{ 2049 value.NewInteger(1), 2050 value.NewString("a"), 2051 }), 2052 NewRecord([]value.Primary{ 2053 value.NewInteger(2), 2054 value.NewString("b"), 2055 }), 2056 }, 2057 }, 2058 fetched: false, 2059 index: -1, 2060 }, 2061 "CUR3": &Cursor{ 2062 Name: "cur3", 2063 query: selectQueryForCursorTest, 2064 view: &View{ 2065 RecordSet: RecordSet{ 2066 NewRecord([]value.Primary{ 2067 value.NewInteger(1), 2068 value.NewString("a"), 2069 }), 2070 NewRecord([]value.Primary{ 2071 value.NewInteger(2), 2072 value.NewString("b"), 2073 }), 2074 }, 2075 }, 2076 fetched: true, 2077 index: 1, 2078 }, 2079 "CUR4": &Cursor{ 2080 Name: "cur4", 2081 query: selectQueryForCursorTest, 2082 view: &View{ 2083 RecordSet: RecordSet{ 2084 NewRecord([]value.Primary{ 2085 value.NewInteger(1), 2086 value.NewString("a"), 2087 }), 2088 NewRecord([]value.Primary{ 2089 value.NewInteger(2), 2090 value.NewString("b"), 2091 }), 2092 }, 2093 }, 2094 fetched: true, 2095 index: 2, 2096 }, 2097 "CUR5": &Cursor{ 2098 Name: "stmtcur", 2099 statement: parser.Identifier{Literal: "stmt"}, 2100 }, 2101 }, 2102 }, 2103 }, nil, time.Time{}, nil), 2104 Expect: "\n" + 2105 " Cursors\n" + 2106 "---------------------------------------------------------------------\n" + 2107 " cur\n" + 2108 " Status: Closed\n" + 2109 " Query:\n" + 2110 " SELECT column1, column2 FROM table1\n" + 2111 " cur2\n" + 2112 " Status: Open Number of Rows: 2 Pointer: UNKNOWN\n" + 2113 " Query:\n" + 2114 " SELECT column1, column2 FROM table1\n" + 2115 " cur3\n" + 2116 " Status: Open Number of Rows: 2 Pointer: 1\n" + 2117 " Query:\n" + 2118 " SELECT column1, column2 FROM table1\n" + 2119 " cur4\n" + 2120 " Status: Open Number of Rows: 2 Pointer: Out of Range\n" + 2121 " Query:\n" + 2122 " SELECT column1, column2 FROM table1\n" + 2123 " stmtcur\n" + 2124 " Status: Closed\n" + 2125 " Statement: stmt\n" + 2126 "\n", 2127 }, 2128 { 2129 Name: "ShowObjects Cursors Empty", 2130 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "cursors"}}, 2131 Expect: "No cursor is declared", 2132 }, 2133 { 2134 Name: "ShowObjects Functions", 2135 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "functions"}}, 2136 Scope: GenerateReferenceScope([]map[string]map[string]interface{}{ 2137 { 2138 scopeNameFunctions: { 2139 "USERFUNC1": &UserDefinedFunction{ 2140 Name: parser.Identifier{Literal: "userfunc1"}, 2141 Parameters: []parser.Variable{ 2142 {Name: "arg1"}, 2143 }, 2144 Statements: []parser.Statement{ 2145 parser.Print{Value: parser.Variable{Name: "arg1"}}, 2146 }, 2147 }, 2148 }, 2149 }, 2150 { 2151 scopeNameFunctions: { 2152 "USERAGGFUNC": &UserDefinedFunction{ 2153 Name: parser.Identifier{Literal: "useraggfunc"}, 2154 Parameters: []parser.Variable{ 2155 {Name: "arg1"}, 2156 {Name: "arg2"}, 2157 }, 2158 Defaults: map[string]parser.QueryExpression{ 2159 "arg2": parser.NewIntegerValue(1), 2160 }, 2161 IsAggregate: true, 2162 RequiredArgs: 1, 2163 Cursor: parser.Identifier{Literal: "column1"}, 2164 Statements: []parser.Statement{ 2165 parser.Print{Value: parser.Variable{Name: "var1"}}, 2166 }, 2167 }, 2168 }, 2169 }, 2170 }, nil, time.Time{}, nil), 2171 Expect: "\n" + 2172 " Scalar Functions\n" + 2173 "-------------------\n" + 2174 " userfunc1 (@arg1)\n" + 2175 "\n" + 2176 " Aggregate Functions\n" + 2177 "-----------------------------------------\n" + 2178 " useraggfunc (column1, @arg1, @arg2 = 1)\n" + 2179 "\n", 2180 }, 2181 { 2182 Name: "ShowObjects Functions Empty", 2183 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "functions"}}, 2184 Expect: "No function is declared", 2185 }, 2186 { 2187 Name: "ShowObjects Statements", 2188 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "statements"}}, 2189 PreparedStatements: GenerateStatementMap([]*PreparedStatement{ 2190 { 2191 Name: "stmt1", 2192 StatementString: "select 1;\nselect 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 22;", 2193 Statements: []parser.Statement{ 2194 parser.SelectQuery{ 2195 SelectEntity: parser.SelectEntity{ 2196 SelectClause: parser.SelectClause{ 2197 BaseExpr: parser.NewBaseExpr(parser.Token{Line: 1, Char: 1, SourceFile: "stmt"}), 2198 Fields: []parser.QueryExpression{ 2199 parser.Field{ 2200 Object: parser.NewIntegerValueFromString("1"), 2201 }, 2202 }, 2203 }, 2204 }, 2205 }, 2206 parser.SelectQuery{ 2207 SelectEntity: parser.SelectEntity{ 2208 SelectClause: parser.SelectClause{ 2209 BaseExpr: parser.NewBaseExpr(parser.Token{Line: 2, Char: 1, SourceFile: "stmt"}), 2210 Fields: []parser.QueryExpression{ 2211 parser.Field{ 2212 Object: parser.NewIntegerValueFromString("2"), 2213 }, 2214 }, 2215 }, 2216 }, 2217 }, 2218 }, 2219 HolderNumber: 0, 2220 }, 2221 { 2222 Name: "stmt2", 2223 StatementString: "select ?", 2224 Statements: []parser.Statement{ 2225 parser.SelectQuery{ 2226 SelectEntity: parser.SelectEntity{ 2227 SelectClause: parser.SelectClause{ 2228 BaseExpr: parser.NewBaseExpr(parser.Token{Line: 1, Char: 1, SourceFile: "stmt"}), 2229 Fields: []parser.QueryExpression{ 2230 parser.Field{ 2231 Object: parser.Placeholder{Literal: "?", Ordinal: 1}, 2232 }, 2233 }, 2234 }, 2235 }, 2236 }, 2237 }, 2238 HolderNumber: 1, 2239 }, 2240 }), 2241 Expect: "\n" + 2242 " Prepared Statements\n" + 2243 "-----------------------------------------------------------------------\n" + 2244 " stmt1\n" + 2245 " Placeholder Number: 0\n" + 2246 " Statement:\n" + 2247 " select 1;\n" + 2248 " select 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,\\\n" + 2249 " 18, 19, 20, 22, 22;\n" + 2250 " stmt2\n" + 2251 " Placeholder Number: 1\n" + 2252 " Statement:\n" + 2253 " select ?\n" + 2254 "\n", 2255 }, 2256 { 2257 Name: "ShowObjects Statements Empty", 2258 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "statements"}}, 2259 Expect: "No statement is prepared", 2260 }, 2261 { 2262 Name: "ShowObjects Flags", 2263 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "flags"}}, 2264 Repository: ".", 2265 Expect: "\n" + 2266 " Flags\n" + 2267 "--------------------------------------------------\n" + 2268 " @@REPOSITORY: .\n" + 2269 " @@TIMEZONE: UTC\n" + 2270 " @@DATETIME_FORMAT: (not set)\n" + 2271 " @@ANSI_QUOTES: false\n" + 2272 " @@STRICT_EQUAL: false\n" + 2273 " @@WAIT_TIMEOUT: 15\n" + 2274 " @@IMPORT_FORMAT: CSV\n" + 2275 " @@DELIMITER: ','\n" + 2276 " @@ALLOW_UNEVEN_FIELDS: false\n" + 2277 " @@DELIMITER_POSITIONS: SPACES\n" + 2278 " @@JSON_QUERY: (empty)\n" + 2279 " @@ENCODING: AUTO\n" + 2280 " @@NO_HEADER: false\n" + 2281 " @@WITHOUT_NULL: false\n" + 2282 " @@STRIP_ENDING_LINE_BREAK: false\n" + 2283 " @@FORMAT: CSV\n" + 2284 " @@WRITE_ENCODING: UTF8\n" + 2285 " @@WRITE_DELIMITER: ','\n" + 2286 " @@WRITE_DELIMITER_POSITIONS: (ignored) SPACES\n" + 2287 " @@WITHOUT_HEADER: false\n" + 2288 " @@LINE_BREAK: LF\n" + 2289 " @@ENCLOSE_ALL: false\n" + 2290 " @@JSON_ESCAPE: (ignored) BACKSLASH\n" + 2291 " @@PRETTY_PRINT: (ignored) false\n" + 2292 " @@SCIENTIFIC_NOTATION: false\n" + 2293 " @@EAST_ASIAN_ENCODING: (ignored) false\n" + 2294 " @@COUNT_DIACRITICAL_SIGN: (ignored) false\n" + 2295 " @@COUNT_FORMAT_CODE: (ignored) false\n" + 2296 " @@COLOR: false\n" + 2297 " @@QUIET: false\n" + 2298 " @@LIMIT_RECURSION: 5\n" + 2299 " @@CPU: " + strconv.Itoa(TestTx.Flags.CPU) + "\n" + 2300 " @@STATS: false\n" + 2301 "\n", 2302 }, 2303 { 2304 Name: "ShowObjects Runtime Information", 2305 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "runinfo"}}, 2306 Repository: ".", 2307 Expect: "\n" + 2308 strings.Repeat(" ", (calcShowRuninfoWidth(GetWD())-19)/2) + "Runtime Information\n" + 2309 strings.Repeat("-", calcShowRuninfoWidth(GetWD())) + "\n" + 2310 " @#UNCOMMITTED: false\n" + 2311 " @#CREATED: 0\n" + 2312 " @#UPDATED: 0\n" + 2313 " @#UPDATED_VIEWS: 0\n" + 2314 " @#LOADED_TABLES: 0\n" + 2315 " @#WORKING_DIRECTORY: " + GetWD() + "\n" + 2316 " @#VERSION: v1.0.0\n" + 2317 "\n", 2318 }, 2319 { 2320 Name: "ShowObjects Invalid Object Type", 2321 Expr: parser.ShowObjects{Type: parser.Identifier{Literal: "invalid"}}, 2322 Error: "object type invalid is invalid", 2323 }, 2324 } 2325 2326 func TestShowObjects(t *testing.T) { 2327 defer func() { 2328 _ = TestTx.ReleaseResources() 2329 TestTx.UncommittedViews.Clean() 2330 TestTx.PreparedStatements = NewPreparedStatementMap() 2331 initFlag(TestTx.Flags) 2332 }() 2333 2334 for _, v := range showObjectsTests { 2335 initFlag(TestTx.Flags) 2336 2337 TestTx.Flags.Repository = v.Repository 2338 TestTx.Flags.ImportOptions.Format = v.ImportFormat 2339 TestTx.Flags.ImportOptions.Delimiter = ',' 2340 if v.Delimiter != 0 { 2341 TestTx.Flags.ImportOptions.Delimiter = v.Delimiter 2342 } 2343 TestTx.Flags.ImportOptions.AllowUnevenFields = v.AllowUnevenFields 2344 TestTx.Flags.ImportOptions.DelimiterPositions = v.DelimiterPositions 2345 TestTx.Flags.ImportOptions.SingleLine = v.SingleLine 2346 TestTx.Flags.ImportOptions.JsonQuery = v.JsonQuery 2347 TestTx.Flags.ExportOptions.Delimiter = ',' 2348 if v.WriteDelimiter != 0 { 2349 TestTx.Flags.ExportOptions.Delimiter = v.WriteDelimiter 2350 } 2351 TestTx.Flags.ExportOptions.DelimiterPositions = v.WriteDelimiterPositions 2352 TestTx.Flags.ExportOptions.SingleLine = v.WriteAsSingleLine 2353 TestTx.Flags.ExportOptions.Format = v.Format 2354 _ = TestTx.CachedViews.Clean(TestTx.FileContainer) 2355 if v.ViewCache.SyncMap != nil { 2356 TestTx.CachedViews = v.ViewCache 2357 } 2358 if v.UncommittedViews.mtx == nil { 2359 TestTx.UncommittedViews = NewUncommittedViews() 2360 } else { 2361 TestTx.UncommittedViews = v.UncommittedViews 2362 } 2363 TestTx.PreparedStatements = NewPreparedStatementMap() 2364 if v.PreparedStatements.SyncMap != nil { 2365 TestTx.PreparedStatements = v.PreparedStatements 2366 } 2367 2368 if v.Scope == nil { 2369 v.Scope = NewReferenceScope(TestTx) 2370 } 2371 result, err := ShowObjects(v.Scope, v.Expr) 2372 if err != nil { 2373 if len(v.Error) < 1 { 2374 t.Errorf("%s: unexpected error %q", v.Name, err) 2375 } else if err.Error() != v.Error { 2376 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 2377 } 2378 continue 2379 } 2380 if 0 < len(v.Error) { 2381 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 2382 continue 2383 } 2384 if result != v.Expect { 2385 t.Errorf("%s: result = %s, want %s", v.Name, result, v.Expect) 2386 } 2387 } 2388 } 2389 2390 var showFieldsTests = []struct { 2391 Name string 2392 Expr parser.ShowFields 2393 Scope *ReferenceScope 2394 ViewCache ViewMap 2395 UncommittedViews UncommittedViews 2396 Expect string 2397 Error string 2398 }{ 2399 { 2400 Name: "ShowFields Temporary Table", 2401 Expr: parser.ShowFields{ 2402 Type: parser.Identifier{Literal: "fields"}, 2403 Table: parser.Identifier{Literal: "view1"}, 2404 }, 2405 Scope: GenerateReferenceScope([]map[string]map[string]interface{}{ 2406 { 2407 scopeNameTempTables: { 2408 "VIEW1": &View{ 2409 Header: NewHeader("view1", []string{"column1", "column2"}), 2410 FileInfo: &FileInfo{ 2411 Path: "view1", 2412 ViewType: ViewTypeTemporaryTable, 2413 }, 2414 }, 2415 }, 2416 }, 2417 }, nil, time.Time{}, nil), 2418 Expect: "\n" + 2419 " Fields in view1\n" + 2420 "-----------------------\n" + 2421 " Type: Temporary Table\n" + 2422 " Status: Fixed\n" + 2423 " Fields:\n" + 2424 " 1. column1\n" + 2425 " 2. column2\n" + 2426 "\n", 2427 }, 2428 { 2429 Name: "ShowFields Stdin Table", 2430 Expr: parser.ShowFields{ 2431 Type: parser.Identifier{Literal: "fields"}, 2432 Table: parser.Stdin{}, 2433 }, 2434 Scope: GenerateReferenceScope([]map[string]map[string]interface{}{ 2435 { 2436 scopeNameTempTables: { 2437 "STDIN": &View{ 2438 Header: NewHeader("stdin", []string{"column1", "column2"}), 2439 FileInfo: &FileInfo{ 2440 Path: "stdin", 2441 Format: option.CSV, 2442 Encoding: text.UTF8, 2443 Delimiter: ',', 2444 LineBreak: text.LF, 2445 ViewType: ViewTypeStdin, 2446 }, 2447 }, 2448 }, 2449 }, 2450 }, nil, time.Time{}, nil), 2451 Expect: "\n" + 2452 " Fields in STDIN\n" + 2453 "-----------------------------------------------------\n" + 2454 " Type: STDIN\n" + 2455 " Format: CSV Delimiter: ',' Enclose All: false\n" + 2456 " Encoding: UTF8 LineBreak: LF Header: true\n" + 2457 " Status: Fixed\n" + 2458 " Fields:\n" + 2459 " 1. column1\n" + 2460 " 2. column2\n" + 2461 "\n", 2462 }, 2463 { 2464 Name: "ShowFields Updated Temporary Table", 2465 Expr: parser.ShowFields{ 2466 Type: parser.Identifier{Literal: "fields"}, 2467 Table: parser.Identifier{Literal: "view1"}, 2468 }, 2469 Scope: GenerateReferenceScope([]map[string]map[string]interface{}{ 2470 { 2471 scopeNameTempTables: { 2472 "VIEW1": &View{ 2473 Header: NewHeader("view1", []string{"column1", "column2"}), 2474 FileInfo: &FileInfo{ 2475 Path: "view1", 2476 ViewType: ViewTypeTemporaryTable, 2477 }, 2478 }, 2479 }, 2480 }, 2481 }, nil, time.Time{}, nil), 2482 UncommittedViews: UncommittedViews{ 2483 mtx: &sync.RWMutex{}, 2484 Created: map[string]*FileInfo{}, 2485 Updated: map[string]*FileInfo{ 2486 "VIEW1": { 2487 Path: "view1", 2488 ViewType: ViewTypeTemporaryTable, 2489 }, 2490 }, 2491 }, 2492 Expect: "\n" + 2493 " Fields in view1\n" + 2494 "-----------------------\n" + 2495 " Type: Temporary Table\n" + 2496 " Status: Updated\n" + 2497 " Fields:\n" + 2498 " 1. column1\n" + 2499 " 2. column2\n" + 2500 "\n", 2501 }, 2502 { 2503 Name: "ShowFields", 2504 Expr: parser.ShowFields{ 2505 Type: parser.Identifier{Literal: "fields"}, 2506 Table: parser.FormatSpecifiedFunction{ 2507 Type: parser.Token{Token: parser.CSV, Literal: "csv"}, 2508 FormatElement: parser.NewStringValue(","), 2509 Path: parser.Identifier{Literal: "show_fields_create.csv"}, 2510 }, 2511 }, 2512 ViewCache: GenerateViewMap([]*View{ 2513 { 2514 Header: NewHeader("show_fields_create", []string{"column1", "column2"}), 2515 FileInfo: &FileInfo{ 2516 Path: GetTestFilePath("show_fields_create.csv"), 2517 Delimiter: ',', 2518 Format: option.CSV, 2519 Encoding: text.UTF8, 2520 LineBreak: text.LF, 2521 NoHeader: false, 2522 ViewType: ViewTypeFile, 2523 }, 2524 }, 2525 }), 2526 UncommittedViews: UncommittedViews{ 2527 mtx: &sync.RWMutex{}, 2528 Created: map[string]*FileInfo{ 2529 strings.ToUpper(GetTestFilePath("show_fields_create.csv")): {Path: "show_fields_create.csv", ViewType: ViewTypeFile}, 2530 }, 2531 Updated: map[string]*FileInfo{}, 2532 }, 2533 Expect: "\n" + 2534 strings.Repeat(" ", (calcShowFieldsWidth("show_fields_create.csv", "show_fields_create.csv", 10)-(10+len("show_fields_create.csv")))/2) + "Fields in show_fields_create.csv\n" + 2535 strings.Repeat("-", calcShowFieldsWidth("show_fields_create.csv", "show_fields_create.csv", 10)) + "\n" + 2536 " Type: File\n" + 2537 " Path: " + GetTestFilePath("show_fields_create.csv") + "\n" + 2538 " Format: CSV Delimiter: ',' Enclose All: false\n" + 2539 " Encoding: UTF8 LineBreak: LF Header: true\n" + 2540 " Status: Created\n" + 2541 " Fields:\n" + 2542 " 1. column1\n" + 2543 " 2. column2\n" + 2544 "\n", 2545 }, 2546 { 2547 Name: "ShowFields Created Table", 2548 Expr: parser.ShowFields{ 2549 Type: parser.Identifier{Literal: "fields"}, 2550 Table: parser.Identifier{Literal: "show_fields_create.csv"}, 2551 }, 2552 ViewCache: GenerateViewMap([]*View{ 2553 { 2554 Header: NewHeader("show_fields_create", []string{"column1", "column2"}), 2555 FileInfo: &FileInfo{ 2556 Path: GetTestFilePath("show_fields_create.csv"), 2557 Delimiter: ',', 2558 Format: option.CSV, 2559 Encoding: text.UTF8, 2560 LineBreak: text.LF, 2561 NoHeader: false, 2562 ViewType: ViewTypeFile, 2563 }, 2564 }, 2565 }), 2566 UncommittedViews: UncommittedViews{ 2567 mtx: &sync.RWMutex{}, 2568 Created: map[string]*FileInfo{ 2569 strings.ToUpper(GetTestFilePath("show_fields_create.csv")): {Path: "show_fields_create.csv", ViewType: ViewTypeFile}, 2570 }, 2571 Updated: map[string]*FileInfo{}, 2572 }, 2573 Expect: "\n" + 2574 strings.Repeat(" ", (calcShowFieldsWidth("show_fields_create.csv", "show_fields_create.csv", 10)-(10+len("show_fields_create.csv")))/2) + "Fields in show_fields_create.csv\n" + 2575 strings.Repeat("-", calcShowFieldsWidth("show_fields_create.csv", "show_fields_create.csv", 10)) + "\n" + 2576 " Type: File\n" + 2577 " Path: " + GetTestFilePath("show_fields_create.csv") + "\n" + 2578 " Format: CSV Delimiter: ',' Enclose All: false\n" + 2579 " Encoding: UTF8 LineBreak: LF Header: true\n" + 2580 " Status: Created\n" + 2581 " Fields:\n" + 2582 " 1. column1\n" + 2583 " 2. column2\n" + 2584 "\n", 2585 }, 2586 { 2587 Name: "ShowFields Updated Table", 2588 Expr: parser.ShowFields{ 2589 Type: parser.Identifier{Literal: "fields"}, 2590 Table: parser.Identifier{Literal: "show_fields_update.csv"}, 2591 }, 2592 ViewCache: GenerateViewMap([]*View{ 2593 { 2594 Header: NewHeader("show_fields_update", []string{"column1", "column2"}), 2595 FileInfo: &FileInfo{ 2596 Path: GetTestFilePath("show_fields_update.csv"), 2597 Delimiter: ',', 2598 Format: option.CSV, 2599 Encoding: text.UTF8, 2600 LineBreak: text.LF, 2601 NoHeader: false, 2602 ViewType: ViewTypeFile, 2603 }, 2604 }, 2605 }), 2606 UncommittedViews: UncommittedViews{ 2607 mtx: &sync.RWMutex{}, 2608 Created: map[string]*FileInfo{}, 2609 Updated: map[string]*FileInfo{ 2610 strings.ToUpper(GetTestFilePath("show_fields_update.csv")): {Path: "show_fields_updated.csv", ViewType: ViewTypeFile}, 2611 }, 2612 }, 2613 Expect: "\n" + 2614 strings.Repeat(" ", (calcShowFieldsWidth("show_fields_update.csv", "show_fields_update.csv", 10)-(10+len("show_fields_update.csv")))/2) + "Fields in show_fields_update.csv\n" + 2615 strings.Repeat("-", calcShowFieldsWidth("show_fields_create.csv", "show_fields_update.csv", 10)) + "\n" + 2616 " Type: File\n" + 2617 " Path: " + GetTestFilePath("show_fields_update.csv") + "\n" + 2618 " Format: CSV Delimiter: ',' Enclose All: false\n" + 2619 " Encoding: UTF8 LineBreak: LF Header: true\n" + 2620 " Status: Updated\n" + 2621 " Fields:\n" + 2622 " 1. column1\n" + 2623 " 2. column2\n" + 2624 "\n", 2625 }, 2626 { 2627 Name: "ShowFields Inline Table from String", 2628 Expr: parser.ShowFields{ 2629 Type: parser.Identifier{Literal: "fields"}, 2630 Table: parser.TableFunction{ 2631 Name: "data", 2632 Args: []parser.QueryExpression{ 2633 parser.NewStringValue("c1,c2\n1,a\n2,b"), 2634 }, 2635 }, 2636 }, 2637 Scope: GenerateReferenceScope([]map[string]map[string]interface{}{}, nil, time.Time{}, nil), 2638 Expect: "\n" + 2639 " Fields in String Object\n" + 2640 "-----------------------------------------------------\n" + 2641 " Type: String Object\n" + 2642 " Format: CSV Delimiter: ',' Enclose All: false\n" + 2643 " Encoding: UTF8 LineBreak: LF Header: true\n" + 2644 " Status: Read-Only\n" + 2645 " Fields:\n" + 2646 " 1. c1\n" + 2647 " 2. c2\n" + 2648 "\n", 2649 }, 2650 { 2651 Name: "ShowFields Load Error", 2652 Expr: parser.ShowFields{ 2653 Type: parser.Identifier{Literal: "fields"}, 2654 Table: parser.Identifier{Literal: "notexist"}, 2655 }, 2656 Error: "file notexist does not exist", 2657 }, 2658 { 2659 Name: "ShowFields Invalid Object Type", 2660 Expr: parser.ShowFields{ 2661 Type: parser.Identifier{Literal: "invalid"}, 2662 Table: parser.Identifier{Literal: "table2"}, 2663 }, 2664 Error: "object type invalid is invalid", 2665 }, 2666 } 2667 2668 func calcShowFieldsWidth(fileName string, fileNameInTitle string, prefixLen int) int { 2669 w := 53 2670 pathLen := 8 + len(GetTestFilePath(fileName)) 2671 titleLen := prefixLen + len(fileNameInTitle) 2672 2673 if w < titleLen { 2674 w = titleLen 2675 } 2676 if w < pathLen { 2677 w = pathLen 2678 } 2679 if 75 < w { 2680 w = 75 2681 } 2682 return w 2683 } 2684 2685 func calcShowRuninfoWidth(wd string) int { 2686 w := 28 2687 pathLen := 22 + len(wd) 2688 if w < pathLen { 2689 w = pathLen 2690 } 2691 w++ 2692 if 75 < w { 2693 w = 75 2694 } 2695 return w 2696 } 2697 2698 func TestShowFields(t *testing.T) { 2699 defer func() { 2700 _ = TestTx.ReleaseResources() 2701 TestTx.UncommittedViews.Clean() 2702 initFlag(TestTx.Flags) 2703 }() 2704 2705 initFlag(TestTx.Flags) 2706 TestTx.Flags.Repository = TestDir 2707 ctx := context.Background() 2708 2709 for _, v := range showFieldsTests { 2710 _ = TestTx.CachedViews.Clean(TestTx.FileContainer) 2711 if v.ViewCache.SyncMap != nil { 2712 TestTx.CachedViews = v.ViewCache 2713 } 2714 if v.UncommittedViews.mtx == nil { 2715 TestTx.UncommittedViews = NewUncommittedViews() 2716 } else { 2717 TestTx.UncommittedViews = v.UncommittedViews 2718 } 2719 2720 if v.Scope == nil { 2721 v.Scope = NewReferenceScope(TestTx) 2722 } 2723 2724 result, err := ShowFields(ctx, v.Scope, v.Expr) 2725 if err != nil { 2726 if len(v.Error) < 1 { 2727 t.Errorf("%s: unexpected error %q", v.Name, err) 2728 } else if err.Error() != v.Error { 2729 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 2730 } 2731 continue 2732 } 2733 if 0 < len(v.Error) { 2734 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 2735 continue 2736 } 2737 if result != v.Expect { 2738 t.Errorf("%s: result = %s, want %s", v.Name, result, v.Expect) 2739 } 2740 } 2741 } 2742 2743 var setEnvVarTests = []struct { 2744 Name string 2745 Expr parser.SetEnvVar 2746 Expect string 2747 Error string 2748 }{ 2749 { 2750 Name: "Set Environment Variable", 2751 Expr: parser.SetEnvVar{ 2752 EnvVar: parser.EnvironmentVariable{ 2753 Name: "CSVQ_SET_ENV_TEST", 2754 }, 2755 Value: parser.NewStringValue("foo"), 2756 }, 2757 Expect: "foo", 2758 }, 2759 { 2760 Name: "Set Environment Variable with Identifier", 2761 Expr: parser.SetEnvVar{ 2762 EnvVar: parser.EnvironmentVariable{ 2763 Name: "CSVQ_SET_ENV_TEST", 2764 }, 2765 Value: parser.Identifier{Literal: "bar"}, 2766 }, 2767 Expect: "bar", 2768 }, 2769 { 2770 Name: "Set Environment Variable with Null", 2771 Expr: parser.SetEnvVar{ 2772 EnvVar: parser.EnvironmentVariable{ 2773 Name: "CSVQ_SET_ENV_TEST", 2774 }, 2775 Value: parser.NewNullValue(), 2776 }, 2777 Expect: "", 2778 }, 2779 { 2780 Name: "Set Environment Variable Evaluation Error", 2781 Expr: parser.SetEnvVar{ 2782 EnvVar: parser.EnvironmentVariable{ 2783 Name: "CSVQ_SET_ENV_TEST", 2784 }, 2785 Value: parser.FieldReference{Column: parser.Identifier{Literal: "err"}}, 2786 }, 2787 Error: "field err does not exist", 2788 }, 2789 } 2790 2791 func TestSetEnvVar(t *testing.T) { 2792 ctx := context.Background() 2793 scope := NewReferenceScope(TestTx) 2794 2795 for _, v := range setEnvVarTests { 2796 err := SetEnvVar(ctx, scope, v.Expr) 2797 2798 if err != nil { 2799 if len(v.Error) < 1 { 2800 t.Errorf("%s: unexpected error %q", v.Name, err) 2801 } else if err.Error() != v.Error { 2802 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 2803 } 2804 continue 2805 } 2806 if 0 < len(v.Error) { 2807 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 2808 continue 2809 } 2810 2811 val := os.Getenv(v.Expr.EnvVar.Name) 2812 if val != v.Expect { 2813 t.Errorf("%s: value = %s, want %s", v.Name, val, v.Expect) 2814 } 2815 } 2816 } 2817 2818 var syntaxTests = []struct { 2819 Expr parser.Syntax 2820 Expect string 2821 }{ 2822 { 2823 Expr: parser.Syntax{}, 2824 Expect: "\n" + 2825 " Contents\n" + 2826 "-------------------------\n" + 2827 " SELECT Statement\n" + 2828 " WITH Clause\n" + 2829 " SELECT Clause\n" + 2830 " INSERT Statement\n" + 2831 " UPDATE Statement\n" + 2832 " DELETE Statement\n" + 2833 " Operators\n" + 2834 " Operator Precedence\n" + 2835 " String Operators\n" + 2836 "\n", 2837 }, 2838 { 2839 Expr: parser.Syntax{Keywords: []parser.QueryExpression{parser.NewStringValue("select clause")}}, 2840 Expect: "\n" + 2841 " Search: select clause\n" + 2842 "-----------------------------------------------------\n" + 2843 " SELECT Clause\n" + 2844 " select_clause\n" + 2845 " : SELECT [DISTINCT] <field> [, <field> ...]\n" + 2846 "\n" + 2847 " field\n" + 2848 " : <value>\n" + 2849 " | <value> AS alias\n" + 2850 "\n" + 2851 "\n", 2852 }, 2853 { 2854 Expr: parser.Syntax{Keywords: []parser.QueryExpression{parser.NewStringValue(" select "), parser.NewStringValue("clause")}}, 2855 Expect: "\n" + 2856 " Search: select clause\n" + 2857 "-----------------------------------------------------\n" + 2858 " SELECT Clause\n" + 2859 " select_clause\n" + 2860 " : SELECT [DISTINCT] <field> [, <field> ...]\n" + 2861 "\n" + 2862 " field\n" + 2863 " : <value>\n" + 2864 " | <value> AS alias\n" + 2865 "\n" + 2866 "\n", 2867 }, 2868 { 2869 Expr: parser.Syntax{Keywords: []parser.QueryExpression{parser.FieldReference{Column: parser.Identifier{Literal: "select clause"}}}}, 2870 Expect: "\n" + 2871 " Search: select clause\n" + 2872 "-----------------------------------------------------\n" + 2873 " SELECT Clause\n" + 2874 " select_clause\n" + 2875 " : SELECT [DISTINCT] <field> [, <field> ...]\n" + 2876 "\n" + 2877 " field\n" + 2878 " : <value>\n" + 2879 " | <value> AS alias\n" + 2880 "\n" + 2881 "\n", 2882 }, 2883 { 2884 Expr: parser.Syntax{Keywords: []parser.QueryExpression{parser.NewStringValue("operator prec")}}, 2885 Expect: "\n" + 2886 " Search: operator prec\n" + 2887 "--------------------------------------\n" + 2888 " Operator Precedence\n" + 2889 " Operator Precedence Description.\n" + 2890 "\n" + 2891 "\n", 2892 }, 2893 { 2894 Expr: parser.Syntax{Keywords: []parser.QueryExpression{parser.NewStringValue("string op")}}, 2895 Expect: "\n" + 2896 " Search: string op\n" + 2897 "------------------------------\n" + 2898 " String Operators\n" + 2899 " concatenation\n" + 2900 " : <value> || <value>\n" + 2901 "\n" + 2902 " description\n" + 2903 "\n" + 2904 "\n", 2905 }, 2906 } 2907 2908 func TestSyntax(t *testing.T) { 2909 origSyntax := syntax.CsvqSyntax 2910 2911 syntax.CsvqSyntax = []syntax.Expression{ 2912 { 2913 Label: "SELECT Statement", 2914 Grammar: []syntax.Definition{ 2915 { 2916 Name: "select_statement", 2917 Group: []syntax.Grammar{ 2918 {syntax.Option{syntax.Link("with_clause")}, syntax.Link("select_query")}, 2919 }, 2920 }, 2921 { 2922 Name: "select_query", 2923 Group: []syntax.Grammar{ 2924 {syntax.Link("select_entity"), syntax.Option{syntax.Link("order_by_clause")}, syntax.Option{syntax.Link("limit_clause")}, syntax.Option{syntax.Link("offset_clause")}}, 2925 }, 2926 }, 2927 }, 2928 Children: []syntax.Expression{ 2929 { 2930 Label: "WITH Clause", 2931 Grammar: []syntax.Definition{ 2932 { 2933 Name: "with_clause", 2934 Group: []syntax.Grammar{ 2935 {syntax.Keyword("WITH"), syntax.ContinuousOption{syntax.Link("common_table_expression")}}, 2936 }, 2937 }, 2938 { 2939 Name: "common_table_expression", 2940 Group: []syntax.Grammar{ 2941 {syntax.Option{syntax.Keyword("RECURSIVE")}, syntax.Identifier("table_name"), syntax.Option{syntax.Parentheses{syntax.ContinuousOption{syntax.Identifier("column_name")}}}, syntax.Keyword("AS"), syntax.Parentheses{syntax.Link("select_query")}}, 2942 }, 2943 }, 2944 }, 2945 }, 2946 { 2947 Label: "SELECT Clause", 2948 Grammar: []syntax.Definition{ 2949 { 2950 Name: "select_clause", 2951 Group: []syntax.Grammar{ 2952 {syntax.Keyword("SELECT"), syntax.Option{syntax.Keyword("DISTINCT")}, syntax.ContinuousOption{syntax.Link("field")}}, 2953 }, 2954 }, 2955 { 2956 Name: "field", 2957 Group: []syntax.Grammar{ 2958 {syntax.Link("value")}, 2959 {syntax.Link("value"), syntax.Keyword("AS"), syntax.Identifier("alias")}, 2960 }, 2961 }, 2962 }, 2963 }, 2964 }, 2965 }, 2966 { 2967 Label: "INSERT Statement", 2968 Grammar: []syntax.Definition{ 2969 { 2970 Name: "insert_statement", 2971 Group: []syntax.Grammar{ 2972 {syntax.Option{syntax.Link("with_clause")}, syntax.Link("insert_query")}, 2973 }, 2974 }, 2975 { 2976 Name: "insert_query", 2977 Group: []syntax.Grammar{ 2978 {syntax.Keyword("INSERT"), syntax.Keyword("INTO"), syntax.Identifier("table_name"), syntax.Option{syntax.Parentheses{syntax.ContinuousOption{syntax.Identifier("column_name")}}}, syntax.Keyword("VALUES"), syntax.ContinuousOption{syntax.Link("row_value")}}, 2979 {syntax.Keyword("INSERT"), syntax.Keyword("INTO"), syntax.Identifier("table_name"), syntax.Option{syntax.Parentheses{syntax.ContinuousOption{syntax.Identifier("column_name")}}}, syntax.Link("select_query")}, 2980 }, 2981 }, 2982 }, 2983 }, 2984 { 2985 Label: "UPDATE Statement", 2986 Grammar: []syntax.Definition{}, 2987 }, 2988 { 2989 Label: "DELETE Statement", 2990 Grammar: []syntax.Definition{}, 2991 }, 2992 { 2993 Label: "Operators", 2994 Children: []syntax.Expression{ 2995 { 2996 Label: "Operator Precedence", 2997 Description: syntax.Description{ 2998 Template: "Operator Precedence Description.", 2999 }, 3000 }, 3001 { 3002 Label: "String Operators", 3003 Grammar: []syntax.Definition{ 3004 { 3005 Name: "concatenation", 3006 Group: []syntax.Grammar{ 3007 {syntax.Link("value"), syntax.Keyword("||"), syntax.Link("value")}, 3008 }, 3009 Description: syntax.Description{Template: "description"}, 3010 }, 3011 }, 3012 }, 3013 }, 3014 }, 3015 } 3016 3017 ctx := context.Background() 3018 scope := NewReferenceScope(TestTx) 3019 3020 for _, v := range syntaxTests { 3021 result, _ := Syntax(ctx, scope, v.Expr) 3022 if result != v.Expect { 3023 t.Errorf("result = %s, want %s for %v", result, v.Expect, v.Expr) 3024 } 3025 } 3026 3027 syntax.CsvqSyntax = origSyntax 3028 }