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

     1  package query
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	gojson "encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"os"
    11  	"strconv"
    12  	"strings"
    13  	"sync"
    14  
    15  	"github.com/mithrandie/csvq/lib/file"
    16  	"github.com/mithrandie/csvq/lib/json"
    17  	"github.com/mithrandie/csvq/lib/option"
    18  	"github.com/mithrandie/csvq/lib/parser"
    19  	"github.com/mithrandie/csvq/lib/value"
    20  
    21  	"github.com/mithrandie/go-text"
    22  	"github.com/mithrandie/go-text/csv"
    23  	"github.com/mithrandie/go-text/fixedlen"
    24  	txjson "github.com/mithrandie/go-text/json"
    25  	"github.com/mithrandie/go-text/jsonl"
    26  	"github.com/mithrandie/go-text/ltsv"
    27  )
    28  
    29  const fileLoadingPreparedRecordSetCap = 300
    30  const fileLoadingBuffer = 300
    31  
    32  const inlineTablePrefix = "@__io__"
    33  
    34  type RecordReader interface {
    35  	Read() ([]text.RawText, error)
    36  }
    37  
    38  func isTableObjectAsDataObject(tablePath parser.QueryExpression) bool {
    39  	_, ok := tablePath.(parser.Identifier)
    40  	return !ok
    41  }
    42  
    43  func isTableObjectAsURL(tablePath parser.QueryExpression) bool {
    44  	i, ok := tablePath.(parser.Identifier)
    45  	if !ok {
    46  		return false
    47  	}
    48  
    49  	return strings.HasPrefix(i.Literal, "http://") || strings.HasPrefix(i.Literal, "https://")
    50  }
    51  
    52  func LoadView(ctx context.Context, scope *ReferenceScope, tables []parser.QueryExpression, forUpdate bool, useInternalId bool) (*View, error) {
    53  	if tables == nil {
    54  		var obj parser.QueryExpression
    55  		if scope.Tx.Session.CanReadStdin {
    56  			obj = parser.Stdin{}
    57  		} else {
    58  			obj = parser.Dual{}
    59  		}
    60  		tables = []parser.QueryExpression{parser.Table{Object: obj}}
    61  	}
    62  
    63  	table := tables[0]
    64  
    65  	for i := 1; i < len(tables); i++ {
    66  		table = parser.Table{
    67  			Object: parser.Join{
    68  				Table:     table,
    69  				JoinTable: tables[i],
    70  				JoinType:  parser.Token{Token: parser.CROSS},
    71  			},
    72  		}
    73  	}
    74  
    75  	view, err := loadView(ctx, scope, table, forUpdate, useInternalId)
    76  	return view, err
    77  }
    78  
    79  func LoadViewFromTableIdentifier(ctx context.Context, scope *ReferenceScope, table parser.QueryExpression, forUpdate bool, useInternalId bool) (*View, error) {
    80  	tables := []parser.QueryExpression{
    81  		parser.Table{Object: table},
    82  	}
    83  
    84  	return LoadView(ctx, scope, tables, forUpdate, useInternalId)
    85  }
    86  
    87  func loadView(ctx context.Context, scope *ReferenceScope, tableExpr parser.QueryExpression, forUpdate bool, useInternalId bool) (view *View, err error) {
    88  	if parentheses, ok := tableExpr.(parser.Parentheses); ok {
    89  		return loadView(ctx, scope, parentheses.Expr, forUpdate, useInternalId)
    90  	}
    91  
    92  	table := tableExpr.(parser.Table)
    93  	tableName, err := ParseTableName(ctx, scope, table)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	switch table.Object.(type) {
    99  	case parser.Dual:
   100  		view = NewDualView()
   101  	case parser.FormatSpecifiedFunction:
   102  		formatSpecifiedFunction := table.Object.(parser.FormatSpecifiedFunction)
   103  		tablePath := formatSpecifiedFunction.Path
   104  		options := scope.Tx.Flags.ImportOptions.Copy()
   105  
   106  		var felem value.Primary
   107  		if formatSpecifiedFunction.FormatElement != nil {
   108  			p, err := Evaluate(ctx, scope, formatSpecifiedFunction.FormatElement)
   109  			if err != nil {
   110  				return nil, err
   111  			}
   112  			felem = value.ToString(p)
   113  		}
   114  
   115  		isInlineObject := false
   116  		switch formatSpecifiedFunction.Type.Token {
   117  		case parser.CSV_INLINE, parser.JSON_INLINE, parser.JSON_TABLE:
   118  			isInlineObject = true
   119  
   120  			if isTableObjectAsDataObject(formatSpecifiedFunction.Path) {
   121  				p, err := Evaluate(ctx, scope, formatSpecifiedFunction.Path)
   122  				if err != nil {
   123  					return nil, err
   124  				}
   125  				d := value.ToString(p)
   126  				if value.IsNull(d) {
   127  					return nil, NewEmptyInlineTableError(formatSpecifiedFunction)
   128  				}
   129  				tablePath = DataObject{BaseExpr: formatSpecifiedFunction.GetBaseExpr(), Raw: d.(*value.String).Raw()}
   130  			} else if isTableObjectAsURL(formatSpecifiedFunction.Path) {
   131  				tablePath = parser.Url{BaseExpr: formatSpecifiedFunction.GetBaseExpr(), Raw: formatSpecifiedFunction.Path.(parser.Identifier).Literal}
   132  			}
   133  
   134  			forUpdate = false
   135  
   136  			switch formatSpecifiedFunction.Type.Token {
   137  			case parser.CSV_INLINE:
   138  				formatSpecifiedFunction.Type.Token = parser.CSV
   139  			default: // JSON_INLINE, JSON_TABLE
   140  				formatSpecifiedFunction.Type.Token = parser.JSON
   141  			}
   142  		}
   143  
   144  		encodingIdx := 0
   145  		noHeaderIdx := 1
   146  		withoutNullIdx := 2
   147  
   148  		switch formatSpecifiedFunction.Type.Token {
   149  		case parser.CSV:
   150  			if felem == nil {
   151  				return nil, NewTableObjectInvalidArgumentError(formatSpecifiedFunction, "delimiter is not specified")
   152  			}
   153  			if value.IsNull(felem) {
   154  				return nil, NewTableObjectInvalidDelimiterError(formatSpecifiedFunction, formatSpecifiedFunction.FormatElement.String())
   155  			}
   156  			s := felem.(*value.String).Raw()
   157  			d := []rune(s)
   158  			if 1 != len(d) {
   159  				return nil, NewTableObjectInvalidDelimiterError(formatSpecifiedFunction, formatSpecifiedFunction.FormatElement.String())
   160  			}
   161  			if 3 < len(formatSpecifiedFunction.Args) {
   162  				return nil, NewTableObjectArgumentsLengthError(formatSpecifiedFunction, 5)
   163  			}
   164  			options.Delimiter = d[0]
   165  			if options.Delimiter == '\t' {
   166  				options.Format = option.TSV
   167  			} else {
   168  				options.Format = option.CSV
   169  			}
   170  		case parser.FIXED:
   171  			if felem == nil {
   172  				return nil, NewTableObjectInvalidArgumentError(formatSpecifiedFunction, "delimiter positions are not specified")
   173  			}
   174  			if value.IsNull(felem) {
   175  				return nil, NewTableObjectInvalidDelimiterPositionsError(formatSpecifiedFunction, formatSpecifiedFunction.FormatElement.String())
   176  			}
   177  			s := felem.(*value.String).Raw()
   178  
   179  			var positions []int
   180  			if !strings.EqualFold("SPACES", s) {
   181  				if strings.HasPrefix(s, "s[") || strings.HasPrefix(s, "S[") {
   182  					options.SingleLine = true
   183  					s = s[1:]
   184  				}
   185  				err = gojson.Unmarshal([]byte(s), &positions)
   186  				if err != nil {
   187  					return nil, NewTableObjectInvalidDelimiterPositionsError(formatSpecifiedFunction, formatSpecifiedFunction.FormatElement.String())
   188  				}
   189  			}
   190  			if 3 < len(formatSpecifiedFunction.Args) {
   191  				return nil, NewTableObjectArgumentsLengthError(formatSpecifiedFunction, 5)
   192  			}
   193  			options.DelimiterPositions = positions
   194  			options.Format = option.FIXED
   195  		case parser.JSON, parser.JSONL:
   196  			if felem == nil {
   197  				return nil, NewTableObjectInvalidArgumentError(formatSpecifiedFunction, "json query is not specified")
   198  			}
   199  			if value.IsNull(felem) {
   200  				return nil, NewTableObjectInvalidJsonQueryError(formatSpecifiedFunction, formatSpecifiedFunction.FormatElement.String())
   201  			}
   202  			if 0 < len(formatSpecifiedFunction.Args) {
   203  				return nil, NewTableObjectJsonArgumentsLengthError(formatSpecifiedFunction, 2)
   204  			}
   205  
   206  			options.JsonQuery = felem.(*value.String).Raw()
   207  			options.Encoding = text.UTF8
   208  			if formatSpecifiedFunction.Type.Token == parser.JSONL {
   209  				options.Format = option.JSONL
   210  			} else {
   211  				options.Format = option.JSON
   212  			}
   213  		case parser.LTSV:
   214  			if 2 < len(formatSpecifiedFunction.Args) {
   215  				return nil, NewTableObjectJsonArgumentsLengthError(formatSpecifiedFunction, 3)
   216  			}
   217  			options.Format = option.LTSV
   218  			withoutNullIdx, noHeaderIdx = noHeaderIdx, withoutNullIdx
   219  		default:
   220  			return nil, NewInvalidTableObjectError(formatSpecifiedFunction, formatSpecifiedFunction.Type.Literal)
   221  		}
   222  
   223  		args := make([]value.Primary, 3)
   224  		defer func() {
   225  			for i := range args {
   226  				if args[i] != nil {
   227  					value.Discard(args[i])
   228  				}
   229  			}
   230  		}()
   231  
   232  		for i, a := range formatSpecifiedFunction.Args {
   233  			if pt, ok := a.(parser.PrimitiveType); ok && value.IsNull(pt.Value) {
   234  				continue
   235  			}
   236  
   237  			var p value.Primary = value.NewNull()
   238  			if fr, ok := a.(parser.FieldReference); ok {
   239  				if col, ok := fr.Column.(parser.Identifier); ok {
   240  					a = parser.NewStringValue(col.Literal)
   241  				} else {
   242  					return nil, NewTableObjectInvalidArgumentError(formatSpecifiedFunction, fmt.Sprintf("cannot be converted as an argument: %s", formatSpecifiedFunction.Args[encodingIdx].String()))
   243  				}
   244  			}
   245  			if pv, err := Evaluate(ctx, scope, a); err == nil {
   246  				p = pv
   247  			}
   248  
   249  			switch i {
   250  			case encodingIdx:
   251  				v := value.ToString(p)
   252  				if !value.IsNull(v) {
   253  					args[i] = v
   254  				} else {
   255  					return nil, NewTableObjectInvalidArgumentError(formatSpecifiedFunction, fmt.Sprintf("cannot be converted as a encoding value: %s", formatSpecifiedFunction.Args[encodingIdx].String()))
   256  				}
   257  			case noHeaderIdx:
   258  				v := value.ToBoolean(p)
   259  				if !value.IsNull(v) {
   260  					args[i] = v
   261  				} else {
   262  					return nil, NewTableObjectInvalidArgumentError(formatSpecifiedFunction, fmt.Sprintf("cannot be converted as a no-header value: %s", formatSpecifiedFunction.Args[noHeaderIdx].String()))
   263  				}
   264  			case withoutNullIdx:
   265  				v := value.ToBoolean(p)
   266  				if !value.IsNull(v) {
   267  					args[i] = v
   268  				} else {
   269  					return nil, NewTableObjectInvalidArgumentError(formatSpecifiedFunction, fmt.Sprintf("cannot be converted as a without-null value: %s", formatSpecifiedFunction.Args[withoutNullIdx].String()))
   270  				}
   271  			}
   272  		}
   273  
   274  		if args[encodingIdx] != nil {
   275  			if options.Encoding, err = option.ParseEncoding(args[0].(*value.String).Raw()); err != nil {
   276  				return nil, NewTableObjectInvalidArgumentError(formatSpecifiedFunction, err.Error())
   277  			}
   278  		}
   279  		if args[noHeaderIdx] != nil {
   280  			options.NoHeader = args[noHeaderIdx].(*value.Boolean).Raw()
   281  		}
   282  		if args[withoutNullIdx] != nil {
   283  			options.WithoutNull = args[withoutNullIdx].(*value.Boolean).Raw()
   284  		}
   285  
   286  		view, err = loadObject(
   287  			ctx,
   288  			scope,
   289  			tablePath,
   290  			tableName,
   291  			forUpdate,
   292  			useInternalId,
   293  			isInlineObject,
   294  			options,
   295  		)
   296  		if err != nil {
   297  			return nil, err
   298  		}
   299  
   300  	case parser.Identifier, parser.Url, parser.TableFunction, parser.Stdin:
   301  		options := scope.Tx.Flags.ImportOptions.Copy()
   302  		options.Format = option.AutoSelect
   303  
   304  		view, err = loadObject(
   305  			ctx,
   306  			scope,
   307  			table.Object,
   308  			tableName,
   309  			forUpdate,
   310  			useInternalId,
   311  			false,
   312  			options,
   313  		)
   314  		if err != nil {
   315  			return nil, err
   316  		}
   317  
   318  	case parser.Join:
   319  		join := table.Object.(parser.Join)
   320  		view, err = loadView(ctx, scope, join.Table, forUpdate, useInternalId)
   321  		if err != nil {
   322  			return nil, err
   323  		}
   324  
   325  		if t, ok := join.JoinTable.(parser.Table); ok && !t.Lateral.IsEmpty() {
   326  			switch join.Direction.Token {
   327  			case parser.RIGHT, parser.FULL:
   328  				return nil, NewIncorrectLateralUsageError(t)
   329  			}
   330  
   331  			joinTableName, err := ParseTableName(ctx, scope, t)
   332  			if err != nil {
   333  				return nil, err
   334  			}
   335  
   336  			subquery := t.Object.(parser.Subquery)
   337  			var hfields Header
   338  			resultSetList := make([]RecordSet, view.RecordLen())
   339  
   340  			if err := EvaluateSequentially(ctx, scope, view, func(seqScope *ReferenceScope, rIdx int) error {
   341  				appliedView, err := Select(ctx, seqScope, subquery.Query)
   342  				if err != nil {
   343  					return err
   344  				}
   345  
   346  				if 0 < len(joinTableName.Literal) {
   347  					if err = appliedView.Header.Update(joinTableName.Literal, nil); err != nil {
   348  						return err
   349  					}
   350  				}
   351  
   352  				calcView := NewView()
   353  				calcView.Header = view.Header.Copy()
   354  				calcView.RecordSet = RecordSet{view.RecordSet[rIdx].Copy()}
   355  				if err = joinViews(ctx, scope, calcView, appliedView, join); err != nil {
   356  					return err
   357  				}
   358  
   359  				if rIdx == 0 {
   360  					hfields = calcView.Header
   361  				}
   362  				resultSetList[rIdx] = calcView.RecordSet
   363  				return nil
   364  			}); err != nil {
   365  				return nil, err
   366  			}
   367  
   368  			resultSet := make(RecordSet, 0, view.RecordLen())
   369  			for i := range resultSetList {
   370  				resultSet = append(resultSet, resultSetList[i]...)
   371  			}
   372  
   373  			view.Header = hfields
   374  			view.RecordSet = resultSet
   375  			view.FileInfo = nil
   376  
   377  		} else {
   378  			joinView, err := loadView(ctx, scope, join.JoinTable, forUpdate, useInternalId)
   379  			if err != nil {
   380  				return nil, err
   381  			}
   382  
   383  			if err = joinViews(ctx, scope, view, joinView, join); err != nil {
   384  				return nil, err
   385  			}
   386  		}
   387  
   388  	case parser.Subquery:
   389  		subquery := table.Object.(parser.Subquery)
   390  		view, err = Select(ctx, scope, subquery.Query)
   391  		if err != nil {
   392  			return nil, err
   393  		}
   394  
   395  		if 0 < len(tableName.Literal) {
   396  			if err := scope.AddAlias(tableName, ""); err != nil {
   397  				return nil, err
   398  			}
   399  
   400  			if err = view.Header.Update(tableName.Literal, nil); err != nil {
   401  				return nil, err
   402  			}
   403  		}
   404  
   405  		if view.FileInfo != nil {
   406  			view.FileInfo.ViewType = ViewTypeInlineTable
   407  		}
   408  	}
   409  
   410  	if view.FileInfo != nil && !(view.FileInfo.IsUpdatable() || view.FileInfo.IsRemoteObject()) {
   411  		view.FileInfo.Path = ""
   412  	}
   413  
   414  	return view, err
   415  }
   416  
   417  func joinViews(ctx context.Context, scope *ReferenceScope, view *View, joinView *View, join parser.Join) error {
   418  	condition, includeFields, excludeFields, err := ParseJoinCondition(join, view, joinView)
   419  	if err != nil {
   420  		return err
   421  	}
   422  
   423  	joinType := join.JoinType.Token
   424  	if join.JoinType.IsEmpty() {
   425  		if join.Direction.IsEmpty() {
   426  			joinType = parser.INNER
   427  		} else {
   428  			joinType = parser.OUTER
   429  		}
   430  	}
   431  
   432  	switch joinType {
   433  	case parser.CROSS:
   434  		if err = CrossJoin(ctx, scope, view, joinView); err != nil {
   435  			return err
   436  		}
   437  	case parser.INNER:
   438  		if err = InnerJoin(ctx, scope, view, joinView, condition); err != nil {
   439  			return err
   440  		}
   441  	case parser.OUTER:
   442  		if err = OuterJoin(ctx, scope, view, joinView, condition, join.Direction.Token); err != nil {
   443  			return err
   444  		}
   445  	}
   446  
   447  	if includeFields != nil {
   448  		includeIndices := NewUintPool(len(includeFields), LimitToUseUintSlicePool)
   449  		excludeIndices := NewUintPool(view.FieldLen()-len(includeFields), LimitToUseUintSlicePool)
   450  		alternatives := make(map[int]int)
   451  
   452  		for i := range includeFields {
   453  			idx, _ := view.Header.SearchIndex(includeFields[i])
   454  			includeIndices.Add(uint(idx))
   455  
   456  			eidx, _ := view.Header.SearchIndex(excludeFields[i])
   457  			excludeIndices.Add(uint(eidx))
   458  
   459  			alternatives[idx] = eidx
   460  		}
   461  
   462  		fieldIndices := make([]int, 0, view.FieldLen()-excludeIndices.Len())
   463  		header := make(Header, 0, view.FieldLen()-excludeIndices.Len())
   464  		_ = includeIndices.Range(func(_ int, fidx uint) error {
   465  			view.Header[fidx].View = ""
   466  			view.Header[fidx].Number = 0
   467  			view.Header[fidx].IsJoinColumn = true
   468  			header = append(header, view.Header[fidx])
   469  			fieldIndices = append(fieldIndices, int(fidx))
   470  			return nil
   471  		})
   472  		for i := range view.Header {
   473  			if excludeIndices.Exists(uint(i)) || includeIndices.Exists(uint(i)) {
   474  				continue
   475  			}
   476  			header = append(header, view.Header[i])
   477  			fieldIndices = append(fieldIndices, i)
   478  		}
   479  		view.Header = header
   480  		fieldLen := len(fieldIndices)
   481  
   482  		if err = NewGoroutineTaskManager(view.RecordLen(), -1, scope.Tx.Flags.CPU).Run(ctx, func(index int) error {
   483  			record := make(Record, fieldLen)
   484  			for i, idx := range fieldIndices {
   485  				if includeIndices.Exists(uint(idx)) && value.IsNull(view.RecordSet[index][idx][0]) {
   486  					record[i] = view.RecordSet[index][alternatives[idx]]
   487  				} else {
   488  					record[i] = view.RecordSet[index][idx]
   489  				}
   490  			}
   491  			view.RecordSet[index] = record
   492  			return nil
   493  		}); err != nil {
   494  			return err
   495  		}
   496  	}
   497  
   498  	return nil
   499  }
   500  
   501  func loadObjectFromStdin(
   502  	ctx context.Context,
   503  	scope *ReferenceScope,
   504  	stdin parser.Stdin,
   505  	tableName parser.Identifier,
   506  	forUpdate bool,
   507  	useInternalId bool,
   508  	options option.ImportOptions,
   509  ) (*View, error) {
   510  	if options.Format == option.AutoSelect {
   511  		options.Format = scope.Tx.Flags.ImportOptions.Format
   512  	}
   513  
   514  	fileInfo := NewStdinFileInfo(stdin.String(), options, scope.Tx.Flags.ExportOptions)
   515  
   516  	scope.Tx.viewLoadingMutex.Lock()
   517  	defer scope.Tx.viewLoadingMutex.Unlock()
   518  
   519  	var err error
   520  	view, ok := scope.Global().TemporaryTables.Load(stdin.String())
   521  	if !ok || (forUpdate && !view.FileInfo.ForUpdate) {
   522  		if forUpdate {
   523  			if err = scope.Tx.LockStdinContext(ctx); err != nil {
   524  				return nil, err
   525  			}
   526  		} else {
   527  			if err = scope.Tx.RLockStdinContext(ctx); err != nil {
   528  				return nil, err
   529  			}
   530  			defer scope.Tx.RUnlockStdin()
   531  		}
   532  		view, err = scope.Tx.Session.GetStdinView(ctx, scope.Tx.Flags, fileInfo, stdin)
   533  		if err != nil {
   534  			return nil, err
   535  		}
   536  		scope.Global().TemporaryTables.Set(view)
   537  	}
   538  
   539  	if useInternalId {
   540  		if view, err = scope.Global().TemporaryTables.GetWithInternalId(ctx, stdin.String(), scope.Tx.Flags); err != nil {
   541  			if err == errTableNotLoaded {
   542  				err = NewUndeclaredTemporaryTableError(parser.Identifier{Literal: stdin.String()})
   543  			}
   544  			return nil, err
   545  		}
   546  	} else {
   547  		if view, err = scope.Global().TemporaryTables.Get(stdin.String()); err != nil {
   548  			if err == errTableNotLoaded {
   549  				err = NewUndeclaredTemporaryTableError(parser.Identifier{Literal: stdin.String()})
   550  			}
   551  			return nil, err
   552  		}
   553  	}
   554  
   555  	if err = scope.AddAlias(tableName, view.FileInfo.Path); err != nil {
   556  		return nil, err
   557  	}
   558  
   559  	if !strings.EqualFold(stdin.String(), tableName.Literal) {
   560  		if err = view.Header.Update(tableName.Literal, nil); err != nil {
   561  			return nil, err
   562  		}
   563  	}
   564  
   565  	return view, nil
   566  }
   567  
   568  func loadObjectFromString(
   569  	ctx context.Context,
   570  	scope *ReferenceScope,
   571  	data string,
   572  	tablePath parser.QueryExpression,
   573  	tableName parser.Identifier,
   574  	options option.ImportOptions,
   575  ) (*View, error) {
   576  	fileInfo := NewInlineFileInfo(inlineTablePrefix+file.RandomString(12), options, scope.Tx.Flags.ExportOptions)
   577  
   578  	r := strings.NewReader(data)
   579  	view, err := loadViewFromFile(ctx, scope.Tx.Flags, r, fileInfo, options, tablePath)
   580  	if err != nil {
   581  		if _, ok := err.(Error); !ok {
   582  			err = NewDataParsingError(tablePath, tablePath.String(), err.Error())
   583  		}
   584  		return nil, err
   585  	}
   586  
   587  	if 0 < len(tableName.Literal) {
   588  		if err = scope.AddAlias(tableName, ""); err != nil {
   589  			return nil, err
   590  		}
   591  		if err = view.Header.Update(tableName.Literal, nil); err != nil {
   592  			return nil, err
   593  		}
   594  	}
   595  
   596  	return view, nil
   597  }
   598  
   599  func loadDataObject(
   600  	ctx context.Context,
   601  	scope *ReferenceScope,
   602  	dataObject DataObject,
   603  	tablePath parser.QueryExpression,
   604  	tableName parser.Identifier,
   605  	options option.ImportOptions,
   606  ) (*View, error) {
   607  	if options.Format == option.AutoSelect {
   608  		options.Format = scope.Tx.Flags.ImportOptions.Format
   609  	}
   610  
   611  	view, err := loadObjectFromString(ctx, scope, dataObject.Raw, tablePath, tableName, options)
   612  	if err == nil {
   613  		view.FileInfo.ViewType = ViewTypeStringObject
   614  	}
   615  	return view, err
   616  }
   617  
   618  func loadHttpObject(
   619  	ctx context.Context,
   620  	scope *ReferenceScope,
   621  	httpObject HttpObject,
   622  	tablePath parser.QueryExpression,
   623  	tableName parser.Identifier,
   624  	options option.ImportOptions,
   625  ) (*View, error) {
   626  	scope.Tx.viewLoadingMutex.Lock()
   627  
   628  	urlResource, ok := scope.Tx.UrlCache[httpObject.URL]
   629  	if !ok {
   630  		res, err := http.Get(httpObject.URL)
   631  		if err != nil {
   632  			scope.Tx.viewLoadingMutex.Unlock()
   633  			return nil, NewHttpRequestError(tablePath, httpObject.URL, err.Error())
   634  		}
   635  		if 400 <= res.StatusCode {
   636  			scope.Tx.viewLoadingMutex.Unlock()
   637  			return nil, NewHttpRequestError(tablePath, httpObject.URL, fmt.Sprintf("code %d, status %q", res.StatusCode, res.Status))
   638  		}
   639  
   640  		urlResource, err = NewUrlResource(res)
   641  		if err != nil {
   642  			scope.Tx.viewLoadingMutex.Unlock()
   643  			return nil, err
   644  		}
   645  		scope.Tx.UrlCache[httpObject.URL] = urlResource
   646  	}
   647  
   648  	data := string(urlResource.Data)
   649  	scope.Tx.viewLoadingMutex.Unlock()
   650  
   651  	if options.Format == option.AutoSelect {
   652  		switch urlResource.MimeType {
   653  		case "text/csv":
   654  			options.Format = option.CSV
   655  		case "application/json":
   656  			options.Format = option.JSON
   657  		default:
   658  			options.Format = scope.Tx.Flags.ImportOptions.Format
   659  		}
   660  	}
   661  
   662  	view, err := loadObjectFromString(ctx, scope, data, tablePath, tableName, options)
   663  	if err == nil {
   664  		view.FileInfo.Path = httpObject.URL
   665  		view.FileInfo.ViewType = ViewTypeRemoteObject
   666  	}
   667  	return view, err
   668  }
   669  
   670  func loadInlineObjectFromFile(
   671  	ctx context.Context,
   672  	scope *ReferenceScope,
   673  	tableIdentifier parser.Identifier,
   674  	tableName parser.Identifier,
   675  	options option.ImportOptions,
   676  ) (view *View, err error) {
   677  	scope.Tx.viewLoadingMutex.Lock()
   678  	defer scope.Tx.viewLoadingMutex.Unlock()
   679  
   680  	fileInfo, err := NewFileInfo(tableIdentifier, scope.Tx.Flags.Repository, options, scope.Tx.Flags.ImportOptions.Format)
   681  	if err != nil {
   682  		return
   683  	}
   684  	fileInfo.ViewType = ViewTypeInlineTable
   685  	fileInfo.SetDefaultFileInfoAttributes(options, scope.Tx.Flags.ExportOptions)
   686  
   687  	var fp *os.File
   688  
   689  	cachedView, cacheExists := scope.Tx.CachedViews.Load(fileInfo.IdentifiedPath())
   690  
   691  	if cacheExists {
   692  		fp = cachedView.FileInfo.Handler.File()
   693  	} else {
   694  		h, e := scope.Tx.FileContainer.CreateHandlerForRead(ctx, fileInfo.Path, scope.Tx.WaitTimeout, scope.Tx.RetryDelay)
   695  		if e != nil {
   696  			tableIdentifier.Literal = fileInfo.Path
   697  			err = ConvertFileHandlerError(e, tableIdentifier)
   698  			return
   699  		}
   700  		defer func() {
   701  			err = appendCompositeError(err, scope.Tx.FileContainer.Close(h))
   702  		}()
   703  		fp = h.File()
   704  	}
   705  	_, err = fp.Seek(0, io.SeekStart)
   706  	if err != nil {
   707  		return nil, NewIOError(tableIdentifier, err.Error())
   708  	}
   709  
   710  	view, err = loadViewFromFile(ctx, scope.Tx.Flags, fp, fileInfo, options, tableIdentifier)
   711  	if err != nil {
   712  		if _, ok := err.(Error); !ok {
   713  			err = NewDataParsingError(tableIdentifier, fileInfo.Path, err.Error())
   714  		}
   715  		return
   716  	}
   717  
   718  	if 0 < len(tableName.Literal) {
   719  		if err = scope.AddAlias(tableName, ""); err != nil {
   720  			return
   721  		}
   722  		if err = view.Header.Update(tableName.Literal, nil); err != nil {
   723  			return
   724  		}
   725  	}
   726  
   727  	if !scope.FilePathExists(tableIdentifier.Literal) {
   728  		scope.StoreFilePath(tableIdentifier.Literal, view.FileInfo.Path)
   729  	}
   730  
   731  	return
   732  }
   733  
   734  func loadObjectFromFile(
   735  	ctx context.Context,
   736  	scope *ReferenceScope,
   737  	fileIdentifier parser.Identifier,
   738  	tableName parser.Identifier,
   739  	forUpdate bool,
   740  	useInternalId bool,
   741  	options option.ImportOptions,
   742  ) (view *View, err error) {
   743  	filePath, err := cacheViewFromFile(
   744  		ctx,
   745  		scope,
   746  		fileIdentifier,
   747  		forUpdate,
   748  		options,
   749  	)
   750  	if err != nil {
   751  		return
   752  	}
   753  
   754  	if useInternalId {
   755  		if view, err = scope.Tx.CachedViews.GetWithInternalId(ctx, strings.ToUpper(filePath), scope.Tx.Flags); err != nil {
   756  			if err == errTableNotLoaded {
   757  				err = NewTableNotLoadedError(parser.Identifier{BaseExpr: fileIdentifier.GetBaseExpr(), Literal: filePath})
   758  			}
   759  			return
   760  		}
   761  	} else {
   762  		if view, err = scope.Tx.CachedViews.Get(strings.ToUpper(filePath)); err != nil {
   763  			err = NewTableNotLoadedError(parser.Identifier{BaseExpr: fileIdentifier.GetBaseExpr(), Literal: filePath})
   764  			return
   765  		}
   766  	}
   767  
   768  	if 0 < len(tableName.Literal) {
   769  		if err = scope.AddAlias(tableName, filePath); err != nil {
   770  			return
   771  		}
   772  	}
   773  
   774  	if !strings.EqualFold(FormatTableName(filePath), tableName.Literal) {
   775  		if err = view.Header.Update(tableName.Literal, nil); err != nil {
   776  			return
   777  		}
   778  	}
   779  
   780  	return
   781  }
   782  
   783  func loadObject(
   784  	ctx context.Context,
   785  	scope *ReferenceScope,
   786  	tablePath parser.QueryExpression,
   787  	tableName parser.Identifier,
   788  	forUpdate bool,
   789  	useInternalId bool,
   790  	isInlineObject bool,
   791  	options option.ImportOptions,
   792  ) (*View, error) {
   793  	if stdin, ok := tablePath.(parser.Stdin); ok {
   794  		return loadObjectFromStdin(ctx, scope, stdin, tableName, forUpdate, useInternalId, options)
   795  	}
   796  
   797  	if !isInlineObject {
   798  		if tableFunction, ok := tablePath.(parser.TableFunction); ok && strings.ToUpper(tableFunction.Name) == "INLINE" {
   799  			isInlineObject = true
   800  		}
   801  	}
   802  
   803  	originalTablePath := tablePath
   804  	tablePath, err := NormalizeTableObject(ctx, scope, tablePath)
   805  	if err != nil {
   806  		return nil, err
   807  	}
   808  
   809  	if dataObject, ok := tablePath.(DataObject); ok {
   810  		return loadDataObject(ctx, scope, dataObject, originalTablePath, tableName, options)
   811  	}
   812  
   813  	if httpObject, ok := tablePath.(HttpObject); ok {
   814  		return loadHttpObject(ctx, scope, httpObject, originalTablePath, tableName, options)
   815  	}
   816  
   817  	fileIdentifier := tablePath.(parser.Identifier)
   818  
   819  	if isInlineObject {
   820  		return loadInlineObjectFromFile(ctx, scope, fileIdentifier, tableName, options)
   821  	}
   822  
   823  	if scope.RecursiveTable != nil && strings.EqualFold(fileIdentifier.Literal, scope.RecursiveTable.Name.Literal) && scope.RecursiveTmpView != nil {
   824  		view := scope.RecursiveTmpView.Copy()
   825  		if !strings.EqualFold(scope.RecursiveTable.Name.Literal, tableName.Literal) {
   826  			if err := view.Header.Update(tableName.Literal, nil); err != nil {
   827  				return nil, err
   828  			}
   829  		}
   830  		return view, nil
   831  	}
   832  
   833  	if scope.InlineTableExists(fileIdentifier) {
   834  		if err := scope.AddAlias(tableName, ""); err != nil {
   835  			return nil, err
   836  		}
   837  
   838  		view, _ := scope.GetInlineTable(fileIdentifier)
   839  		if !strings.EqualFold(fileIdentifier.Literal, tableName.Literal) {
   840  			if err := view.Header.Update(tableName.Literal, nil); err != nil {
   841  				return nil, err
   842  			}
   843  		}
   844  		return view, nil
   845  	}
   846  
   847  	if scope.TemporaryTableExists(fileIdentifier.Literal) {
   848  		var view *View = nil
   849  		var err error
   850  
   851  		if useInternalId {
   852  			view, err = scope.GetTemporaryTableWithInternalId(ctx, fileIdentifier, scope.Tx.Flags)
   853  		} else {
   854  			view, err = scope.GetTemporaryTable(fileIdentifier)
   855  		}
   856  		if err != nil {
   857  			return nil, err
   858  		}
   859  
   860  		if err := scope.AddAlias(tableName, fileIdentifier.Literal); err != nil {
   861  			return nil, err
   862  		}
   863  
   864  		if !strings.EqualFold(FormatTableName(fileIdentifier.Literal), tableName.Literal) {
   865  			if err := view.Header.Update(tableName.Literal, nil); err != nil {
   866  				return nil, err
   867  			}
   868  		}
   869  
   870  		return view, nil
   871  	}
   872  
   873  	return loadObjectFromFile(ctx, scope, fileIdentifier, tableName, forUpdate, useInternalId, options)
   874  }
   875  
   876  func cacheViewFromFile(
   877  	ctx context.Context,
   878  	scope *ReferenceScope,
   879  	fileIdentifier parser.Identifier,
   880  	forUpdate bool,
   881  	options option.ImportOptions,
   882  ) (filePath string, err error) {
   883  	scope.Tx.viewLoadingMutex.Lock()
   884  	defer scope.Tx.viewLoadingMutex.Unlock()
   885  
   886  	filePath, view, isCached, err := func() (string, *View, bool, error) {
   887  		if p, ok := scope.LoadFilePath(fileIdentifier.Literal); ok {
   888  			if v, ok := scope.Tx.CachedViews.Load(strings.ToUpper(p)); ok {
   889  				return p, v, true, nil
   890  			}
   891  		}
   892  
   893  		// Uncommitted newly created tables are not yet created as files, so they need to be checked if they are
   894  		// registered in the cache with CreateFilePath(), instead of SearchFilePath().
   895  		p, e := CreateFilePath(fileIdentifier, scope.Tx.Flags.Repository)
   896  		if e != nil {
   897  			return "", nil, false, NewIOError(fileIdentifier, err.Error())
   898  		}
   899  		if v, ok := scope.Tx.CachedViews.Load(strings.ToUpper(p)); ok {
   900  			return p, v, true, nil
   901  		}
   902  
   903  		p, _, e = SearchFilePath(fileIdentifier, scope.Tx.Flags.Repository, options, scope.Tx.Flags.ImportOptions.Format)
   904  		if e != nil {
   905  			return "", nil, false, e
   906  		}
   907  		v, ok := scope.Tx.CachedViews.Load(strings.ToUpper(p))
   908  		return p, v, ok, nil
   909  	}()
   910  	if err != nil {
   911  		return
   912  	}
   913  
   914  	if !isCached || (forUpdate && !view.FileInfo.ForUpdate) {
   915  		var fileInfo *FileInfo = nil
   916  		if isCached {
   917  			fileInfo = view.FileInfo
   918  			if err = scope.Tx.CachedViews.Dispose(scope.Tx.FileContainer, fileInfo.IdentifiedPath()); err != nil {
   919  				return
   920  			}
   921  		} else {
   922  			fileInfo, err = NewFileInfo(fileIdentifier, scope.Tx.Flags.Repository, options, scope.Tx.Flags.ImportOptions.Format)
   923  			if err != nil {
   924  				return
   925  			}
   926  			fileInfo.SetDefaultFileInfoAttributes(options, scope.Tx.Flags.ExportOptions)
   927  			filePath = fileInfo.Path
   928  		}
   929  
   930  		var fp *os.File
   931  
   932  		if forUpdate {
   933  			h, e := scope.Tx.FileContainer.CreateHandlerForUpdate(ctx, fileInfo.Path, scope.Tx.WaitTimeout, scope.Tx.RetryDelay)
   934  			if e != nil {
   935  				fileIdentifier.Literal = fileInfo.Path
   936  				err = ConvertFileHandlerError(e, fileIdentifier)
   937  				return
   938  			}
   939  			fileInfo.Handler = h
   940  			fp = h.File()
   941  		} else {
   942  			h, e := scope.Tx.FileContainer.CreateHandlerForRead(ctx, fileInfo.Path, scope.Tx.WaitTimeout, scope.Tx.RetryDelay)
   943  			if e != nil {
   944  				fileIdentifier.Literal = fileInfo.Path
   945  				err = ConvertFileHandlerError(e, fileIdentifier)
   946  				return
   947  			}
   948  			defer func() {
   949  				err = appendCompositeError(err, scope.Tx.FileContainer.Close(h))
   950  			}()
   951  			fp = h.File()
   952  		}
   953  		_, err = fp.Seek(0, io.SeekStart)
   954  		if err != nil {
   955  			return filePath, NewIOError(fileIdentifier, err.Error())
   956  		}
   957  
   958  		view, err = loadViewFromFile(ctx, scope.Tx.Flags, fp, fileInfo, options, fileIdentifier)
   959  		if err != nil {
   960  			if _, ok := err.(Error); !ok {
   961  				err = NewDataParsingError(fileIdentifier, fileInfo.Path, err.Error())
   962  			}
   963  			if forUpdate {
   964  				err = appendCompositeError(err, scope.Tx.FileContainer.Close(fileInfo.Handler))
   965  			}
   966  			return
   967  		}
   968  		view.FileInfo.ForUpdate = forUpdate
   969  		scope.Tx.CachedViews.Set(view)
   970  	}
   971  
   972  	if !scope.FilePathExists(fileIdentifier.Literal) {
   973  		scope.StoreFilePath(fileIdentifier.Literal, filePath)
   974  	}
   975  
   976  	return
   977  }
   978  
   979  func loadViewFromFile(ctx context.Context, flags *option.Flags, fp io.Reader, fileInfo *FileInfo, options option.ImportOptions, expr parser.QueryExpression) (*View, error) {
   980  	fileReader, err := file.NewReader(fp, 2048)
   981  	if err != nil {
   982  		return nil, NewIOError(expr, err.Error())
   983  	}
   984  
   985  	switch fileInfo.Format {
   986  	case option.FIXED:
   987  		return loadViewFromFixedLengthTextFile(ctx, fileReader, fileInfo, options.WithoutNull, expr)
   988  	case option.LTSV:
   989  		return loadViewFromLTSVFile(ctx, flags, fileReader, fileInfo, options.WithoutNull, expr)
   990  	case option.JSON:
   991  		return loadViewFromJsonFile(fileReader, fileInfo, expr)
   992  	case option.JSONL:
   993  		return loadViewFromJsonLinesFile(ctx, flags, fileReader, fileInfo, expr)
   994  	}
   995  	return loadViewFromCSVFile(ctx, fileReader, fileInfo, options.AllowUnevenFields, options.WithoutNull, expr)
   996  }
   997  
   998  func loadViewFromFixedLengthTextFile(ctx context.Context, fp *file.Reader, fileInfo *FileInfo, withoutNull bool, expr parser.QueryExpression) (*View, error) {
   999  	fileHead, err := fp.HeadBytes()
  1000  	if err != nil {
  1001  		return nil, NewIOError(expr, err.Error())
  1002  	}
  1003  
  1004  	enc, err := text.DetectInSpecifiedEncoding(fileHead, fileInfo.Encoding)
  1005  	if err != nil {
  1006  		return nil, NewCannotDetectFileEncodingError(expr)
  1007  	}
  1008  	fileInfo.Encoding = enc
  1009  
  1010  	var r io.Reader
  1011  
  1012  	if fileInfo.DelimiterPositions == nil {
  1013  		data, err := io.ReadAll(fp)
  1014  		if err != nil {
  1015  			return nil, NewIOError(expr, err.Error())
  1016  		}
  1017  		br := bytes.NewReader(data)
  1018  
  1019  		d, err := fixedlen.NewDelimiter(br, fileInfo.Encoding)
  1020  		if err != nil {
  1021  			return nil, err
  1022  		}
  1023  		d.NoHeader = fileInfo.NoHeader
  1024  		d.Encoding = fileInfo.Encoding
  1025  		fileInfo.DelimiterPositions, err = d.Delimit()
  1026  		if err != nil {
  1027  			return nil, err
  1028  		}
  1029  
  1030  		if _, err = br.Seek(0, io.SeekStart); err != nil {
  1031  			return nil, NewIOError(expr, err.Error())
  1032  		}
  1033  		r = br
  1034  	} else {
  1035  		r = fp
  1036  	}
  1037  
  1038  	reader, err := fixedlen.NewReader(r, fileInfo.DelimiterPositions, fileInfo.Encoding)
  1039  	if err != nil {
  1040  		return nil, err
  1041  	}
  1042  	reader.WithoutNull = withoutNull
  1043  	reader.Encoding = fileInfo.Encoding
  1044  	reader.SingleLine = fileInfo.SingleLine
  1045  
  1046  	var header []string
  1047  	if !fileInfo.NoHeader && !fileInfo.SingleLine {
  1048  		header, err = reader.ReadHeader()
  1049  		if err != nil && err != io.EOF {
  1050  			return nil, err
  1051  		}
  1052  	}
  1053  
  1054  	records, err := readRecordSet(ctx, reader, fp.Size())
  1055  	if err != nil {
  1056  		return nil, err
  1057  	}
  1058  
  1059  	if header == nil {
  1060  		header = make([]string, len(fileInfo.DelimiterPositions))
  1061  		for i := 0; i < len(fileInfo.DelimiterPositions); i++ {
  1062  			header[i] = "c" + strconv.Itoa(i+1)
  1063  		}
  1064  	}
  1065  
  1066  	if reader.DetectedLineBreak != "" {
  1067  		fileInfo.LineBreak = reader.DetectedLineBreak
  1068  	}
  1069  
  1070  	view := NewView()
  1071  	view.Header = NewHeaderWithAutofill(FormatTableName(fileInfo.Path), header)
  1072  	view.RecordSet = records
  1073  	view.FileInfo = fileInfo
  1074  	return view, nil
  1075  }
  1076  
  1077  func loadViewFromCSVFile(ctx context.Context, fp *file.Reader, fileInfo *FileInfo, allowUnevenFields bool, withoutNull bool, expr parser.QueryExpression) (*View, error) {
  1078  	if fileInfo.Format == option.TSV {
  1079  		fileInfo.Delimiter = '\t'
  1080  	}
  1081  
  1082  	fileHead, err := fp.HeadBytes()
  1083  	if err != nil {
  1084  		return nil, NewIOError(expr, err.Error())
  1085  	}
  1086  
  1087  	enc, err := text.DetectInSpecifiedEncoding(fileHead, fileInfo.Encoding)
  1088  	if err != nil {
  1089  		return nil, NewCannotDetectFileEncodingError(expr)
  1090  	}
  1091  	fileInfo.Encoding = enc
  1092  
  1093  	reader, err := csv.NewReader(fp, fileInfo.Encoding)
  1094  	if err != nil {
  1095  		return nil, err
  1096  	}
  1097  	reader.Delimiter = fileInfo.Delimiter
  1098  	reader.WithoutNull = withoutNull
  1099  	reader.AllowUnevenFields = allowUnevenFields
  1100  
  1101  	var header []string
  1102  	if !fileInfo.NoHeader {
  1103  		header, err = reader.ReadHeader()
  1104  		if err != nil && err != io.EOF {
  1105  			return nil, err
  1106  		}
  1107  	}
  1108  
  1109  	records, err := readRecordSet(ctx, reader, fp.Size())
  1110  	if err != nil {
  1111  		return nil, err
  1112  	}
  1113  
  1114  	if header == nil {
  1115  		header = make([]string, reader.FieldsPerRecord)
  1116  		for i := 0; i < reader.FieldsPerRecord; i++ {
  1117  			header[i] = "c" + strconv.Itoa(i+1)
  1118  		}
  1119  	}
  1120  
  1121  	if reader.DetectedLineBreak != "" {
  1122  		fileInfo.LineBreak = reader.DetectedLineBreak
  1123  	}
  1124  	fileInfo.EncloseAll = reader.EnclosedAll
  1125  
  1126  	view := NewView()
  1127  
  1128  	if allowUnevenFields {
  1129  		if len(header) < reader.FieldsPerRecord {
  1130  			header = append(header, make([]string, reader.FieldsPerRecord-len(header))...)
  1131  		}
  1132  		view.Header = NewHeaderWithAutofill(FormatTableName(fileInfo.Path), header)
  1133  
  1134  		for i := range records {
  1135  			if reader.FieldsPerRecord <= len(records[i]) {
  1136  				continue
  1137  			}
  1138  
  1139  			filling := make([]Cell, reader.FieldsPerRecord-len(records[i]))
  1140  			for j := range filling {
  1141  				if withoutNull {
  1142  					filling[j] = NewCell(value.NewString(""))
  1143  				} else {
  1144  					filling[j] = NewCell(value.NewNull())
  1145  				}
  1146  			}
  1147  
  1148  			records[i] = append(records[i], filling...)
  1149  		}
  1150  	} else {
  1151  		view.Header = NewHeader(FormatTableName(fileInfo.Path), header)
  1152  	}
  1153  
  1154  	view.RecordSet = records
  1155  	view.FileInfo = fileInfo
  1156  	return view, nil
  1157  }
  1158  
  1159  func loadViewFromLTSVFile(ctx context.Context, flags *option.Flags, fp *file.Reader, fileInfo *FileInfo, withoutNull bool, expr parser.QueryExpression) (*View, error) {
  1160  	fileHead, err := fp.HeadBytes()
  1161  	if err != nil {
  1162  		return nil, NewIOError(expr, err.Error())
  1163  	}
  1164  
  1165  	enc, err := text.DetectInSpecifiedEncoding(fileHead, fileInfo.Encoding)
  1166  	if err != nil {
  1167  		return nil, NewCannotDetectFileEncodingError(expr)
  1168  	}
  1169  	fileInfo.Encoding = enc
  1170  
  1171  	reader, err := ltsv.NewReader(fp, fileInfo.Encoding)
  1172  	if err != nil {
  1173  		return nil, NewIOError(expr, err.Error())
  1174  	}
  1175  	reader.WithoutNull = withoutNull
  1176  
  1177  	records, err := readRecordSet(ctx, reader, fp.Size())
  1178  	if err != nil {
  1179  		return nil, err
  1180  	}
  1181  
  1182  	header := reader.Header.Fields()
  1183  	if err = NewGoroutineTaskManager(len(records), -1, flags.CPU).Run(ctx, func(index int) error {
  1184  		for j := len(records[index]); j < len(header); j++ {
  1185  			if withoutNull {
  1186  				records[index] = append(records[index], NewCell(value.NewString("")))
  1187  			} else {
  1188  				records[index] = append(records[index], NewCell(value.NewNull()))
  1189  			}
  1190  		}
  1191  		return nil
  1192  	}); err != nil {
  1193  		return nil, err
  1194  	}
  1195  
  1196  	if reader.DetectedLineBreak != "" {
  1197  		fileInfo.LineBreak = reader.DetectedLineBreak
  1198  	}
  1199  
  1200  	view := NewView()
  1201  	view.Header = NewHeader(FormatTableName(fileInfo.Path), header)
  1202  	view.RecordSet = records
  1203  	view.FileInfo = fileInfo
  1204  	return view, nil
  1205  }
  1206  
  1207  func readRecordSet(ctx context.Context, reader RecordReader, fileSize int64) (RecordSet, error) {
  1208  	var err error
  1209  	recordSet := make(RecordSet, 0, fileLoadingPreparedRecordSetCap)
  1210  	rowch := make(chan []text.RawText, fileLoadingBuffer)
  1211  	panicCh := make(chan bool, 1)
  1212  	pos := 0
  1213  
  1214  	wg := sync.WaitGroup{}
  1215  
  1216  	wg.Add(1)
  1217  	go func() {
  1218  		defer func() {
  1219  			if err == nil {
  1220  				if panicReport := recover(); panicReport != nil {
  1221  					err = NewFatalError(panicReport)
  1222  				}
  1223  			}
  1224  			panicCh <- true
  1225  			wg.Done()
  1226  		}()
  1227  
  1228  		for {
  1229  			row, ok := <-rowch
  1230  			if !ok {
  1231  				break
  1232  			}
  1233  
  1234  			record := make(Record, len(row))
  1235  			for i, v := range row {
  1236  				if v == nil {
  1237  					record[i] = NewCell(value.NewNull())
  1238  				} else {
  1239  					record[i] = NewCell(value.NewString(string(v)))
  1240  				}
  1241  			}
  1242  
  1243  			if 0 < fileSize && 0 < pos && len(recordSet) == fileLoadingPreparedRecordSetCap && int64(pos) < fileSize {
  1244  				l := int((float64(fileSize) / float64(pos)) * fileLoadingPreparedRecordSetCap * 1.2)
  1245  				newSet := make(RecordSet, fileLoadingPreparedRecordSetCap, l)
  1246  				copy(newSet, recordSet)
  1247  				recordSet = newSet
  1248  			}
  1249  
  1250  			recordSet = append(recordSet, record)
  1251  		}
  1252  	}()
  1253  
  1254  	wg.Add(1)
  1255  	go func() {
  1256  		panicOccurred := false
  1257  
  1258  		defer func() {
  1259  			if err == nil && !panicOccurred {
  1260  				if panicReport := recover(); panicReport != nil {
  1261  					err = NewFatalError(panicReport)
  1262  				}
  1263  			}
  1264  			close(rowch)
  1265  			wg.Done()
  1266  		}()
  1267  
  1268  		i := 0
  1269  
  1270  		for {
  1271  			if i&15 == 0 && ctx.Err() != nil {
  1272  				err = ConvertContextError(ctx.Err())
  1273  				break
  1274  			}
  1275  
  1276  			row, e := reader.Read()
  1277  			if e == io.EOF {
  1278  				break
  1279  			}
  1280  			if e != nil {
  1281  				err = e
  1282  				break
  1283  			}
  1284  
  1285  			if 0 < fileSize && i < fileLoadingPreparedRecordSetCap {
  1286  				for j := range row {
  1287  					pos += len(row[j])
  1288  				}
  1289  			}
  1290  
  1291  			select {
  1292  			case _ = <-panicCh:
  1293  				panicOccurred = true
  1294  			case rowch <- row:
  1295  				// Row data sent.
  1296  			}
  1297  
  1298  			if panicOccurred {
  1299  				break
  1300  			}
  1301  			i++
  1302  		}
  1303  	}()
  1304  
  1305  	wg.Wait()
  1306  	close(panicCh)
  1307  
  1308  	return recordSet, err
  1309  }
  1310  
  1311  func loadViewFromJsonFile(fp *file.Reader, fileInfo *FileInfo, expr parser.QueryExpression) (*View, error) {
  1312  	jsonText, err := io.ReadAll(fp)
  1313  	if err != nil {
  1314  		return nil, NewIOError(expr, err.Error())
  1315  	}
  1316  
  1317  	headerLabels, rows, escapeType, err := json.LoadTable(fileInfo.JsonQuery, string(jsonText))
  1318  	if err != nil {
  1319  		return nil, NewLoadJsonError(expr, err.Error())
  1320  	}
  1321  
  1322  	records := make(RecordSet, len(rows))
  1323  	for i := range rows {
  1324  		records[i] = NewRecord(rows[i])
  1325  	}
  1326  
  1327  	fileInfo.Encoding = text.UTF8
  1328  	fileInfo.JsonEscape = escapeType
  1329  
  1330  	view := NewView()
  1331  	view.Header = NewHeader(FormatTableName(fileInfo.Path), headerLabels)
  1332  	view.RecordSet = records
  1333  	view.FileInfo = fileInfo
  1334  	return view, nil
  1335  }
  1336  
  1337  func loadViewFromJsonLinesFile(ctx context.Context, flags *option.Flags, fp *file.Reader, fileInfo *FileInfo, expr parser.QueryExpression) (*View, error) {
  1338  	var err error
  1339  	headerList := make([]string, 0, 32)
  1340  	headerMap := make(map[string]bool, 32)
  1341  	objectList := make([]txjson.Object, 0, fileLoadingPreparedRecordSetCap)
  1342  
  1343  	escapeType := txjson.Backslash
  1344  	fileSize := fp.Size()
  1345  	jsonQuery, err := json.Query.Parse(fileInfo.JsonQuery)
  1346  	if err != nil {
  1347  		return nil, NewLoadJsonError(expr, err.Error())
  1348  	}
  1349  
  1350  	rowch := make(chan txjson.Object, fileLoadingBuffer)
  1351  	panicCh := make(chan bool, 1)
  1352  	pos := 0
  1353  
  1354  	reader := jsonl.NewReader(fp)
  1355  	reader.SetUseInteger(false)
  1356  
  1357  	wg := sync.WaitGroup{}
  1358  
  1359  	wg.Add(1)
  1360  	go func() {
  1361  		defer func() {
  1362  			if err == nil {
  1363  				if panicReport := recover(); panicReport != nil {
  1364  					err = NewFatalError(panicReport)
  1365  				}
  1366  			}
  1367  			panicCh <- true
  1368  			wg.Done()
  1369  		}()
  1370  
  1371  		for {
  1372  			row, ok := <-rowch
  1373  			if !ok {
  1374  				break
  1375  			}
  1376  
  1377  			for _, v := range row.Keys() {
  1378  				if _, ok := headerMap[v]; !ok {
  1379  					headerMap[v] = true
  1380  					headerList = append(headerList, v)
  1381  				}
  1382  			}
  1383  
  1384  			if 0 < fileSize && 0 < pos && len(objectList) == fileLoadingPreparedRecordSetCap && int64(pos) < fileSize {
  1385  				l := int((float64(fileSize) / float64(pos)) * fileLoadingPreparedRecordSetCap * 1.2)
  1386  				newSet := make([]txjson.Object, fileLoadingPreparedRecordSetCap, l)
  1387  				copy(newSet, objectList)
  1388  				objectList = newSet
  1389  			}
  1390  
  1391  			objectList = append(objectList, row)
  1392  		}
  1393  	}()
  1394  
  1395  	wg.Add(1)
  1396  	go func() {
  1397  		panicOccurred := false
  1398  
  1399  		defer func() {
  1400  			if err == nil && !panicOccurred {
  1401  				if panicReport := recover(); panicReport != nil {
  1402  					err = NewFatalError(panicReport)
  1403  				}
  1404  			}
  1405  			close(rowch)
  1406  			wg.Done()
  1407  		}()
  1408  
  1409  		i := 0
  1410  		for {
  1411  			if i&15 == 0 && ctx.Err() != nil {
  1412  				err = ConvertContextError(ctx.Err())
  1413  				break
  1414  			}
  1415  
  1416  			row, et, e := reader.Read()
  1417  			if e == io.EOF {
  1418  				break
  1419  			}
  1420  			if e != nil {
  1421  				err = e
  1422  				break
  1423  			}
  1424  
  1425  			rowObj, ok := row.(txjson.Object)
  1426  			if !ok {
  1427  				err = NewJsonLinesStructureError(expr)
  1428  				break
  1429  			}
  1430  
  1431  			if jsonQuery != nil {
  1432  				jstruct, e := json.Extract(jsonQuery, rowObj)
  1433  				if e != nil {
  1434  					err = e
  1435  					break
  1436  				}
  1437  				jarray, ok := jstruct.(txjson.Array)
  1438  				if !ok || len(jarray) < 1 {
  1439  					err = NewJsonLinesStructureError(expr)
  1440  					break
  1441  				}
  1442  				rowObj, ok = jarray[0].(txjson.Object)
  1443  				if !ok {
  1444  					err = NewJsonLinesStructureError(expr)
  1445  					break
  1446  				}
  1447  			}
  1448  
  1449  			if escapeType < et {
  1450  				escapeType = et
  1451  			}
  1452  
  1453  			if 0 < fileSize && i < fileLoadingPreparedRecordSetCap {
  1454  				pos = reader.Pos()
  1455  			}
  1456  
  1457  			select {
  1458  			case _ = <-panicCh:
  1459  				panicOccurred = true
  1460  			case rowch <- rowObj:
  1461  				// Row data sent.
  1462  			}
  1463  
  1464  			if panicOccurred {
  1465  				break
  1466  			}
  1467  			i++
  1468  		}
  1469  	}()
  1470  
  1471  	wg.Wait()
  1472  	close(panicCh)
  1473  
  1474  	if err != nil {
  1475  		return nil, err
  1476  	}
  1477  
  1478  	recordSet := make(RecordSet, len(objectList))
  1479  
  1480  	if err = NewGoroutineTaskManager(len(objectList), -1, flags.CPU).Run(ctx, func(index int) error {
  1481  		values := make([]value.Primary, len(headerList))
  1482  
  1483  		for i, v := range headerList {
  1484  			if objectList[index].Exists(v) {
  1485  				values[i] = json.ConvertToValue(objectList[index].Value(v))
  1486  			} else {
  1487  				values[i] = value.NewNull()
  1488  			}
  1489  		}
  1490  
  1491  		recordSet[index] = NewRecord(values)
  1492  		return nil
  1493  	}); err != nil {
  1494  		return nil, err
  1495  	}
  1496  
  1497  	fileInfo.Encoding = text.UTF8
  1498  	fileInfo.JsonEscape = escapeType
  1499  
  1500  	view := NewView()
  1501  	view.Header = NewHeader(FormatTableName(fileInfo.Path), headerList)
  1502  	view.RecordSet = recordSet
  1503  	view.FileInfo = fileInfo
  1504  	return view, nil
  1505  }