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  }