github.com/mithrandie/csvq@v1.18.1/lib/query/transaction.go (about)

     1  package query
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/mithrandie/csvq/lib/doc"
    15  	"github.com/mithrandie/csvq/lib/file"
    16  	"github.com/mithrandie/csvq/lib/option"
    17  	"github.com/mithrandie/csvq/lib/parser"
    18  	"github.com/mithrandie/csvq/lib/value"
    19  
    20  	"github.com/mithrandie/go-text/color"
    21  	"github.com/mithrandie/go-text/fixedlen"
    22  )
    23  
    24  type UrlResource struct {
    25  	MimeType string
    26  	Data     []byte
    27  }
    28  
    29  func NewUrlResource(res *http.Response) (*UrlResource, error) {
    30  	contentType := res.Header.Get("Content-Type")
    31  	contentItems := strings.Split(contentType, ";")
    32  	mimeType := contentItems[0]
    33  
    34  	body, err := io.ReadAll(res.Body)
    35  	if err != nil {
    36  		return nil, NewSystemError(err.Error())
    37  	}
    38  
    39  	return &UrlResource{
    40  		MimeType: mimeType,
    41  		Data:     body,
    42  	}, nil
    43  }
    44  
    45  type Transaction struct {
    46  	Session *Session
    47  
    48  	Environment *option.Environment
    49  	Palette     *color.Palette
    50  	Flags       *option.Flags
    51  
    52  	WaitTimeout   time.Duration
    53  	RetryDelay    time.Duration
    54  	FileContainer *file.Container
    55  
    56  	CachedViews      ViewMap
    57  	UncommittedViews UncommittedViews
    58  
    59  	UrlCache map[string]*UrlResource
    60  
    61  	operationMutex   *sync.Mutex
    62  	viewLoadingMutex *sync.Mutex
    63  	stdinIsLocked    bool
    64  
    65  	flagMutex *sync.RWMutex
    66  
    67  	PreparedStatements PreparedStatementMap
    68  
    69  	SelectedViews []*View
    70  	AffectedRows  int
    71  
    72  	AutoCommit bool
    73  }
    74  
    75  func NewTransaction(ctx context.Context, defaultWaitTimeout time.Duration, retryDelay time.Duration, session *Session) (*Transaction, error) {
    76  	environment, err := option.NewEnvironment(ctx, defaultWaitTimeout, retryDelay)
    77  	if err != nil {
    78  		return nil, ConvertLoadConfigurationError(err)
    79  	}
    80  
    81  	flags, err := option.NewFlags(environment)
    82  	if err != nil {
    83  		return nil, ConvertLoadConfigurationError(err)
    84  	}
    85  
    86  	palette, err := option.NewPalette(environment)
    87  	if err != nil {
    88  		return nil, ConvertLoadConfigurationError(err)
    89  	}
    90  
    91  	palette.Disable()
    92  
    93  	return &Transaction{
    94  		Session:            session,
    95  		Environment:        environment,
    96  		Palette:            palette,
    97  		Flags:              flags,
    98  		WaitTimeout:        file.DefaultWaitTimeout,
    99  		RetryDelay:         file.DefaultRetryDelay,
   100  		FileContainer:      file.NewContainer(),
   101  		CachedViews:        NewViewMap(),
   102  		UncommittedViews:   NewUncommittedViews(),
   103  		UrlCache:           make(map[string]*UrlResource, 5),
   104  		operationMutex:     &sync.Mutex{},
   105  		viewLoadingMutex:   &sync.Mutex{},
   106  		stdinIsLocked:      false,
   107  		flagMutex:          &sync.RWMutex{},
   108  		PreparedStatements: NewPreparedStatementMap(),
   109  		SelectedViews:      nil,
   110  		AffectedRows:       0,
   111  		AutoCommit:         false,
   112  	}, nil
   113  }
   114  
   115  func (tx *Transaction) UpdateWaitTimeout(waitTimeout float64, retryDelay time.Duration) {
   116  	d, err := time.ParseDuration(strconv.FormatFloat(waitTimeout, 'f', -1, 64) + "s")
   117  	if err != nil {
   118  		d = file.DefaultWaitTimeout
   119  	}
   120  
   121  	tx.WaitTimeout = d
   122  	tx.RetryDelay = retryDelay
   123  	tx.Flags.SetWaitTimeout(waitTimeout)
   124  }
   125  
   126  func (tx *Transaction) UseColor(useColor bool) {
   127  	if useColor {
   128  		tx.Palette.Enable()
   129  	} else {
   130  		tx.Palette.Disable()
   131  	}
   132  	tx.Flags.SetColor(useColor)
   133  }
   134  
   135  func (tx *Transaction) Commit(ctx context.Context, scope *ReferenceScope, expr parser.Expression) error {
   136  	tx.operationMutex.Lock()
   137  	defer tx.operationMutex.Unlock()
   138  
   139  	createdFiles, updatedFiles := tx.UncommittedViews.UncommittedFiles()
   140  
   141  	createFileInfo := make([]*FileInfo, 0, len(createdFiles))
   142  	updateFileInfo := make([]*FileInfo, 0, len(updatedFiles))
   143  
   144  	if 0 < len(createdFiles) {
   145  		for _, fileInfo := range createdFiles {
   146  			view, _ := tx.CachedViews.Get(fileInfo.IdentifiedPath())
   147  
   148  			fp, _ := view.FileInfo.Handler.FileForUpdate()
   149  			if err := fp.Truncate(0); err != nil {
   150  				return NewSystemError(err.Error())
   151  			}
   152  			if _, err := fp.Seek(0, io.SeekStart); err != nil {
   153  				return NewSystemError(err.Error())
   154  			}
   155  
   156  			if _, err := EncodeView(ctx, fp, view, fileInfo.ExportOptions(tx), tx.Palette); err != nil {
   157  				return NewCommitError(expr, err.Error())
   158  			}
   159  
   160  			if !tx.Flags.ExportOptions.StripEndingLineBreak && !(fileInfo.Format == option.FIXED && fileInfo.SingleLine) {
   161  				if _, err := fp.Write([]byte(tx.Flags.ExportOptions.LineBreak.Value())); err != nil {
   162  					return NewCommitError(expr, err.Error())
   163  				}
   164  			}
   165  
   166  			createFileInfo = append(createFileInfo, view.FileInfo)
   167  		}
   168  	}
   169  
   170  	if 0 < len(updatedFiles) {
   171  		for _, fileInfo := range updatedFiles {
   172  			view, _ := tx.CachedViews.Get(fileInfo.IdentifiedPath())
   173  
   174  			fp, _ := view.FileInfo.Handler.FileForUpdate()
   175  			if err := fp.Truncate(0); err != nil {
   176  				return NewSystemError(err.Error())
   177  			}
   178  			if _, err := fp.Seek(0, io.SeekStart); err != nil {
   179  				return NewSystemError(err.Error())
   180  			}
   181  
   182  			if _, err := EncodeView(ctx, fp, view, fileInfo.ExportOptions(tx), tx.Palette); err != nil {
   183  				return NewCommitError(expr, err.Error())
   184  			}
   185  
   186  			if !tx.Flags.ExportOptions.StripEndingLineBreak && !(fileInfo.Format == option.FIXED && fileInfo.SingleLine) {
   187  				if _, err := fp.Write([]byte(tx.Flags.ExportOptions.LineBreak.Value())); err != nil {
   188  					return NewCommitError(expr, err.Error())
   189  				}
   190  			}
   191  
   192  			updateFileInfo = append(updateFileInfo, view.FileInfo)
   193  		}
   194  	}
   195  
   196  	for _, f := range createFileInfo {
   197  		if err := tx.FileContainer.Commit(f.Handler); err != nil {
   198  			return NewCommitError(expr, err.Error())
   199  		}
   200  		tx.UncommittedViews.Unset(f)
   201  		tx.LogNotice(fmt.Sprintf("Commit: file %q is created.", f.Path), tx.Flags.Quiet)
   202  	}
   203  	for _, f := range updateFileInfo {
   204  		if err := tx.FileContainer.Commit(f.Handler); err != nil {
   205  			return NewCommitError(expr, err.Error())
   206  		}
   207  		tx.UncommittedViews.Unset(f)
   208  		tx.LogNotice(fmt.Sprintf("Commit: file %q is updated.", f.Path), tx.Flags.Quiet)
   209  	}
   210  
   211  	msglist := scope.StoreTemporaryTable(tx.Session, tx.UncommittedViews.UncommittedTempViews())
   212  	if 0 < len(msglist) {
   213  		tx.LogNotice(strings.Join(msglist, "\n"), tx.quietForTemporaryViews(expr))
   214  	}
   215  	tx.UncommittedViews.Clean()
   216  	tx.UnlockStdin()
   217  	if err := tx.ReleaseResources(); err != nil {
   218  		return NewCommitError(expr, err.Error())
   219  	}
   220  	return nil
   221  }
   222  
   223  func (tx *Transaction) Rollback(scope *ReferenceScope, expr parser.Expression) error {
   224  	tx.operationMutex.Lock()
   225  	defer tx.operationMutex.Unlock()
   226  
   227  	createdFiles, updatedFiles := tx.UncommittedViews.UncommittedFiles()
   228  
   229  	if 0 < len(createdFiles) {
   230  		for _, fileinfo := range createdFiles {
   231  			tx.LogNotice(fmt.Sprintf("Rollback: file %q is deleted.", fileinfo.Path), tx.Flags.Quiet)
   232  		}
   233  	}
   234  
   235  	if 0 < len(updatedFiles) {
   236  		for _, fileinfo := range updatedFiles {
   237  			tx.LogNotice(fmt.Sprintf("Rollback: file %q is restored.", fileinfo.Path), tx.Flags.Quiet)
   238  		}
   239  	}
   240  
   241  	if scope != nil {
   242  		msglist := scope.RestoreTemporaryTable(tx.UncommittedViews.UncommittedTempViews())
   243  		if 0 < len(msglist) {
   244  			tx.LogNotice(strings.Join(msglist, "\n"), tx.quietForTemporaryViews(expr))
   245  		}
   246  	}
   247  	tx.UncommittedViews.Clean()
   248  	tx.UnlockStdin()
   249  	if err := tx.ReleaseResources(); err != nil {
   250  		return NewRollbackError(expr, err.Error())
   251  	}
   252  	return nil
   253  }
   254  
   255  func (tx *Transaction) quietForTemporaryViews(expr parser.Expression) bool {
   256  	return tx.Flags.Quiet || expr == nil
   257  }
   258  
   259  func (tx *Transaction) ReleaseResources() error {
   260  	if err := tx.CachedViews.Clean(tx.FileContainer); err != nil {
   261  		return err
   262  	}
   263  	if err := tx.FileContainer.CloseAll(); err != nil {
   264  		return err
   265  	}
   266  	tx.UnlockStdin()
   267  	tx.ClearUrlCache()
   268  	return nil
   269  }
   270  
   271  func (tx *Transaction) ReleaseResourcesWithErrors() error {
   272  	var errs []error
   273  	if err := tx.CachedViews.CleanWithErrors(tx.FileContainer); err != nil {
   274  		errs = append(errs, err.(*file.ForcedUnlockError).Errors...)
   275  	}
   276  	if err := tx.FileContainer.CloseAllWithErrors(); err != nil {
   277  		errs = append(errs, err.(*file.ForcedUnlockError).Errors...)
   278  	}
   279  	tx.UnlockStdin()
   280  	tx.ClearUrlCache()
   281  	return file.NewForcedUnlockError(errs)
   282  }
   283  
   284  func (tx *Transaction) LockStdinContext(ctx context.Context) error {
   285  	tctx, cancel := file.GetTimeoutContext(ctx, tx.WaitTimeout)
   286  	defer cancel()
   287  
   288  	err := tx.Session.stdinLocker.LockContext(tctx)
   289  	if err == nil {
   290  		tx.stdinIsLocked = true
   291  	}
   292  	return err
   293  }
   294  
   295  func (tx *Transaction) UnlockStdin() {
   296  	if tx.stdinIsLocked {
   297  		tx.stdinIsLocked = false
   298  		_ = tx.Session.stdinLocker.Unlock()
   299  	}
   300  }
   301  
   302  func (tx *Transaction) RLockStdinContext(ctx context.Context) error {
   303  	tctx, cancel := file.GetTimeoutContext(ctx, tx.WaitTimeout)
   304  	defer cancel()
   305  
   306  	return tx.Session.stdinLocker.RLockContext(tctx)
   307  }
   308  
   309  func (tx *Transaction) RUnlockStdin() {
   310  	_ = tx.Session.stdinLocker.RUnlock()
   311  }
   312  
   313  func (tx *Transaction) ClearUrlCache() {
   314  	for k := range tx.UrlCache {
   315  		delete(tx.UrlCache, k)
   316  	}
   317  }
   318  
   319  func (tx *Transaction) CreateDocumentWriter() *doc.Writer {
   320  	return doc.NewWriter(tx.Session.ScreenWidth(), tx.Flags, tx.Palette)
   321  }
   322  
   323  func (tx *Transaction) Error(s string) string {
   324  	if tx.Palette != nil {
   325  		return tx.Palette.Render(option.ErrorEffect, s)
   326  	}
   327  	return s
   328  }
   329  
   330  func (tx *Transaction) Warn(s string) string {
   331  	if tx.Palette != nil {
   332  		return tx.Palette.Render(option.WarnEffect, s)
   333  	}
   334  	return s
   335  }
   336  
   337  func (tx *Transaction) Notice(s string) string {
   338  	if tx.Palette != nil {
   339  		return tx.Palette.Render(option.NoticeEffect, s)
   340  	}
   341  	return s
   342  }
   343  
   344  func (tx *Transaction) Log(log string, quiet bool) {
   345  	if !quiet {
   346  		if err := tx.Session.WriteToStdoutWithLineBreak(log); err != nil {
   347  			println(err.Error())
   348  		}
   349  	}
   350  }
   351  
   352  func (tx *Transaction) LogNotice(log string, quiet bool) {
   353  	if !quiet {
   354  		if err := tx.Session.WriteToStdoutWithLineBreak(tx.Notice(log)); err != nil {
   355  			println(err.Error())
   356  		}
   357  	}
   358  }
   359  
   360  func (tx *Transaction) LogWarn(log string, quiet bool) {
   361  	if !quiet {
   362  		if err := tx.Session.WriteToStdoutWithLineBreak(tx.Warn(log)); err != nil {
   363  			println(err.Error())
   364  		}
   365  	}
   366  }
   367  
   368  func (tx *Transaction) LogError(log string) {
   369  	if err := tx.Session.WriteToStderrWithLineBreak(tx.Error(log)); err != nil {
   370  		println(err.Error())
   371  	}
   372  }
   373  
   374  var errNotAllowdFlagFormat = errors.New("not allowed flag format")
   375  var errInvalidFlagName = errors.New("invalid flag name")
   376  
   377  func (tx *Transaction) SetFormatFlag(value interface{}, outFile string) error {
   378  	return tx.setFlag(option.FormatFlag, value, outFile)
   379  }
   380  
   381  func (tx *Transaction) SetFlag(key string, value interface{}) error {
   382  	return tx.setFlag(key, value, "")
   383  }
   384  
   385  func (tx *Transaction) setFlag(key string, value interface{}, outFile string) error {
   386  	tx.flagMutex.Lock()
   387  	defer tx.flagMutex.Unlock()
   388  
   389  	var err error
   390  
   391  	switch strings.ToUpper(key) {
   392  	case option.RepositoryFlag:
   393  		if s, ok := value.(string); ok {
   394  			err = tx.Flags.SetRepository(s)
   395  		} else {
   396  			err = errNotAllowdFlagFormat
   397  		}
   398  	case option.TimezoneFlag:
   399  		if s, ok := value.(string); ok {
   400  			err = tx.Flags.SetLocation(s)
   401  		} else {
   402  			err = errNotAllowdFlagFormat
   403  		}
   404  	case option.DatetimeFormatFlag:
   405  		if s, ok := value.(string); ok {
   406  			tx.Flags.SetDatetimeFormat(s)
   407  		} else {
   408  			err = errNotAllowdFlagFormat
   409  		}
   410  	case option.AnsiQuotesFlag:
   411  		if b, ok := value.(bool); ok {
   412  			tx.Flags.SetAnsiQuotes(b)
   413  		} else {
   414  			err = errNotAllowdFlagFormat
   415  		}
   416  	case option.StrictEqualFlag:
   417  		if b, ok := value.(bool); ok {
   418  			tx.Flags.SetStrictEqual(b)
   419  		} else {
   420  			err = errNotAllowdFlagFormat
   421  		}
   422  	case option.WaitTimeoutFlag:
   423  		if f, ok := value.(float64); ok {
   424  			tx.UpdateWaitTimeout(f, file.DefaultRetryDelay)
   425  		} else {
   426  			err = errNotAllowdFlagFormat
   427  		}
   428  	case option.ImportFormatFlag:
   429  		if s, ok := value.(string); ok {
   430  			err = tx.Flags.SetImportFormat(s)
   431  		} else {
   432  			err = errNotAllowdFlagFormat
   433  		}
   434  	case option.DelimiterFlag:
   435  		if s, ok := value.(string); ok {
   436  			err = tx.Flags.SetDelimiter(s)
   437  		} else {
   438  			err = errNotAllowdFlagFormat
   439  		}
   440  	case option.AllowUnevenFieldsFlag:
   441  		if b, ok := value.(bool); ok {
   442  			tx.Flags.SetAllowUnevenFields(b)
   443  		} else {
   444  			err = errNotAllowdFlagFormat
   445  		}
   446  	case option.DelimiterPositionsFlag:
   447  		if s, ok := value.(string); ok {
   448  			err = tx.Flags.SetDelimiterPositions(s)
   449  		} else {
   450  			err = errNotAllowdFlagFormat
   451  		}
   452  	case option.JsonQueryFlag:
   453  		if s, ok := value.(string); ok {
   454  			tx.Flags.SetJsonQuery(s)
   455  		} else {
   456  			err = errNotAllowdFlagFormat
   457  		}
   458  	case option.EncodingFlag:
   459  		if s, ok := value.(string); ok {
   460  			err = tx.Flags.SetEncoding(s)
   461  		} else {
   462  			err = errNotAllowdFlagFormat
   463  		}
   464  	case option.NoHeaderFlag:
   465  		if b, ok := value.(bool); ok {
   466  			tx.Flags.SetNoHeader(b)
   467  		} else {
   468  			err = errNotAllowdFlagFormat
   469  		}
   470  	case option.WithoutNullFlag:
   471  		if b, ok := value.(bool); ok {
   472  			tx.Flags.SetWithoutNull(b)
   473  		} else {
   474  			err = errNotAllowdFlagFormat
   475  		}
   476  	case option.FormatFlag:
   477  		if s, ok := value.(string); ok {
   478  			err = tx.Flags.SetFormat(s, outFile, tx.Session.CanOutputToPipe)
   479  		} else {
   480  			err = errNotAllowdFlagFormat
   481  		}
   482  	case option.ExportEncodingFlag:
   483  		if s, ok := value.(string); ok {
   484  			err = tx.Flags.SetWriteEncoding(s)
   485  		} else {
   486  			err = errNotAllowdFlagFormat
   487  		}
   488  	case option.ExportDelimiterFlag:
   489  		if s, ok := value.(string); ok {
   490  			err = tx.Flags.SetWriteDelimiter(s)
   491  		} else {
   492  			err = errNotAllowdFlagFormat
   493  		}
   494  	case option.ExportDelimiterPositionsFlag:
   495  		if s, ok := value.(string); ok {
   496  			err = tx.Flags.SetWriteDelimiterPositions(s)
   497  		} else {
   498  			err = errNotAllowdFlagFormat
   499  		}
   500  	case option.WithoutHeaderFlag:
   501  		if b, ok := value.(bool); ok {
   502  			tx.Flags.SetWithoutHeader(b)
   503  		} else {
   504  			err = errNotAllowdFlagFormat
   505  		}
   506  	case option.LineBreakFlag:
   507  		if s, ok := value.(string); ok {
   508  			err = tx.Flags.SetLineBreak(s)
   509  		} else {
   510  			err = errNotAllowdFlagFormat
   511  		}
   512  	case option.EncloseAllFlag:
   513  		if b, ok := value.(bool); ok {
   514  			tx.Flags.SetEncloseAll(b)
   515  		} else {
   516  			err = errNotAllowdFlagFormat
   517  		}
   518  	case option.JsonEscapeFlag:
   519  		if s, ok := value.(string); ok {
   520  			err = tx.Flags.SetJsonEscape(s)
   521  		} else {
   522  			err = errNotAllowdFlagFormat
   523  		}
   524  	case option.PrettyPrintFlag:
   525  		if b, ok := value.(bool); ok {
   526  			tx.Flags.SetPrettyPrint(b)
   527  		} else {
   528  			err = errNotAllowdFlagFormat
   529  		}
   530  	case option.ScientificNotationFlag:
   531  		if b, ok := value.(bool); ok {
   532  			tx.Flags.SetScientificNotation(b)
   533  		} else {
   534  			err = errNotAllowdFlagFormat
   535  		}
   536  	case option.StripEndingLineBreakFlag:
   537  		if b, ok := value.(bool); ok {
   538  			tx.Flags.SetStripEndingLineBreak(b)
   539  		} else {
   540  			err = errNotAllowdFlagFormat
   541  		}
   542  	case option.EastAsianEncodingFlag:
   543  		if b, ok := value.(bool); ok {
   544  			tx.Flags.SetEastAsianEncoding(b)
   545  		} else {
   546  			err = errNotAllowdFlagFormat
   547  		}
   548  	case option.CountDiacriticalSignFlag:
   549  		if b, ok := value.(bool); ok {
   550  			tx.Flags.SetCountDiacriticalSign(b)
   551  		} else {
   552  			err = errNotAllowdFlagFormat
   553  		}
   554  	case option.CountFormatCodeFlag:
   555  		if b, ok := value.(bool); ok {
   556  			tx.Flags.SetCountFormatCode(b)
   557  		} else {
   558  			err = errNotAllowdFlagFormat
   559  		}
   560  	case option.ColorFlag:
   561  		if b, ok := value.(bool); ok {
   562  			tx.UseColor(b)
   563  		} else {
   564  			err = errNotAllowdFlagFormat
   565  		}
   566  	case option.QuietFlag:
   567  		if b, ok := value.(bool); ok {
   568  			tx.Flags.SetQuiet(b)
   569  		} else {
   570  			err = errNotAllowdFlagFormat
   571  		}
   572  	case option.LimitRecursion:
   573  		if i, ok := value.(int64); ok {
   574  			tx.Flags.SetLimitRecursion(i)
   575  		} else {
   576  			err = errNotAllowdFlagFormat
   577  		}
   578  	case option.CPUFlag:
   579  		if i, ok := value.(int64); ok {
   580  			tx.Flags.SetCPU(int(i))
   581  		} else {
   582  			err = errNotAllowdFlagFormat
   583  		}
   584  	case option.StatsFlag:
   585  		if b, ok := value.(bool); ok {
   586  			tx.Flags.SetStats(b)
   587  		} else {
   588  			err = errNotAllowdFlagFormat
   589  		}
   590  	default:
   591  		err = errInvalidFlagName
   592  	}
   593  
   594  	return err
   595  }
   596  
   597  func (tx *Transaction) GetFlag(key string) (value.Primary, bool) {
   598  	tx.flagMutex.RLock()
   599  	defer tx.flagMutex.RUnlock()
   600  
   601  	var val value.Primary
   602  	var ok = true
   603  
   604  	switch strings.ToUpper(key) {
   605  	case option.RepositoryFlag:
   606  		val = value.NewString(tx.Flags.Repository)
   607  	case option.TimezoneFlag:
   608  		val = value.NewString(tx.Flags.Location)
   609  	case option.DatetimeFormatFlag:
   610  		s := ""
   611  		if 0 < len(tx.Flags.DatetimeFormat) {
   612  			list := make([]string, 0, len(tx.Flags.DatetimeFormat))
   613  			for _, f := range tx.Flags.DatetimeFormat {
   614  				list = append(list, "\""+f+"\"")
   615  			}
   616  			s = "[" + strings.Join(list, ", ") + "]"
   617  		}
   618  		val = value.NewString(s)
   619  	case option.AnsiQuotesFlag:
   620  		val = value.NewBoolean(tx.Flags.AnsiQuotes)
   621  	case option.StrictEqualFlag:
   622  		val = value.NewBoolean(tx.Flags.StrictEqual)
   623  	case option.WaitTimeoutFlag:
   624  		val = value.NewFloat(tx.Flags.WaitTimeout)
   625  	case option.ImportFormatFlag:
   626  		val = value.NewString(tx.Flags.ImportOptions.Format.String())
   627  	case option.DelimiterFlag:
   628  		val = value.NewString(string(tx.Flags.ImportOptions.Delimiter))
   629  	case option.AllowUnevenFieldsFlag:
   630  		val = value.NewBoolean(tx.Flags.ImportOptions.AllowUnevenFields)
   631  	case option.DelimiterPositionsFlag:
   632  		s := fixedlen.DelimiterPositions(tx.Flags.ImportOptions.DelimiterPositions).String()
   633  		if tx.Flags.ImportOptions.SingleLine {
   634  			s = "S" + s
   635  		}
   636  		val = value.NewString(s)
   637  	case option.JsonQueryFlag:
   638  		val = value.NewString(tx.Flags.ImportOptions.JsonQuery)
   639  	case option.EncodingFlag:
   640  		val = value.NewString(tx.Flags.ImportOptions.Encoding.String())
   641  	case option.NoHeaderFlag:
   642  		val = value.NewBoolean(tx.Flags.ImportOptions.NoHeader)
   643  	case option.WithoutNullFlag:
   644  		val = value.NewBoolean(tx.Flags.ImportOptions.WithoutNull)
   645  	case option.FormatFlag:
   646  		val = value.NewString(tx.Flags.ExportOptions.Format.String())
   647  	case option.ExportEncodingFlag:
   648  		val = value.NewString(tx.Flags.ExportOptions.Encoding.String())
   649  	case option.ExportDelimiterFlag:
   650  		val = value.NewString(string(tx.Flags.ExportOptions.Delimiter))
   651  	case option.ExportDelimiterPositionsFlag:
   652  		s := fixedlen.DelimiterPositions(tx.Flags.ExportOptions.DelimiterPositions).String()
   653  		if tx.Flags.ExportOptions.SingleLine {
   654  			s = "S" + s
   655  		}
   656  		val = value.NewString(s)
   657  	case option.WithoutHeaderFlag:
   658  		val = value.NewBoolean(tx.Flags.ExportOptions.WithoutHeader)
   659  	case option.LineBreakFlag:
   660  		val = value.NewString(tx.Flags.ExportOptions.LineBreak.String())
   661  	case option.EncloseAllFlag:
   662  		val = value.NewBoolean(tx.Flags.ExportOptions.EncloseAll)
   663  	case option.JsonEscapeFlag:
   664  		val = value.NewString(option.JsonEscapeTypeToString(tx.Flags.ExportOptions.JsonEscape))
   665  	case option.PrettyPrintFlag:
   666  		val = value.NewBoolean(tx.Flags.ExportOptions.PrettyPrint)
   667  	case option.ScientificNotationFlag:
   668  		val = value.NewBoolean(tx.Flags.ExportOptions.ScientificNotation)
   669  	case option.StripEndingLineBreakFlag:
   670  		val = value.NewBoolean(tx.Flags.ExportOptions.StripEndingLineBreak)
   671  	case option.EastAsianEncodingFlag:
   672  		val = value.NewBoolean(tx.Flags.ExportOptions.EastAsianEncoding)
   673  	case option.CountDiacriticalSignFlag:
   674  		val = value.NewBoolean(tx.Flags.ExportOptions.CountDiacriticalSign)
   675  	case option.CountFormatCodeFlag:
   676  		val = value.NewBoolean(tx.Flags.ExportOptions.CountFormatCode)
   677  	case option.ColorFlag:
   678  		val = value.NewBoolean(tx.Flags.ExportOptions.Color)
   679  	case option.QuietFlag:
   680  		val = value.NewBoolean(tx.Flags.Quiet)
   681  	case option.LimitRecursion:
   682  		val = value.NewInteger(tx.Flags.LimitRecursion)
   683  	case option.CPUFlag:
   684  		val = value.NewInteger(int64(tx.Flags.CPU))
   685  	case option.StatsFlag:
   686  		val = value.NewBoolean(tx.Flags.Stats)
   687  	default:
   688  		ok = false
   689  	}
   690  	return val, ok
   691  }