github.com/mithrandie/csvq@v1.18.1/lib/terminal/completer_readline.go (about)

     1  //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
     2  
     3  package terminal
     4  
     5  import (
     6  	"os"
     7  	"path/filepath"
     8  	"sort"
     9  	"strings"
    10  	"unicode"
    11  
    12  	"github.com/mithrandie/csvq/lib/constant"
    13  	"github.com/mithrandie/csvq/lib/option"
    14  	"github.com/mithrandie/csvq/lib/parser"
    15  	"github.com/mithrandie/csvq/lib/query"
    16  
    17  	"github.com/mithrandie/go-text"
    18  	"github.com/mithrandie/readline-csvq"
    19  	"github.com/mithrandie/ternary"
    20  )
    21  
    22  const (
    23  	dummySubquery    = "____subquery____"
    24  	dummyTableObject = "____table_object____"
    25  	dummyTable       = "____table____"
    26  )
    27  
    28  var statementPrefix = []string{
    29  	"WITH",
    30  	"SELECT",
    31  	"INSERT",
    32  	"UPDATE",
    33  	"REPLACE",
    34  	"DELETE",
    35  	"CREATE",
    36  	"ALTER",
    37  	"DECLARE",
    38  	"PREPARE",
    39  	"VAR",
    40  	"SET",
    41  	"UNSET",
    42  	"ADD",
    43  	"REMOVE",
    44  	"ECHO",
    45  	"PRINT",
    46  	"PRINTF",
    47  	"CHDIR",
    48  	"EXECUTE",
    49  	"SHOW",
    50  	"SOURCE",
    51  	"SYNTAX",
    52  	"RELOAD",
    53  }
    54  
    55  var singleCommandStatement = []string{
    56  	"COMMIT",
    57  	"ROLLBACK",
    58  	"EXIT",
    59  	"PWD",
    60  }
    61  
    62  var delimiterCandidates = []string{
    63  	"','",
    64  	"'\\t'",
    65  }
    66  
    67  var delimiterPositionsCandidates = []string{
    68  	"'SPACES'",
    69  	"'S[]'",
    70  	"'[]'",
    71  }
    72  
    73  var joinCandidates = []string{
    74  	"JOIN",
    75  	"CROSS",
    76  	"INNER",
    77  	"FULL",
    78  	"LEFT",
    79  	"RIGHT",
    80  	"NATURAL",
    81  }
    82  
    83  var tableObjectCandidates = []string{
    84  	"CSV()",
    85  	"FIXED()",
    86  	"JSON()",
    87  	"JSONL()",
    88  	"LTSV()",
    89  }
    90  
    91  var exportEncodingsCandidates = []string{
    92  	"SJIS",
    93  	"UTF16",
    94  	"UTF16BE",
    95  	"UTF16BEM",
    96  	"UTF16LE",
    97  	"UTF16LEM",
    98  	"UTF8",
    99  	"UTF8M",
   100  }
   101  
   102  type ReadlineListener struct {
   103  	scanner parser.Scanner
   104  }
   105  
   106  func skipInputtingEnclosure(line []rune, pos int) []rune {
   107  	tail := line[pos:]
   108  	line = append(line[:pos-1], tail...)
   109  	return line
   110  }
   111  
   112  func completeEnclosure(line []rune, pos int, rightEnclosure rune) []rune {
   113  	tail := append([]rune{rightEnclosure}, line[pos:]...)
   114  	line = append(line[:pos], tail...)
   115  	return line
   116  }
   117  
   118  func (l ReadlineListener) OnChange(line []rune, pos int, key rune) ([]rune, int, bool) {
   119  	switch {
   120  	case readline.IsQuotationMark(key):
   121  		if !readline.LiteralIsEnclosed(key, line) {
   122  			if pos < len(line) && key == line[pos] {
   123  				return skipInputtingEnclosure(line, pos), pos, true
   124  			} else {
   125  				return completeEnclosure(line, pos, key), pos, true
   126  			}
   127  		}
   128  	case readline.IsBracket(key):
   129  		if !readline.BracketIsEnclosed(key, line) {
   130  			return completeEnclosure(line, pos, readline.RightBracket[key]), pos, true
   131  		}
   132  	case readline.IsRightBracket(key):
   133  		if pos < len(line) && readline.IsRightBracket(line[pos]) && readline.BracketIsEnclosedByRightBracket(key, line) {
   134  			return skipInputtingEnclosure(line, pos), pos, true
   135  		}
   136  	}
   137  
   138  	return line, pos, false
   139  }
   140  
   141  type Completer struct {
   142  	completer *readline.PrefixCompleter
   143  	scope     *query.ReferenceScope
   144  
   145  	flagList      []string
   146  	runinfoList   []string
   147  	funcs         []string
   148  	aggFuncs      []string
   149  	analyticFuncs []string
   150  
   151  	constants []string
   152  
   153  	statementList    []string
   154  	userFuncs        []string
   155  	userAggFuncs     []string
   156  	userFuncList     []string
   157  	viewList         []string
   158  	cursorList       []string
   159  	funcList         []string
   160  	aggFuncList      []string
   161  	analyticFuncList []string
   162  	varList          []string
   163  	envList          []string
   164  	enclosedEnvList  []string
   165  	allColumns       []string
   166  	tableColumns     map[string][]string
   167  
   168  	tokens            []parser.Token
   169  	lastIdx           int
   170  	selectIntoEnabled bool
   171  
   172  	isInAndAfterSelect bool
   173  }
   174  
   175  func NewCompleter(scope *query.ReferenceScope) *Completer {
   176  	completer := &Completer{
   177  		completer:    readline.NewPrefixCompleter(),
   178  		scope:        scope,
   179  		tableColumns: make(map[string][]string),
   180  	}
   181  
   182  	completer.flagList = make([]string, 0, len(option.FlagList))
   183  	for _, v := range option.FlagList {
   184  		completer.flagList = append(completer.flagList, option.FlagSymbol(v))
   185  	}
   186  	completer.runinfoList = make([]string, 0, len(query.RuntimeInformatinList))
   187  	for _, v := range query.RuntimeInformatinList {
   188  		completer.runinfoList = append(completer.runinfoList, option.RuntimeInformationSymbol(v))
   189  	}
   190  
   191  	sort.Strings(completer.flagList)
   192  	sort.Strings(completer.runinfoList)
   193  
   194  	completer.funcs = make([]string, 0, len(query.Functions)+3)
   195  	for k := range query.Functions {
   196  		completer.funcs = append(completer.funcs, k)
   197  	}
   198  	completer.funcs = append(completer.funcs, "CALL")
   199  	completer.funcs = append(completer.funcs, "NOW")
   200  	completer.funcs = append(completer.funcs, "JSON_OBJECT")
   201  
   202  	completer.aggFuncs = make([]string, 0, len(query.AggregateFunctions)+2)
   203  	completer.analyticFuncs = make([]string, 0, len(query.AnalyticFunctions)+len(query.AggregateFunctions))
   204  	for k := range query.AggregateFunctions {
   205  		completer.aggFuncs = append(completer.aggFuncs, k)
   206  		completer.analyticFuncs = append(completer.analyticFuncs, k)
   207  	}
   208  	completer.aggFuncs = append(completer.aggFuncs, "LISTAGG")
   209  	completer.aggFuncs = append(completer.aggFuncs, "JSON_AGG")
   210  	for k := range query.AnalyticFunctions {
   211  		completer.analyticFuncs = append(completer.analyticFuncs, k)
   212  	}
   213  
   214  	completer.constants = make([]string, 0, constant.Count())
   215  	for category, valueMap := range constant.Definition {
   216  		for name := range valueMap {
   217  			completer.constants = append(completer.constants, category+parser.ConstantDelimiter+name)
   218  		}
   219  	}
   220  	sort.Strings(completer.constants)
   221  
   222  	completer.tokens = make([]parser.Token, 0, 20)
   223  
   224  	return completer
   225  }
   226  
   227  func (c *Completer) Do(line []rune, pos int, index int) (readline.CandidateList, int) {
   228  	return c.completer.Do(line, pos, index)
   229  }
   230  
   231  func (c *Completer) Update() {
   232  	c.updateStatements()
   233  	c.updateViews()
   234  	c.updateCursors()
   235  	c.updateFunctions()
   236  	c.updateVariables()
   237  	c.updateEnvironmentVariables()
   238  	c.updateAllColumns()
   239  
   240  	completer := readline.NewPrefixCompleter()
   241  	statements := readline.PcItemDynamic(c.Statements)
   242  	statements.AppendOnly = true
   243  	completer.SetChildren([]readline.PrefixCompleterInterface{statements})
   244  	c.completer = completer
   245  }
   246  
   247  func (c *Completer) updateStatements() {
   248  	c.statementList = make([]string, 0, 10)
   249  	c.scope.Tx.PreparedStatements.Range(func(key, value interface{}) bool {
   250  		c.statementList = append(c.statementList, value.(*query.PreparedStatement).Name)
   251  		return true
   252  	})
   253  	sort.Strings(c.statementList)
   254  }
   255  
   256  func (c *Completer) updateViews() {
   257  	views := c.scope.AllTemporaryTables()
   258  	viewKeys := views.SortedKeys()
   259  	c.viewList = make([]string, 0, len(viewKeys))
   260  	for _, key := range viewKeys {
   261  		if view, ok := views.Load(key); ok {
   262  			c.viewList = append(c.viewList, view.FileInfo.Path)
   263  		}
   264  	}
   265  }
   266  
   267  func (c *Completer) updateCursors() {
   268  	cursors := c.scope.AllCursors()
   269  	cursorKeys := cursors.SortedKeys()
   270  	c.cursorList = make([]string, 0, len(cursorKeys))
   271  	for _, key := range cursorKeys {
   272  		if cur, ok := cursors.Load(key); ok {
   273  			c.cursorList = append(c.cursorList, cur.Name)
   274  		}
   275  	}
   276  }
   277  
   278  func (c *Completer) updateFunctions() {
   279  	userfuncs, userAggFuncs := c.scope.AllFunctions()
   280  	c.userFuncs = make([]string, 0, userfuncs.Len())
   281  	c.userAggFuncs = make([]string, 0, userAggFuncs.Len())
   282  
   283  	funcKeys := make([]string, 0, len(c.funcs)+userfuncs.Len())
   284  	for _, v := range c.funcs {
   285  		funcKeys = append(funcKeys, v+"()")
   286  	}
   287  	userfuncs.Range(func(key, value interface{}) bool {
   288  		f := value.(*query.UserDefinedFunction)
   289  		funcKeys = append(funcKeys, f.Name.String()+"()")
   290  		c.userFuncs = append(c.userFuncs, f.Name.String())
   291  		return true
   292  	})
   293  	sort.Strings(funcKeys)
   294  	c.funcList = funcKeys
   295  
   296  	aggFuncKeys := make([]string, 0, len(c.aggFuncs)+userAggFuncs.Len())
   297  	for _, v := range c.aggFuncs {
   298  		aggFuncKeys = append(aggFuncKeys, v+"()")
   299  	}
   300  	userAggFuncs.Range(func(key, value interface{}) bool {
   301  		f := value.(*query.UserDefinedFunction)
   302  		aggFuncKeys = append(aggFuncKeys, f.Name.String()+"()")
   303  		c.userAggFuncs = append(c.userAggFuncs, f.Name.String())
   304  		return true
   305  	})
   306  	sort.Strings(aggFuncKeys)
   307  	c.aggFuncList = aggFuncKeys
   308  
   309  	c.userFuncList = append(c.userFuncs, c.userAggFuncs...)
   310  	sort.Strings(c.userFuncList)
   311  
   312  	analyticFuncKeys := make([]string, 0, len(c.analyticFuncs)+userAggFuncs.Len())
   313  	for _, v := range c.analyticFuncs {
   314  		analyticFuncKeys = append(analyticFuncKeys, v+"() OVER ()")
   315  	}
   316  	userAggFuncs.Range(func(key, value interface{}) bool {
   317  		f := value.(*query.UserDefinedFunction)
   318  		analyticFuncKeys = append(analyticFuncKeys, f.Name.String()+"() OVER ()")
   319  		return true
   320  	})
   321  	sort.Strings(analyticFuncKeys)
   322  	c.analyticFuncList = analyticFuncKeys
   323  }
   324  
   325  func (c *Completer) updateVariables() {
   326  	vars := c.scope.AllVariables()
   327  	varKeys := vars.SortedKeys()
   328  
   329  	c.varList = make([]string, 0, len(varKeys))
   330  	for _, k := range varKeys {
   331  		c.varList = append(c.varList, option.VariableSymbol(k))
   332  	}
   333  }
   334  
   335  func (c *Completer) updateEnvironmentVariables() {
   336  	env := os.Environ()
   337  	c.envList = make([]string, 0, len(env))
   338  	c.enclosedEnvList = make([]string, 0, len(env))
   339  	for _, e := range env {
   340  		words := strings.Split(e, "=")
   341  		c.envList = append(c.envList, option.EnvironmentVariableSymbol(words[0]))
   342  		c.enclosedEnvList = append(c.enclosedEnvList, option.EnclosedEnvironmentVariableSymbol(words[0]))
   343  	}
   344  	sort.Strings(c.envList)
   345  	sort.Strings(c.enclosedEnvList)
   346  }
   347  
   348  func (c *Completer) updateAllColumns() {
   349  	c.allColumns = c.AllColumnList()
   350  }
   351  
   352  func (c *Completer) GetStatementPrefix(line string, origLine string, index int) readline.CandidateList {
   353  	prefix := statementPrefix
   354  	if 0 < len(c.cursorList) || 0 < len(c.userFuncList) || 0 < len(c.viewList) || 0 < len(c.varList) || 0 < len(c.statementList) {
   355  		prefix = append(prefix, "DISPOSE")
   356  	}
   357  	if 0 < len(c.cursorList) {
   358  		prefix = append(prefix,
   359  			"OPEN",
   360  			"CLOSE",
   361  			"FETCH",
   362  		)
   363  	}
   364  
   365  	var cands readline.CandidateList
   366  	for _, p := range prefix {
   367  		cands = append(cands, c.candidate(p, true))
   368  	}
   369  	for _, p := range singleCommandStatement {
   370  		cands = append(cands, c.candidate(p, false))
   371  	}
   372  	cands = append(cands, c.SearchValues(line, origLine, index)...)
   373  
   374  	cands.Sort()
   375  	return cands
   376  }
   377  
   378  func (c *Completer) Statements(line string, origLine string, index int) readline.CandidateList {
   379  	origRunes := []rune(origLine)
   380  	c.UpdateTokens(line, string(origRunes[:index]))
   381  
   382  	token := parser.EOF
   383  	if (1 == len(c.tokens) && unicode.IsSpace(origRunes[index-1])) || 1 < len(c.tokens) {
   384  		token = c.tokens[0].Token
   385  	}
   386  
   387  	switch token {
   388  	case parser.WITH:
   389  		return c.WithArgs(line, origLine, index)
   390  	case parser.SELECT:
   391  		return c.SelectArgs(line, origLine, index)
   392  	case parser.INSERT:
   393  		return c.InsertArgs(line, origLine, index)
   394  	case parser.UPDATE:
   395  		return c.UpdateArgs(line, origLine, index)
   396  	case parser.REPLACE:
   397  		return c.ReplaceArgs(line, origLine, index)
   398  	case parser.DELETE:
   399  		return c.DeleteArgs(line, origLine, index)
   400  	case parser.CREATE:
   401  		return c.CreateArgs(line, origLine, index)
   402  	case parser.ALTER:
   403  		return c.AlterArgs(line, origLine, index)
   404  	case parser.DECLARE, parser.VAR:
   405  		return c.DeclareArgs(line, origLine, index)
   406  	case parser.PREPARE:
   407  		return c.PrepareArgs(line, origLine, index)
   408  	case parser.SET:
   409  		return c.SetArgs(line, origLine, index)
   410  	case parser.UNSET:
   411  		return c.candidateList(c.environmentVariableList(line), false)
   412  	case parser.ADD:
   413  		return c.AddFlagArgs(line, origLine, index)
   414  	case parser.REMOVE:
   415  		return c.RemoveFlagArgs(line, origLine, index)
   416  	case parser.ECHO:
   417  		return c.SearchValues(line, origLine, index)
   418  	case parser.PRINT:
   419  		return c.SearchValues(line, origLine, index)
   420  	case parser.PRINTF:
   421  		return c.UsingArgs(line, origLine, index)
   422  	case parser.CHDIR:
   423  		return c.SearchDirs(line, origLine, index)
   424  	case parser.EXECUTE:
   425  		return c.UsingArgs(line, origLine, index)
   426  	case parser.SHOW:
   427  		return c.ShowArgs(line, origLine, index)
   428  	case parser.SOURCE:
   429  		return c.SearchExecutableFiles(line, origLine, index)
   430  	case parser.RELOAD:
   431  		if 0 < len(line) && len(c.tokens) == 2 || len(line) < 1 && len(c.tokens) == 1 {
   432  			return readline.CandidateList{c.candidate("CONFIG", false)}
   433  		} else {
   434  			return nil
   435  		}
   436  	case parser.DISPOSE:
   437  		return c.DisposeArgs(line, origLine, index)
   438  	case parser.OPEN:
   439  		return c.UsingArgs(line, origLine, index)
   440  	case parser.CLOSE:
   441  		return c.candidateList(c.cursorList, false)
   442  	case parser.FETCH:
   443  		return c.FetchArgs(line, origLine, index)
   444  	case parser.COMMIT:
   445  		return nil
   446  	case parser.ROLLBACK:
   447  		return nil
   448  	case parser.EXIT:
   449  		return nil
   450  	case parser.PWD:
   451  		return nil
   452  	case parser.SYNTAX:
   453  		return nil
   454  	case parser.EOF:
   455  		return c.GetStatementPrefix(line, origLine, index)
   456  	default:
   457  		if 0 < len(c.tokens) {
   458  			switch {
   459  			case c.isTableObject(c.tokens[0]):
   460  				return c.TableObjectArgs(line, origLine, index)
   461  			case c.isFunction(c.tokens[0]):
   462  				return c.FunctionArgs(line, origLine, index)
   463  			}
   464  		}
   465  	}
   466  
   467  	cands := c.SearchValues(line, origLine, index)
   468  	cands.Sort()
   469  	return cands
   470  }
   471  
   472  func (c *Completer) TableObjectArgs(line string, origLine string, index int) readline.CandidateList {
   473  	commaCnt := 0
   474  	for _, t := range c.tokens {
   475  		if t.Token == ',' {
   476  			commaCnt++
   477  		}
   478  	}
   479  
   480  	var cands readline.CandidateList
   481  
   482  	switch strings.ToUpper(c.tokens[0].Literal) {
   483  	case "LTSV":
   484  		switch commaCnt {
   485  		case 0:
   486  			if c.tokens[c.lastIdx].Token == '(' {
   487  				cands = c.SearchAllTables(line, origLine, index)
   488  			}
   489  		case 1:
   490  			if c.tokens[c.lastIdx].Token == ',' {
   491  				cands = c.candidateList(c.encodingList(), false)
   492  			}
   493  		case 2:
   494  			if c.tokens[c.lastIdx].Token == ',' {
   495  				cands = c.candidateList([]string{ternary.TRUE.String(), ternary.FALSE.String()}, false)
   496  			}
   497  		}
   498  	default:
   499  		switch commaCnt {
   500  		case 0:
   501  			if c.tokens[c.lastIdx].Token == '(' {
   502  				switch strings.ToUpper(c.tokens[0].Literal) {
   503  				case option.CSV.String():
   504  					cands = c.candidateList(delimiterCandidates, false)
   505  				case option.FIXED.String():
   506  					cands = c.candidateList(delimiterPositionsCandidates, false)
   507  				}
   508  			}
   509  		case 1:
   510  			if c.tokens[c.lastIdx].Token == ',' {
   511  				cands = c.SearchAllTables(line, origLine, index)
   512  			}
   513  		case 2:
   514  			if c.tokens[c.lastIdx].Token == ',' {
   515  				switch strings.ToUpper(c.tokens[0].Literal) {
   516  				case option.CSV.String(), option.FIXED.String():
   517  					cands = c.candidateList(c.encodingList(), false)
   518  				}
   519  			}
   520  		case 3, 4:
   521  			if c.tokens[c.lastIdx].Token == ',' {
   522  				switch strings.ToUpper(c.tokens[0].Literal) {
   523  				case option.CSV.String(), option.FIXED.String():
   524  					cands = c.candidateList([]string{ternary.TRUE.String(), ternary.FALSE.String()}, false)
   525  				}
   526  			}
   527  		}
   528  	}
   529  
   530  	cands = append(cands, c.SearchValues(line, origLine, index)...)
   531  	return cands
   532  }
   533  
   534  func (c *Completer) FunctionArgs(line string, origLine string, index int) readline.CandidateList {
   535  	if c.tokens[0].Token == parser.SUBSTRING {
   536  		return c.substringArgs(line, origLine, index)
   537  	} else {
   538  		return c.functionArgs(line, origLine, index)
   539  	}
   540  }
   541  
   542  func (c *Completer) substringArgs(line string, origLine string, index int) readline.CandidateList {
   543  	return c.completeArgs(
   544  		line,
   545  		origLine,
   546  		index,
   547  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
   548  			customList = append(customList, c.SearchValues(line, origLine, index)...)
   549  			customList.Sort()
   550  
   551  			switch c.tokens[i].Token {
   552  			case parser.FOR:
   553  				//Do nothing
   554  			case parser.FROM:
   555  				if i < c.lastIdx {
   556  					keywords = append(keywords, "FOR")
   557  				}
   558  			case parser.SUBSTRING:
   559  				if i < c.lastIdx-1 {
   560  					keywords = append(keywords, "FROM")
   561  				}
   562  			default:
   563  				return keywords, customList, false
   564  			}
   565  
   566  			return keywords, customList, true
   567  		},
   568  	)
   569  }
   570  
   571  func (c *Completer) functionArgs(line string, origLine string, index int) readline.CandidateList {
   572  	return c.completeArgs(
   573  		line,
   574  		origLine,
   575  		index,
   576  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
   577  			switch c.tokens[i].Token {
   578  			case parser.BETWEEN:
   579  				if i == c.lastIdx {
   580  					customList = append(customList, c.candidateList([]string{
   581  						"UNBOUNDED PRECEDING",
   582  						"CURRENT ROW",
   583  					}, true)...)
   584  				} else if i == c.lastIdx-1 {
   585  					switch c.tokens[c.lastIdx].Token {
   586  					case parser.UNBOUNDED:
   587  						customList = c.candidateList([]string{"PRECEDING"}, true)
   588  					case parser.CURRENT:
   589  						customList = c.candidateList([]string{"ROW"}, true)
   590  					default:
   591  						customList = c.candidateList([]string{
   592  							"PRECEDING",
   593  							"FOLLOWING",
   594  						}, true)
   595  					}
   596  				} else if c.tokens[c.lastIdx].Token == parser.PRECEDING ||
   597  					c.tokens[c.lastIdx].Token == parser.FOLLOWING ||
   598  					c.tokens[c.lastIdx].Token == parser.ROW {
   599  
   600  					keywords = append(keywords, "AND")
   601  				} else if c.tokens[c.lastIdx].Token == parser.AND {
   602  					customList = append(customList, c.candidateList([]string{
   603  						"UNBOUNDED FOLLOWING",
   604  						"CURRENT ROW",
   605  					}, false)...)
   606  				} else {
   607  					switch c.tokens[c.lastIdx].Token {
   608  					case parser.UNBOUNDED:
   609  						customList = c.candidateList([]string{"FOLLOWING"}, false)
   610  					case parser.CURRENT:
   611  						customList = c.candidateList([]string{"ROW"}, false)
   612  					default:
   613  						customList = c.candidateList([]string{
   614  							"PRECEDING",
   615  							"FOLLOWING",
   616  						}, false)
   617  					}
   618  				}
   619  			case parser.ROWS:
   620  				if i == c.lastIdx {
   621  					customList = append(customList, c.candidateList([]string{
   622  						"UNBOUNDED PRECEDING",
   623  						"CURRENT ROW",
   624  					}, false)...)
   625  
   626  					customList = append(customList, c.candidate("BETWEEN", true))
   627  				} else if i == c.lastIdx-1 {
   628  					switch c.tokens[c.lastIdx].Token {
   629  					case parser.CURRENT:
   630  						customList = c.candidateList([]string{"ROW"}, false)
   631  					default:
   632  						customList = c.candidateList([]string{"PRECEDING"}, false)
   633  					}
   634  				}
   635  			case parser.ORDER:
   636  				if i == c.lastIdx {
   637  					keywords = append(keywords, "BY")
   638  				} else {
   639  					if i < c.lastIdx-1 && c.tokens[c.lastIdx].Token != ',' {
   640  						canUseWindowingClause := false
   641  
   642  						switch c.tokens[c.lastIdx].Token {
   643  						case parser.ASC, parser.DESC:
   644  							customList = append(customList, c.candidateList([]string{
   645  								"NULLS FIRST",
   646  								"NULLS LAST",
   647  							}, false)...)
   648  							canUseWindowingClause = true
   649  						case parser.NULLS:
   650  							customList = append(customList, c.candidateList([]string{
   651  								"FIRST",
   652  								"LAST",
   653  							}, false)...)
   654  						case parser.FIRST, parser.LAST:
   655  							canUseWindowingClause = true
   656  						default:
   657  							customList = append(customList, c.candidateList([]string{
   658  								"ASC",
   659  								"DESC",
   660  								"NULLS FIRST",
   661  								"NULLS LAST",
   662  							}, false)...)
   663  							customList = append(customList, c.SearchValues(line, origLine, index)...)
   664  
   665  							canUseWindowingClause = true
   666  						}
   667  
   668  						if canUseWindowingClause {
   669  							funcName := strings.ToUpper(c.tokens[0].Literal)
   670  							if funcName == "FIRST_VALUE" ||
   671  								funcName == "LAST_VALUE" ||
   672  								funcName == "NTH_VALUE" ||
   673  								(funcName != "LISTAGG" && funcName != "JSON_AGG" && query.InStrSliceWithCaseInsensitive(funcName, c.aggFuncs)) ||
   674  								query.InStrSliceWithCaseInsensitive(funcName, c.userAggFuncs) {
   675  
   676  								customList = append(customList, c.candidate("ROWS", true))
   677  							}
   678  						}
   679  					} else {
   680  						customList = append(customList, c.SearchValues(line, origLine, index)...)
   681  					}
   682  				}
   683  			case parser.PARTITION:
   684  				if i == c.lastIdx {
   685  					keywords = append(keywords,
   686  						"BY",
   687  					)
   688  				} else {
   689  					if i < c.lastIdx-1 && c.tokens[c.lastIdx].Token != ',' {
   690  						keywords = append(keywords,
   691  							"ORDER BY",
   692  						)
   693  					}
   694  					customList = append(customList, c.SearchValues(line, origLine, index)...)
   695  				}
   696  			case parser.OVER:
   697  				if i == c.lastIdx-1 && c.tokens[c.lastIdx].Token == '(' {
   698  					keywords = append(keywords,
   699  						"PARTITION BY",
   700  						"ORDER BY",
   701  					)
   702  				}
   703  			default:
   704  				if i == 0 {
   705  					if 0 < len(line) && i == c.lastIdx-1 {
   706  						if query.InStrSliceWithCaseInsensitive(c.tokens[i].Literal, c.aggFuncs) ||
   707  							query.InStrSliceWithCaseInsensitive(c.tokens[i].Literal, c.userAggFuncs) {
   708  							keywords = append(keywords, "DISTINCT")
   709  						}
   710  					}
   711  					customList = append(customList, c.SearchValues(line, origLine, index)...)
   712  				} else {
   713  					return nil, nil, false
   714  				}
   715  			}
   716  
   717  			if customList != nil {
   718  				customList.Sort()
   719  			}
   720  			return keywords, customList, true
   721  		},
   722  	)
   723  }
   724  
   725  func (c *Completer) WithArgs(line string, origLine string, index int) readline.CandidateList {
   726  	var searchQuery = func() int {
   727  		blockLevel := 0
   728  		for i := 0; i < len(c.tokens); i++ {
   729  			switch c.tokens[i].Token {
   730  			case ')':
   731  				blockLevel++
   732  			case '(':
   733  				blockLevel--
   734  			case parser.SELECT, parser.INSERT, parser.UPDATE, parser.REPLACE, parser.DELETE:
   735  				if blockLevel == 0 {
   736  					return i
   737  				}
   738  			}
   739  		}
   740  		return -1
   741  	}
   742  
   743  	if queryStart := searchQuery(); -1 < queryStart {
   744  		c.tokens = c.tokens[queryStart:]
   745  		c.SetLastIndex(line)
   746  
   747  		switch c.tokens[0].Token {
   748  		case parser.SELECT:
   749  			return c.SelectArgs(line, origLine, index)
   750  		case parser.INSERT:
   751  			return c.InsertArgs(line, origLine, index)
   752  		case parser.UPDATE:
   753  			return c.UpdateArgs(line, origLine, index)
   754  		case parser.REPLACE:
   755  			return c.ReplaceArgs(line, origLine, index)
   756  		case parser.DELETE:
   757  			return c.DeleteArgs(line, origLine, index)
   758  		}
   759  	}
   760  
   761  	blockLevel := 0
   762  
   763  	return c.completeArgs(
   764  		line,
   765  		origLine,
   766  		index,
   767  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
   768  			switch c.tokens[i].Token {
   769  			case ')':
   770  				blockLevel++
   771  				if blockLevel == 1 && i == c.lastIdx {
   772  					keywords = append(keywords, "AS")
   773  				}
   774  			case '(':
   775  				blockLevel--
   776  				if blockLevel == -1 && i == c.lastIdx && c.tokens[c.lastIdx-1].Token == parser.AS {
   777  					keywords = append(keywords, "SELECT")
   778  				}
   779  			case parser.WITH:
   780  				if blockLevel == 0 {
   781  					switch {
   782  					case i == c.lastIdx || c.tokens[c.lastIdx].Token == ',':
   783  						keywords = append(keywords, "RECURSIVE")
   784  					case c.tokens[c.lastIdx].Token == parser.IDENTIFIER:
   785  						if c.tokens[c.lastIdx].Literal == dummySubquery && c.tokens[c.lastIdx-1].Token == parser.AS {
   786  							keywords = append(keywords,
   787  								"SELECT",
   788  								"INSERT",
   789  								"UPDATE",
   790  								"REPLACE",
   791  								"DELETE",
   792  							)
   793  						} else {
   794  							keywords = append(keywords, "AS")
   795  						}
   796  					}
   797  				}
   798  			default:
   799  				return nil, nil, false
   800  			}
   801  			return keywords, customList, true
   802  		},
   803  	)
   804  }
   805  
   806  func (c *Completer) combineTableAlias(fromIdx int) {
   807  	combined := make([]parser.Token, 0, cap(c.tokens))
   808  	temp := make([]parser.Token, 0, cap(c.tokens))
   809  	blockLevel := 0
   810  	for i := 0; i < len(c.tokens); i++ {
   811  		if i <= fromIdx {
   812  			combined = append(combined, c.tokens[i])
   813  			continue
   814  		}
   815  
   816  		if 0 != blockLevel {
   817  			temp = append(temp, c.tokens[i])
   818  
   819  			switch c.tokens[i].Token {
   820  			case '(':
   821  				blockLevel++
   822  			case ')':
   823  				blockLevel--
   824  				if 0 == blockLevel {
   825  					combined = append(combined, parser.Token{Token: parser.IDENTIFIER, Literal: dummyTable, Quoted: true})
   826  					temp = temp[:0]
   827  				}
   828  			}
   829  			continue
   830  		}
   831  
   832  		if c.tokens[i].Token == '(' {
   833  			blockLevel++
   834  			temp = append(temp, c.tokens[i])
   835  			continue
   836  		}
   837  
   838  		combined = append(combined, c.tokens[i])
   839  
   840  		if c.tokens[i].Token == parser.IDENTIFIER {
   841  			combined[len(combined)-1].Quoted = false
   842  			if i+2 <= c.lastIdx && c.tokens[i+1].Token == parser.AS && c.tokens[i+2].Token == parser.IDENTIFIER {
   843  				i = i + 2
   844  				combined[len(combined)-1].Quoted = true
   845  			} else if i+1 <= c.lastIdx && c.tokens[i+1].Token == parser.IDENTIFIER {
   846  				i = i + 1
   847  				combined[len(combined)-1].Quoted = true
   848  			}
   849  		}
   850  	}
   851  	if 0 < len(temp) {
   852  		combined = append(combined, temp...)
   853  	}
   854  
   855  	c.tokens = combined
   856  }
   857  
   858  func (c *Completer) allTableCandidates(line string, origLine string, index int) readline.CandidateList {
   859  	list := c.candidateList(append(tableObjectCandidates, "JSON_TABLE()"), false)
   860  	list.Sort()
   861  	list = append(list, c.SearchAllTables(line, origLine, index)...)
   862  	return list
   863  }
   864  
   865  func (c *Completer) allTableCandidatesForUpdate(line string, origLine string, index int) readline.CandidateList {
   866  	list := c.candidateList(tableObjectCandidates, false)
   867  	list.Sort()
   868  	list = append(list, c.SearchAllTables(line, origLine, index)...)
   869  	return list
   870  }
   871  
   872  func (c *Completer) allTableCandidatesWithSpaceForUpdate(line string, origLine string, index int) readline.CandidateList {
   873  	list := c.candidateList(tableObjectCandidates, true)
   874  	list.Sort()
   875  	list = append(list, c.SearchAllTablesWithSpace(line, origLine, index)...)
   876  	return list
   877  }
   878  
   879  func (c *Completer) fromClause(i int, line string, origLine string, index int) (tables readline.CandidateList, customList readline.CandidateList, restrict bool) {
   880  	c.combineTableAlias(i)
   881  	c.SetLastIndex(line)
   882  
   883  	var isInUsing = func() bool {
   884  		for j := len(c.tokens) - 1; j > i; j-- {
   885  			switch c.tokens[j].Token {
   886  			case parser.IDENTIFIER, ',':
   887  				//OK
   888  			case '(':
   889  				return c.tokens[j-1].Token == parser.USING
   890  			default:
   891  				return false
   892  			}
   893  		}
   894  		return false
   895  	}
   896  
   897  	var isInOn = func() bool {
   898  		blockLevel := 0
   899  		for j := len(c.tokens) - 1; j > i; j-- {
   900  			switch c.tokens[j].Token {
   901  			case '(':
   902  				blockLevel--
   903  			case ')':
   904  				blockLevel++
   905  			case parser.JOIN:
   906  				if blockLevel <= 0 {
   907  					return false
   908  				}
   909  			case parser.ON:
   910  				if blockLevel <= 0 {
   911  					return true
   912  				}
   913  			}
   914  		}
   915  		return false
   916  	}
   917  
   918  	var joinConditionRequired = func() bool {
   919  		if c.tokens[c.lastIdx].Token == '(' {
   920  			return false
   921  		}
   922  
   923  		baseIdx := c.lastIdx - 1
   924  		if c.tokens[baseIdx].Token == parser.LATERAL {
   925  			baseIdx--
   926  		}
   927  
   928  		if c.tokens[baseIdx].Token != parser.JOIN {
   929  			return false
   930  		}
   931  		if c.tokens[baseIdx-1].Token == parser.CROSS ||
   932  			c.tokens[baseIdx-1].Token == parser.NATURAL ||
   933  			c.tokens[baseIdx-2].Token == parser.NATURAL ||
   934  			c.tokens[baseIdx-3].Token == parser.NATURAL {
   935  			return false
   936  		}
   937  		return true
   938  	}
   939  
   940  	if isInUsing() {
   941  		restrict = true
   942  		return
   943  	}
   944  
   945  	if isInOn() {
   946  		customList = append(customList, c.whereClause(line, origLine, index)...)
   947  		if c.tokens[c.lastIdx].Token == parser.ON {
   948  			restrict = true
   949  		} else {
   950  			customList = append(customList, c.candidateList(joinCandidates, true)...)
   951  		}
   952  		return
   953  	}
   954  
   955  	switch c.tokens[c.lastIdx].Token {
   956  	case parser.LATERAL:
   957  		restrict = true
   958  	case parser.CROSS, parser.INNER, parser.OUTER:
   959  		customList = append(customList, c.candidate("JOIN", true))
   960  		restrict = true
   961  	case parser.LEFT, parser.RIGHT, parser.FULL:
   962  		customList = append(customList, c.candidateList([]string{"JOIN", "OUTER"}, true)...)
   963  		restrict = true
   964  	case parser.NATURAL:
   965  		customList = append(customList, c.candidateList([]string{"INNER", "LEFT", "RIGHT"}, true)...)
   966  		restrict = true
   967  	case parser.AS, parser.USING:
   968  		restrict = true
   969  	}
   970  
   971  	if joinConditionRequired() {
   972  		customList = append(customList, c.candidate("ON", true))
   973  
   974  		if c.tokens[c.lastIdx-2].Token != parser.FULL &&
   975  			c.tokens[c.lastIdx-3].Token != parser.FULL {
   976  
   977  			customList = append(customList, c.candidate("USING ()", true))
   978  		}
   979  
   980  		if c.tokens[c.lastIdx].Quoted == false {
   981  			customList = append(customList, c.candidate("AS", true))
   982  		}
   983  		restrict = true
   984  	} else {
   985  		canUseLateral := false
   986  		switch c.tokens[c.lastIdx].Token {
   987  		case ',':
   988  			canUseLateral = true
   989  		case parser.JOIN:
   990  			canUseLateral = true
   991  			switch c.tokens[c.lastIdx-1].Token {
   992  			case parser.RIGHT, parser.FULL:
   993  				canUseLateral = false
   994  			case parser.OUTER:
   995  				switch c.tokens[c.lastIdx-2].Token {
   996  				case parser.RIGHT, parser.FULL:
   997  					canUseLateral = false
   998  				}
   999  			}
  1000  
  1001  		}
  1002  
  1003  		if canUseLateral {
  1004  			customList = append(customList, c.candidate("LATERAL", true))
  1005  		}
  1006  
  1007  		switch c.tokens[c.lastIdx].Token {
  1008  		case '(':
  1009  			customList = append(customList, c.candidate("SELECT", true))
  1010  			fallthrough
  1011  		case parser.FROM, parser.JOIN, ',':
  1012  			tables = c.allTableCandidates(line, origLine, index)
  1013  			restrict = true
  1014  		}
  1015  	}
  1016  
  1017  	if restrict {
  1018  		return
  1019  	}
  1020  
  1021  	if c.tokens[c.lastIdx].Token == parser.IDENTIFIER {
  1022  		customList = append(customList, c.candidateList(joinCandidates, true)...)
  1023  
  1024  		if c.tokens[c.lastIdx].Quoted == false {
  1025  			customList = append(customList, c.candidate("AS", true))
  1026  		}
  1027  	}
  1028  	return
  1029  }
  1030  
  1031  func (c *Completer) whereClause(line string, origLine string, index int) readline.CandidateList {
  1032  	cands := c.SearchValues(line, origLine, index)
  1033  	if 0 < len(line) {
  1034  		cands = append(cands, c.candidate("JSON_ROW()", false))
  1035  	}
  1036  	return cands
  1037  }
  1038  
  1039  func (c *Completer) SelectArgs(line string, origLine string, index int) readline.CandidateList {
  1040  	isSelectInto := false
  1041  	if c.selectIntoEnabled {
  1042  		for i := len(c.tokens) - 1; i >= 0; i-- {
  1043  			if c.tokens[i].Token == parser.INTO {
  1044  				isSelectInto = true
  1045  				break
  1046  			}
  1047  		}
  1048  	}
  1049  
  1050  	return c.completeArgs(
  1051  		line,
  1052  		origLine,
  1053  		index,
  1054  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1055  			switch c.tokens[i].Token {
  1056  			case parser.FOR:
  1057  				if i == c.lastIdx {
  1058  					customList = append(customList, c.candidateList([]string{
  1059  						"UPDATE",
  1060  					}, false)...)
  1061  					customList.Sort()
  1062  				}
  1063  				return nil, customList, true
  1064  			case parser.LIMIT:
  1065  				if i < c.lastIdx {
  1066  					switch c.tokens[c.lastIdx].Token {
  1067  					case parser.PERCENT:
  1068  						customList = append(customList, c.candidateList([]string{
  1069  							"OFFSET",
  1070  						}, true)...)
  1071  						customList = append(customList, c.candidateList([]string{
  1072  							"WITH TIES",
  1073  							"FOR UPDATE",
  1074  						}, false)...)
  1075  					case parser.WITH:
  1076  						customList = append(customList, c.candidate("TIES", false))
  1077  					case parser.TIES:
  1078  						customList = append(customList, c.candidateList([]string{
  1079  							"OFFSET",
  1080  						}, true)...)
  1081  						customList = append(customList, c.candidate("FOR UPDATE", false))
  1082  					default:
  1083  						customList = append(customList, c.candidateList([]string{
  1084  							"OFFSET",
  1085  						}, true)...)
  1086  						customList = append(customList, c.candidateList([]string{
  1087  							"PERCENT",
  1088  							"WITH TIES",
  1089  							"FOR UPDATE",
  1090  						}, false)...)
  1091  						customList = append(customList, c.SearchValues(line, origLine, index)...)
  1092  					}
  1093  				} else {
  1094  					customList = append(customList, c.SearchValues(line, origLine, index)...)
  1095  				}
  1096  				customList.Sort()
  1097  				return keywords, customList, true
  1098  			case parser.FETCH:
  1099  				if i == c.lastIdx {
  1100  					afterOffset := false
  1101  
  1102  				CompleterSelectArgsSearchOffsetLoop:
  1103  					for j := c.lastIdx - 1; j >= 0; j-- {
  1104  						switch c.tokens[j].Token {
  1105  						case parser.OFFSET:
  1106  							afterOffset = true
  1107  							break CompleterSelectArgsSearchOffsetLoop
  1108  						case parser.ORDER, parser.HAVING, parser.GROUP, parser.FROM, parser.SELECT:
  1109  							break CompleterSelectArgsSearchOffsetLoop
  1110  						}
  1111  					}
  1112  
  1113  					if afterOffset {
  1114  						keywords = append(keywords, "NEXT")
  1115  					} else {
  1116  						keywords = append(keywords, "FIRST")
  1117  					}
  1118  				} else {
  1119  					switch c.tokens[c.lastIdx].Token {
  1120  					case parser.ROW, parser.ROWS, parser.PERCENT:
  1121  						customList = append(customList, c.candidateList([]string{
  1122  							"ONLY",
  1123  							"WITH TIES",
  1124  							"FOR UPDATE",
  1125  						}, false)...)
  1126  					case parser.WITH:
  1127  						customList = append(customList, c.candidateList([]string{
  1128  							"TIES",
  1129  						}, false)...)
  1130  					case parser.ONLY, parser.TIES:
  1131  						customList = append(customList, c.candidateList([]string{
  1132  							"FOR UPDATE",
  1133  						}, false)...)
  1134  					case parser.FIRST, parser.NEXT:
  1135  						//Do nothing
  1136  					default:
  1137  						if c.tokens[c.lastIdx].Literal == "1" {
  1138  							keywords = append(keywords, "ROW")
  1139  						} else {
  1140  							keywords = append(keywords, "ROWS")
  1141  						}
  1142  						keywords = append(keywords, "PERCENT")
  1143  					}
  1144  				}
  1145  
  1146  				if customList != nil {
  1147  					customList.Sort()
  1148  				}
  1149  				return keywords, customList, true
  1150  			case parser.OFFSET:
  1151  				if i < c.lastIdx {
  1152  					afterLimit := false
  1153  
  1154  				CompleterSelectArgsSearchLimitLoop:
  1155  					for j := c.lastIdx - 1; j >= 0; j-- {
  1156  						switch c.tokens[j].Token {
  1157  						case parser.LIMIT:
  1158  							afterLimit = true
  1159  							break CompleterSelectArgsSearchLimitLoop
  1160  						case parser.ORDER, parser.HAVING, parser.GROUP, parser.FROM, parser.SELECT:
  1161  							break CompleterSelectArgsSearchLimitLoop
  1162  						}
  1163  					}
  1164  
  1165  					if !afterLimit {
  1166  						customList = append(customList, c.candidateList([]string{
  1167  							"FETCH",
  1168  						}, true)...)
  1169  					}
  1170  
  1171  					customList = append(customList, c.candidateList([]string{
  1172  						"FOR UPDATE",
  1173  					}, false)...)
  1174  					if c.tokens[c.lastIdx].Token != parser.ROW && c.tokens[c.lastIdx].Token != parser.ROWS {
  1175  						if c.tokens[c.lastIdx].Literal == "1" {
  1176  							customList = append(customList, c.candidateList([]string{
  1177  								"ROW",
  1178  							}, false)...)
  1179  						} else {
  1180  							customList = append(customList, c.candidateList([]string{
  1181  								"ROWS",
  1182  							}, false)...)
  1183  						}
  1184  					}
  1185  				}
  1186  				customList = append(customList, c.SearchValues(line, origLine, index)...)
  1187  				customList.Sort()
  1188  				return nil, customList, true
  1189  			case parser.ORDER:
  1190  				if i == c.lastIdx {
  1191  					keywords = append(keywords, "BY")
  1192  				} else if i < c.lastIdx-1 && c.tokens[c.lastIdx].Token != ',' {
  1193  					switch c.tokens[c.lastIdx].Token {
  1194  					case parser.ASC, parser.DESC:
  1195  						customList = append(customList, c.candidateList([]string{
  1196  							"NULLS FIRST",
  1197  							"NULLS LAST",
  1198  							"FOR UPDATE",
  1199  						}, false)...)
  1200  						customList = append(customList, c.candidateList([]string{
  1201  							"OFFSET",
  1202  							"FETCH",
  1203  							"LIMIT",
  1204  						}, true)...)
  1205  					case parser.NULLS:
  1206  						customList = append(customList, c.candidateList([]string{
  1207  							"FIRST",
  1208  							"LAST",
  1209  						}, false)...)
  1210  					case parser.FIRST, parser.LAST:
  1211  						customList = append(customList, c.candidateList([]string{
  1212  							"OFFSET",
  1213  							"FETCH",
  1214  							"LIMIT",
  1215  						}, true)...)
  1216  						customList = append(customList, c.candidateList([]string{
  1217  							"FOR UPDATE",
  1218  						}, false)...)
  1219  					default:
  1220  						customList = append(customList, c.candidateList([]string{
  1221  							"ASC",
  1222  							"DESC",
  1223  							"NULLS FIRST",
  1224  							"NULLS LAST",
  1225  							"FOR UPDATE",
  1226  						}, false)...)
  1227  						customList = append(customList, c.candidateList([]string{
  1228  							"OFFSET",
  1229  							"FETCH",
  1230  							"LIMIT",
  1231  						}, true)...)
  1232  						customList = append(customList, c.SearchValues(line, origLine, index)...)
  1233  					}
  1234  				} else {
  1235  					customList = append(customList, c.SearchValues(line, origLine, index)...)
  1236  				}
  1237  
  1238  				if customList != nil {
  1239  					customList.Sort()
  1240  				}
  1241  				return keywords, customList, true
  1242  			case parser.ALL:
  1243  				if i == c.lastIdx && 0 <= c.lastIdx-1 {
  1244  					switch c.tokens[i-1].Token {
  1245  					case parser.UNION, parser.EXCEPT, parser.INTERSECT:
  1246  						keywords = append(keywords, "SELECT")
  1247  						return keywords, nil, true
  1248  					}
  1249  				}
  1250  			case parser.UNION, parser.EXCEPT, parser.INTERSECT:
  1251  				if i == c.lastIdx {
  1252  					keywords = append(keywords,
  1253  						"ALL",
  1254  						"SELECT",
  1255  					)
  1256  				}
  1257  				return keywords, nil, true
  1258  			case parser.HAVING:
  1259  				customList = append(customList, c.whereClause(line, origLine, index)...)
  1260  				customList = append(customList, c.aggregateFunctionCandidateList(line)...)
  1261  				if i < c.lastIdx {
  1262  					customList = append(customList, c.candidateList([]string{
  1263  						"ORDER BY",
  1264  						"OFFSET",
  1265  						"FETCH",
  1266  						"LIMIT",
  1267  					}, true)...)
  1268  					if !isSelectInto {
  1269  						customList = append(customList, c.candidateList([]string{
  1270  							"UNION",
  1271  							"EXCEPT",
  1272  							"INTERSECT",
  1273  						}, true)...)
  1274  					}
  1275  					customList = append(customList, c.candidateList([]string{
  1276  						"FOR UPDATE",
  1277  					}, false)...)
  1278  				}
  1279  				customList.Sort()
  1280  				return keywords, customList, true
  1281  			case parser.GROUP:
  1282  				if i == c.lastIdx {
  1283  					keywords = append(keywords, "BY")
  1284  				} else {
  1285  					customList = append(customList, c.whereClause(line, origLine, index)...)
  1286  					if i < c.lastIdx-1 && c.tokens[c.lastIdx].Token != ',' {
  1287  						customList = append(customList, c.candidateList([]string{
  1288  							"HAVING",
  1289  							"ORDER BY",
  1290  							"OFFSET",
  1291  							"FETCH",
  1292  							"LIMIT",
  1293  						}, true)...)
  1294  						if !isSelectInto {
  1295  							customList = append(customList, c.candidateList([]string{
  1296  								"UNION",
  1297  								"EXCEPT",
  1298  								"INTERSECT",
  1299  							}, true)...)
  1300  						}
  1301  						customList = append(customList, c.candidateList([]string{
  1302  							"FOR UPDATE",
  1303  						}, false)...)
  1304  					}
  1305  					customList.Sort()
  1306  				}
  1307  				return keywords, customList, true
  1308  			case parser.WHERE:
  1309  				customList = append(customList, c.whereClause(line, origLine, index)...)
  1310  				if i < c.lastIdx {
  1311  					customList = append(customList, c.candidateList([]string{
  1312  						"GROUP BY",
  1313  						"HAVING",
  1314  						"ORDER BY",
  1315  						"OFFSET",
  1316  						"FETCH",
  1317  						"LIMIT",
  1318  					}, true)...)
  1319  					if !isSelectInto {
  1320  						customList = append(customList, c.candidateList([]string{
  1321  							"UNION",
  1322  							"EXCEPT",
  1323  							"INTERSECT",
  1324  						}, true)...)
  1325  					}
  1326  					customList = append(customList, c.candidateList([]string{
  1327  						"FOR UPDATE",
  1328  					}, false)...)
  1329  				}
  1330  				customList.Sort()
  1331  				return keywords, customList, true
  1332  			case parser.FROM:
  1333  				tables, clist, restrict := c.fromClause(i, line, origLine, index)
  1334  				if !restrict {
  1335  					if i < c.lastIdx && c.tokens[c.lastIdx].Token != ',' {
  1336  						clist = append(clist, c.candidateList([]string{
  1337  							"WHERE",
  1338  							"GROUP BY",
  1339  							"HAVING",
  1340  							"ORDER BY",
  1341  							"OFFSET",
  1342  							"FETCH",
  1343  							"LIMIT",
  1344  						}, true)...)
  1345  						if !isSelectInto {
  1346  							clist = append(clist, c.candidateList([]string{
  1347  								"UNION",
  1348  								"EXCEPT",
  1349  								"INTERSECT",
  1350  							}, true)...)
  1351  						}
  1352  						clist = append(clist, c.candidateList([]string{
  1353  							"FOR UPDATE",
  1354  						}, false)...)
  1355  					}
  1356  				}
  1357  				clist.Sort()
  1358  				return nil, append(tables, clist...), true
  1359  			case parser.INTO:
  1360  				switch c.tokens[c.lastIdx].Token {
  1361  				case parser.INTO, ',':
  1362  					customList = append(customList, c.candidateList(c.varList, false)...)
  1363  				case parser.VARIABLE:
  1364  					customList = append(customList, c.candidateList([]string{
  1365  						"FROM",
  1366  						"WHERE",
  1367  						"GROUP BY",
  1368  						"HAVING",
  1369  						"ORDER BY",
  1370  						"OFFSET",
  1371  						"FETCH",
  1372  						"LIMIT",
  1373  					}, true)...)
  1374  					customList = append(customList, c.candidateList([]string{
  1375  						"FOR UPDATE",
  1376  					}, false)...)
  1377  				}
  1378  				if customList != nil {
  1379  					customList.Sort()
  1380  				}
  1381  				return keywords, customList, true
  1382  			case parser.SELECT:
  1383  				if i == c.lastIdx {
  1384  					if 0 < len(line) {
  1385  						keywords = append(keywords, "DISTINCT")
  1386  					}
  1387  				} else {
  1388  					lastIdx := c.lastIdx
  1389  					if i+1 < len(c.tokens) && c.tokens[i+1].Token == parser.DISTINCT {
  1390  						lastIdx--
  1391  					}
  1392  					if i < lastIdx && c.tokens[c.lastIdx].Token != ',' {
  1393  						customList = append(customList, c.candidateList([]string{
  1394  							"AS",
  1395  							"FROM",
  1396  							"WHERE",
  1397  							"GROUP BY",
  1398  							"HAVING",
  1399  							"ORDER BY",
  1400  							"OFFSET",
  1401  							"FETCH",
  1402  							"LIMIT",
  1403  							"UNION",
  1404  							"EXCEPT",
  1405  							"INTERSECT",
  1406  						}, true)...)
  1407  						customList = append(customList, c.candidateList([]string{
  1408  							"FOR UPDATE",
  1409  						}, false)...)
  1410  						if c.selectIntoEnabled {
  1411  							customList = append(customList, c.candidateList([]string{
  1412  								"INTO",
  1413  							}, true)...)
  1414  						}
  1415  					}
  1416  				}
  1417  				customList = append(customList, c.SearchValues(line, origLine, index)...)
  1418  				customList.Sort()
  1419  				return keywords, customList, true
  1420  			}
  1421  			return nil, nil, false
  1422  		},
  1423  	)
  1424  }
  1425  
  1426  func (c *Completer) InsertArgs(line string, origLine string, index int) readline.CandidateList {
  1427  	return c.completeArgs(
  1428  		line,
  1429  		origLine,
  1430  		index,
  1431  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1432  			switch c.tokens[i].Token {
  1433  			case parser.SELECT:
  1434  				return nil, c.SelectArgs(line, origLine, index), true
  1435  			case parser.VALUES:
  1436  				customList = c.SearchValues(line, origLine, index)
  1437  				if 0 < len(line) {
  1438  					customList = append(customList, c.candidate("JSON_ROW()", false))
  1439  				}
  1440  				customList.Sort()
  1441  				return nil, customList, true
  1442  			case parser.INTO:
  1443  				if i == c.lastIdx {
  1444  					customList = c.allTableCandidatesWithSpaceForUpdate(line, origLine, index)
  1445  				} else {
  1446  					if c.tokens[c.lastIdx-1].Token == parser.INTO || c.tokens[c.lastIdx].Token == ')' {
  1447  						keywords = append(keywords, "VALUES", "SELECT")
  1448  					}
  1449  				}
  1450  				return keywords, customList, true
  1451  			case parser.INSERT:
  1452  				if i == c.lastIdx {
  1453  					keywords = append(keywords, "INTO")
  1454  				}
  1455  				return keywords, nil, true
  1456  			}
  1457  			return nil, nil, false
  1458  		},
  1459  	)
  1460  }
  1461  
  1462  func (c *Completer) UpdateArgs(line string, origLine string, index int) readline.CandidateList {
  1463  	return c.completeArgs(
  1464  		line,
  1465  		origLine,
  1466  		index,
  1467  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1468  			switch c.tokens[i].Token {
  1469  			case parser.WHERE:
  1470  				customList = append(customList, c.whereClause(line, origLine, index)...)
  1471  				customList.Sort()
  1472  				return nil, customList, true
  1473  			case parser.FROM:
  1474  				tables, clist, restrict := c.fromClause(i, line, origLine, index)
  1475  				if !restrict {
  1476  					if i < c.lastIdx && c.tokens[c.lastIdx].Token != ',' {
  1477  						clist = append(clist, c.candidate("WHERE", true))
  1478  					}
  1479  				}
  1480  				clist.Sort()
  1481  				return nil, append(tables, clist...), true
  1482  			case parser.SET:
  1483  				if c.tokens[c.lastIdx].Token != parser.SET && c.tokens[c.lastIdx].Token != ',' &&
  1484  					c.tokens[c.lastIdx-1].Token != parser.SET && c.tokens[c.lastIdx-1].Token != ',' {
  1485  
  1486  					customList = append(customList, c.SearchValues(line, origLine, index)...)
  1487  					customList.Sort()
  1488  					if c.tokens[c.lastIdx].Token != '=' {
  1489  						keywords = append(keywords, "FROM", "WHERE")
  1490  					}
  1491  				}
  1492  				return keywords, customList, true
  1493  			case parser.UPDATE:
  1494  				if c.tokens[c.lastIdx].Token == parser.UPDATE || c.tokens[c.lastIdx].Token == ',' {
  1495  					customList = c.allTableCandidatesForUpdate(line, origLine, index)
  1496  				} else {
  1497  					keywords = append(keywords, "SET")
  1498  				}
  1499  				return keywords, customList, true
  1500  			}
  1501  			return nil, nil, false
  1502  		},
  1503  	)
  1504  }
  1505  
  1506  func (c *Completer) ReplaceArgs(line string, origLine string, index int) readline.CandidateList {
  1507  	usingExists := false
  1508  
  1509  	return c.completeArgs(
  1510  		line,
  1511  		origLine,
  1512  		index,
  1513  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1514  			switch c.tokens[i].Token {
  1515  			case parser.SELECT:
  1516  				return nil, c.SelectArgs(line, origLine, index), true
  1517  			case parser.VALUES:
  1518  				customList = c.SearchValues(line, origLine, index)
  1519  				if 0 < len(line) {
  1520  					customList = append(customList, c.candidate("JSON_ROW()", false))
  1521  				}
  1522  				customList.Sort()
  1523  				return nil, customList, true
  1524  			case parser.USING:
  1525  				usingExists = true
  1526  			case parser.INTO:
  1527  				if i == c.lastIdx {
  1528  					customList = c.allTableCandidatesWithSpaceForUpdate(line, origLine, index)
  1529  				} else if c.tokens[c.lastIdx-1].Token == parser.INTO || (!usingExists && c.tokens[c.lastIdx].Token == ')') {
  1530  					customList = append(customList, c.candidate("USING ()", true))
  1531  				} else if usingExists && c.tokens[c.lastIdx].Token == ')' {
  1532  					keywords = append(keywords, "VALUES", "SELECT")
  1533  				}
  1534  				return keywords, customList, true
  1535  			case parser.REPLACE:
  1536  				if i == c.lastIdx {
  1537  					keywords = append(keywords, "INTO")
  1538  				}
  1539  				return keywords, nil, true
  1540  			}
  1541  			return nil, nil, false
  1542  		},
  1543  	)
  1544  }
  1545  
  1546  func (c *Completer) DeleteArgs(line string, origLine string, index int) readline.CandidateList {
  1547  	return c.completeArgs(
  1548  		line,
  1549  		origLine,
  1550  		index,
  1551  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1552  			switch c.tokens[i].Token {
  1553  			case parser.WHERE:
  1554  				customList = append(customList, c.whereClause(line, origLine, index)...)
  1555  				customList.Sort()
  1556  				return nil, customList, true
  1557  			case parser.FROM:
  1558  				if c.tokens[i-1].Token == parser.DELETE {
  1559  					if c.tokens[c.lastIdx].Token == parser.FROM || c.tokens[c.lastIdx].Token == ',' {
  1560  						customList = c.allTableCandidates(line, origLine, index)
  1561  					} else {
  1562  						customList = append(customList, c.candidate("WHERE", true))
  1563  					}
  1564  				} else {
  1565  					tables, clist, restrict := c.fromClause(i, line, origLine, index)
  1566  					if !restrict {
  1567  						if i < c.lastIdx && c.tokens[c.lastIdx].Token != ',' {
  1568  							clist = append(clist, c.candidate("WHERE", true))
  1569  						}
  1570  					}
  1571  					clist.Sort()
  1572  					customList = append(tables, clist...)
  1573  				}
  1574  				return keywords, customList, true
  1575  			case parser.DELETE:
  1576  				if c.tokens[c.lastIdx].Token != ',' {
  1577  					keywords = append(keywords, "FROM")
  1578  				}
  1579  				return keywords, nil, true
  1580  			}
  1581  			return nil, nil, false
  1582  		},
  1583  	)
  1584  }
  1585  
  1586  func (c *Completer) CreateArgs(line string, origLine string, index int) readline.CandidateList {
  1587  	var isPrepositionOfSelect = func(i int) bool {
  1588  		for j := i; j >= 0; j-- {
  1589  			if c.tokens[j].Token == ';' || c.tokens[j].Token == parser.TABLE {
  1590  				break
  1591  			}
  1592  			if c.tokens[j].Token == parser.SELECT {
  1593  				return false
  1594  			}
  1595  		}
  1596  		return true
  1597  	}
  1598  
  1599  	return c.completeArgs(
  1600  		line,
  1601  		origLine,
  1602  		index,
  1603  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1604  			switch c.tokens[i].Token {
  1605  			case parser.SELECT:
  1606  				return nil, c.SelectArgs(line, origLine, index), true
  1607  			case parser.AS:
  1608  				if isPrepositionOfSelect(i) {
  1609  					return []string{"SELECT"}, nil, true
  1610  				}
  1611  			case parser.TABLE:
  1612  				if i == c.lastIdx {
  1613  					return []string{"IF NOT EXISTS"}, nil, true
  1614  				}
  1615  
  1616  				if c.lastIdx == i+1 && c.tokens[c.lastIdx].Token == parser.IF {
  1617  					return []string{"NOT EXISTS"}, nil, true
  1618  				}
  1619  				if c.lastIdx == i+2 && c.tokens[c.lastIdx].Token == parser.NOT && c.tokens[c.lastIdx-1].Token == parser.IF {
  1620  					return []string{"EXISTS"}, nil, true
  1621  				}
  1622  
  1623  				if (c.tokens[c.lastIdx].Token == ')' && c.BracketIsEnclosed()) ||
  1624  					i == c.lastIdx-1 {
  1625  					return []string{"AS", "SELECT"}, nil, true
  1626  				}
  1627  			case parser.CREATE:
  1628  				if i == c.lastIdx {
  1629  					return []string{"TABLE"}, nil, true
  1630  				}
  1631  			}
  1632  			return nil, nil, false
  1633  		},
  1634  	)
  1635  }
  1636  
  1637  func (c *Completer) AlterArgs(line string, origLine string, index int) readline.CandidateList {
  1638  	operations := []string{
  1639  		"ADD",
  1640  		"DROP",
  1641  		"RENAME",
  1642  		"SET",
  1643  	}
  1644  
  1645  	addPositions := []string{
  1646  		"FIRST",
  1647  		"LAST",
  1648  		"AFTER",
  1649  		"BEFORE",
  1650  	}
  1651  
  1652  	var columnsInTable = func(i int, appendSpace bool) readline.CandidateList {
  1653  		var tableName string
  1654  		for j := i; j >= 0; j-- {
  1655  			if c.tokens[j].Token == parser.TABLE {
  1656  				tableName = c.tokens[j+1].Literal
  1657  				break
  1658  			}
  1659  		}
  1660  
  1661  		var clist readline.CandidateList
  1662  		if 0 < len(tableName) {
  1663  			clist = c.identifierList(c.ColumnList(tableName, c.scope.Tx.Flags.Repository), appendSpace)
  1664  		}
  1665  		return clist
  1666  	}
  1667  
  1668  	return c.completeArgs(
  1669  		line,
  1670  		origLine,
  1671  		index,
  1672  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1673  			switch c.tokens[i].Token {
  1674  			case parser.AFTER, parser.BEFORE:
  1675  				return nil, columnsInTable(i, false), true
  1676  			case parser.ADD:
  1677  				prevToken := c.tokens[c.lastIdx].Token
  1678  
  1679  				if i+1 < len(c.tokens) && c.tokens[i+1].Token == '(' {
  1680  					if c.BracketIsEnclosed() {
  1681  						if prevToken == ')' {
  1682  							return nil, c.candidateList(addPositions, true), true
  1683  						}
  1684  					} else {
  1685  						switch {
  1686  						case prevToken == '(' || prevToken == ',':
  1687  							//Column
  1688  						case c.tokens[c.lastIdx-1].Token == '(' || c.tokens[c.lastIdx-1].Token == ',':
  1689  							return []string{"DEFAULT"}, nil, true
  1690  						default:
  1691  							return nil, c.SearchValues(line, origLine, index), true
  1692  						}
  1693  					}
  1694  				} else {
  1695  					switch i {
  1696  					case c.lastIdx:
  1697  						//Column
  1698  					case c.lastIdx - 1:
  1699  						return []string{"DEFAULT"}, c.candidateList(addPositions, true), true
  1700  					default:
  1701  						return nil, c.SearchValues(line, origLine, index), true
  1702  					}
  1703  				}
  1704  			case parser.DROP:
  1705  				if i+1 < len(c.tokens) && c.tokens[i+1].Token == '(' {
  1706  					if !c.BracketIsEnclosed() {
  1707  						return nil, columnsInTable(i, false), true
  1708  					}
  1709  				} else {
  1710  					switch i {
  1711  					case c.lastIdx:
  1712  						return nil, columnsInTable(i, false), true
  1713  					}
  1714  				}
  1715  			case parser.RENAME:
  1716  				switch i {
  1717  				case c.lastIdx:
  1718  					return nil, columnsInTable(i, true), true
  1719  				case c.lastIdx - 1:
  1720  					return []string{"TO"}, nil, true
  1721  				}
  1722  			case parser.SET:
  1723  				switch i {
  1724  				case c.lastIdx:
  1725  					return query.FileAttributeList, nil, true
  1726  				case c.lastIdx - 1:
  1727  					return []string{"TO"}, nil, true
  1728  				case c.lastIdx - 2:
  1729  					switch strings.ToUpper(c.tokens[c.lastIdx-1].Literal) {
  1730  					case query.TableFormat:
  1731  						return nil, c.candidateList(c.tableFormatList(), false), true
  1732  					case query.TableDelimiter:
  1733  						return nil, c.candidateList(delimiterCandidates, false), true
  1734  					case query.TableDelimiterPositions:
  1735  						return nil, c.candidateList(delimiterPositionsCandidates, false), true
  1736  					case query.TableEncoding:
  1737  						return nil, c.candidateList(exportEncodingsCandidates, false), true
  1738  					case query.TableLineBreak:
  1739  						return nil, c.candidateList(c.lineBreakList(), false), true
  1740  					case query.TableJsonEscape:
  1741  						return nil, c.candidateList(c.jsonEscapeTypeList(), false), true
  1742  					case query.TableHeader, query.TableEncloseAll, query.TablePrettyPrint:
  1743  						return nil, c.candidateList([]string{ternary.TRUE.String(), ternary.FALSE.String()}, false), true
  1744  					}
  1745  				}
  1746  			case parser.TABLE:
  1747  				switch i {
  1748  				case c.lastIdx:
  1749  					return nil, c.allTableCandidatesWithSpaceForUpdate(line, origLine, index), true
  1750  				case c.lastIdx - 1:
  1751  					return operations, nil, true
  1752  				}
  1753  			case parser.ALTER:
  1754  				if i == c.lastIdx {
  1755  					return []string{"TABLE"}, nil, true
  1756  				}
  1757  			default:
  1758  				return nil, nil, false
  1759  			}
  1760  			return nil, nil, true
  1761  		},
  1762  	)
  1763  }
  1764  
  1765  func (c *Completer) DeclareArgs(line string, origLine string, index int) readline.CandidateList {
  1766  	return c.completeArgs(
  1767  		line,
  1768  		origLine,
  1769  		index,
  1770  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1771  			switch c.tokens[i].Token {
  1772  			case parser.SELECT:
  1773  				return nil, c.SelectArgs(line, origLine, index), true
  1774  			case parser.CURSOR:
  1775  				if i == c.lastIdx {
  1776  					return []string{"FOR"}, nil, true
  1777  				} else if i == c.lastIdx-1 && c.tokens[c.lastIdx].Token == parser.FOR {
  1778  					return []string{"SELECT"}, c.candidateList(c.statementList, false), true
  1779  				}
  1780  			case parser.VIEW:
  1781  				switch c.tokens[c.lastIdx].Token {
  1782  				case parser.AS:
  1783  					return []string{"SELECT"}, nil, true
  1784  				case parser.VIEW, ')':
  1785  					return []string{"AS"}, nil, true
  1786  				}
  1787  			case parser.AGGREGATE, parser.FUNCTION:
  1788  			case parser.VAR:
  1789  				switch c.tokens[c.lastIdx].Token {
  1790  				case parser.VARIABLE, ',':
  1791  				default:
  1792  					return nil, c.SearchValues(line, origLine, index), true
  1793  				}
  1794  			case parser.DECLARE:
  1795  				if i == c.lastIdx-1 && c.tokens[c.lastIdx].Token != parser.VARIABLE {
  1796  					obj := []string{
  1797  						"CURSOR",
  1798  						"VIEW",
  1799  						"FUNCTION",
  1800  						"AGGREGATE",
  1801  					}
  1802  					return obj, nil, true
  1803  				} else if i < c.lastIdx-1 && c.tokens[i+1].Token == parser.VARIABLE {
  1804  					switch c.tokens[c.lastIdx].Token {
  1805  					case parser.VARIABLE, ',':
  1806  					default:
  1807  						return nil, c.SearchValues(line, origLine, index), true
  1808  					}
  1809  				}
  1810  			default:
  1811  				return nil, nil, false
  1812  			}
  1813  
  1814  			if c.tokens[c.lastIdx].Token == parser.SUBSTITUTION_OP {
  1815  				return nil, c.SearchValues(line, origLine, index), true
  1816  			}
  1817  
  1818  			return nil, nil, true
  1819  		},
  1820  	)
  1821  }
  1822  
  1823  func (c *Completer) PrepareArgs(line string, origLine string, index int) readline.CandidateList {
  1824  	return c.completeArgs(
  1825  		line,
  1826  		origLine,
  1827  		index,
  1828  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1829  			switch c.tokens[i].Token {
  1830  			case parser.PREPARE:
  1831  				if i == c.lastIdx-1 {
  1832  					return []string{"FROM"}, nil, true
  1833  				}
  1834  			default:
  1835  				return nil, nil, false
  1836  			}
  1837  
  1838  			return nil, nil, true
  1839  		},
  1840  	)
  1841  }
  1842  
  1843  func (c *Completer) FetchArgs(line string, origLine string, index int) readline.CandidateList {
  1844  	positions := []string{
  1845  		"NEXT",
  1846  		"PRIOR",
  1847  		"FIRST",
  1848  		"LAST",
  1849  		"ABSOLUTE",
  1850  		"RELATIVE",
  1851  	}
  1852  
  1853  	return c.completeArgs(
  1854  		line,
  1855  		origLine,
  1856  		index,
  1857  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1858  			switch c.tokens[i].Token {
  1859  			case parser.INTO:
  1860  				return nil, c.SearchValues(line, origLine, index), true
  1861  			case parser.NEXT, parser.PRIOR, parser.FIRST, parser.LAST:
  1862  				switch i {
  1863  				case c.lastIdx:
  1864  					return c.cursorList, nil, true
  1865  				case c.lastIdx - 1:
  1866  					return []string{"INTO"}, nil, true
  1867  				}
  1868  				return nil, nil, true
  1869  			case parser.ABSOLUTE, parser.RELATIVE:
  1870  				switch i {
  1871  				case c.lastIdx:
  1872  					return nil, c.SearchValuesWithSpace(line, origLine, index), true
  1873  				default:
  1874  					if c.tokens[c.lastIdx].Token == parser.IDENTIFIER {
  1875  						return []string{"INTO"}, nil, true
  1876  					} else {
  1877  						return c.cursorList, nil, true
  1878  					}
  1879  				}
  1880  			case parser.FETCH:
  1881  				switch i {
  1882  				case c.lastIdx:
  1883  					return c.cursorList, c.candidateList(positions, true), true
  1884  				case c.lastIdx - 1:
  1885  					return []string{"INTO"}, nil, true
  1886  				}
  1887  				return nil, nil, true
  1888  			}
  1889  			return nil, nil, false
  1890  		},
  1891  	)
  1892  }
  1893  
  1894  func (c *Completer) SetArgs(line string, origLine string, index int) readline.CandidateList {
  1895  	return c.completeArgs(
  1896  		line,
  1897  		origLine,
  1898  		index,
  1899  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1900  			switch c.tokens[i].Token {
  1901  			case parser.TO:
  1902  				if i == c.lastIdx && c.tokens[c.lastIdx-1].Token == parser.FLAG {
  1903  					switch strings.ToUpper(c.tokens[c.lastIdx-1].Literal) {
  1904  					case option.RepositoryFlag:
  1905  						return nil, c.SearchDirs(line, origLine, index), true
  1906  					case option.TimezoneFlag:
  1907  						return nil, c.candidateList([]string{"Local", "UTC"}, false), true
  1908  					case option.ImportFormatFlag:
  1909  						return nil, c.candidateList(c.importFormatList(), false), true
  1910  					case option.DelimiterFlag, option.ExportDelimiterFlag:
  1911  						return nil, c.candidateList(delimiterCandidates, false), true
  1912  					case option.DelimiterPositionsFlag, option.ExportDelimiterPositionsFlag:
  1913  						return nil, c.candidateList(delimiterPositionsCandidates, false), true
  1914  					case option.EncodingFlag:
  1915  						return nil, c.candidateList(c.encodingList(), false), true
  1916  					case option.ExportEncodingFlag:
  1917  						return nil, c.candidateList(exportEncodingsCandidates, false), true
  1918  					case option.AnsiQuotesFlag, option.StrictEqualFlag, option.AllowUnevenFieldsFlag,
  1919  						option.NoHeaderFlag, option.WithoutNullFlag,
  1920  						option.WithoutHeaderFlag, option.EncloseAllFlag, option.PrettyPrintFlag,
  1921  						option.ScientificNotationFlag,
  1922  						option.StripEndingLineBreakFlag, option.EastAsianEncodingFlag,
  1923  						option.CountDiacriticalSignFlag, option.CountFormatCodeFlag,
  1924  						option.ColorFlag, option.QuietFlag, option.StatsFlag:
  1925  						return nil, c.candidateList([]string{ternary.TRUE.String(), ternary.FALSE.String()}, false), true
  1926  					case option.FormatFlag:
  1927  						return nil, c.candidateList(c.tableFormatList(), false), true
  1928  					case option.LineBreakFlag:
  1929  						return nil, c.candidateList(c.lineBreakList(), false), true
  1930  					case option.JsonEscapeFlag:
  1931  						return nil, c.candidateList(c.jsonEscapeTypeList(), false), true
  1932  					}
  1933  				}
  1934  				return nil, c.SearchValues(line, origLine, index), true
  1935  			case parser.SET:
  1936  				switch i {
  1937  				case c.lastIdx:
  1938  					return nil, append(c.candidateList(c.flagList, true), c.candidateList(c.environmentVariableList(line), true)...), true
  1939  				case c.lastIdx - 1:
  1940  					return []string{"TO"}, nil, true
  1941  				}
  1942  				return nil, nil, true
  1943  			}
  1944  			return nil, nil, false
  1945  		},
  1946  	)
  1947  }
  1948  
  1949  func (c *Completer) UsingArgs(line string, origLine string, index int) readline.CandidateList {
  1950  	return c.completeArgs(
  1951  		line,
  1952  		origLine,
  1953  		index,
  1954  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1955  			switch c.tokens[i].Token {
  1956  			case parser.USING:
  1957  				if c.tokens[c.lastIdx-1].Token == parser.USING || c.tokens[c.lastIdx-1].Token == ',' {
  1958  					keywords = []string{"AS"}
  1959  				}
  1960  				return keywords, c.SearchValues(line, origLine, index), true
  1961  			case parser.EXECUTE, parser.PRINTF, parser.OPEN:
  1962  				if i == c.lastIdx {
  1963  					switch c.tokens[i].Token {
  1964  					case parser.EXECUTE:
  1965  						keywords = c.statementList
  1966  					case parser.OPEN:
  1967  						keywords = c.cursorList
  1968  					}
  1969  				} else {
  1970  					keywords = append(keywords, "USING")
  1971  				}
  1972  				return keywords, c.SearchValues(line, origLine, index), true
  1973  			}
  1974  			return nil, nil, false
  1975  		},
  1976  	)
  1977  }
  1978  
  1979  func (c *Completer) AddFlagArgs(line string, origLine string, index int) readline.CandidateList {
  1980  	return c.completeArgs(
  1981  		line,
  1982  		origLine,
  1983  		index,
  1984  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  1985  			switch c.tokens[i].Token {
  1986  			case parser.TO:
  1987  				return nil, c.candidateList([]string{option.FlagSymbol(option.DatetimeFormatFlag)}, false), true
  1988  			case parser.ADD:
  1989  				if i < c.lastIdx {
  1990  					keywords = append(keywords, "TO")
  1991  				}
  1992  				return keywords, c.SearchValues(line, origLine, index), true
  1993  			}
  1994  			return nil, nil, false
  1995  		},
  1996  	)
  1997  }
  1998  
  1999  func (c *Completer) RemoveFlagArgs(line string, origLine string, index int) readline.CandidateList {
  2000  	return c.completeArgs(
  2001  		line,
  2002  		origLine,
  2003  		index,
  2004  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  2005  			switch c.tokens[i].Token {
  2006  			case parser.FROM:
  2007  				return nil, c.candidateList([]string{option.FlagSymbol(option.DatetimeFormatFlag)}, false), true
  2008  			case parser.REMOVE:
  2009  				if i < c.lastIdx {
  2010  					keywords = append(keywords, "FROM")
  2011  				}
  2012  				return keywords, c.SearchValues(line, origLine, index), true
  2013  			}
  2014  			return nil, nil, false
  2015  		},
  2016  	)
  2017  
  2018  }
  2019  
  2020  func (c *Completer) DisposeArgs(line string, origLine string, index int) readline.CandidateList {
  2021  	return c.completeArgs(
  2022  		line,
  2023  		origLine,
  2024  		index,
  2025  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  2026  			switch c.tokens[i].Token {
  2027  			case parser.CURSOR:
  2028  				switch i {
  2029  				case c.lastIdx:
  2030  					return nil, c.candidateList(c.cursorList, false), true
  2031  				}
  2032  			case parser.FUNCTION:
  2033  				switch i {
  2034  				case c.lastIdx:
  2035  					return nil, c.candidateList(c.userFuncList, false), true
  2036  				}
  2037  			case parser.VIEW:
  2038  				switch i {
  2039  				case c.lastIdx:
  2040  					return nil, c.candidateList(c.viewList, false), true
  2041  				}
  2042  			case parser.PREPARE:
  2043  				switch i {
  2044  				case c.lastIdx:
  2045  					return nil, c.candidateList(c.statementList, false), true
  2046  				}
  2047  			case parser.DISPOSE:
  2048  				switch i {
  2049  				case c.lastIdx:
  2050  					var items []string
  2051  					if 0 < len(c.cursorList) {
  2052  						items = append(items, "CURSOR")
  2053  					}
  2054  					if 0 < len(c.userFuncList) {
  2055  						items = append(items, "FUNCTION")
  2056  					}
  2057  					if 0 < len(c.viewList) {
  2058  						items = append(items, "VIEW")
  2059  					}
  2060  					if 0 < len(c.statementList) {
  2061  						items = append(items, "PREPARE")
  2062  					}
  2063  					sort.Strings(items)
  2064  					list := append(c.candidateList(items, true), c.candidateList(c.varList, false)...)
  2065  					return nil, list, true
  2066  				}
  2067  			default:
  2068  				return nil, nil, false
  2069  			}
  2070  			return nil, nil, true
  2071  		},
  2072  	)
  2073  }
  2074  
  2075  func (c *Completer) ShowArgs(line string, origLine string, index int) readline.CandidateList {
  2076  	var showChild = func() readline.CandidateList {
  2077  		cands := c.candidateList(query.ShowObjectList, false)
  2078  		cands = append(cands, c.candidate("FIELDS", true))
  2079  		cands.Sort()
  2080  		cands = append(cands, c.candidateList(c.flagList, false)...)
  2081  		return cands
  2082  	}
  2083  
  2084  	return c.completeArgs(
  2085  		line,
  2086  		origLine,
  2087  		index,
  2088  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  2089  			switch c.tokens[i].Token {
  2090  			case parser.FROM:
  2091  				switch i {
  2092  				case c.lastIdx:
  2093  					return nil, c.allTableCandidatesForUpdate(line, origLine, index), true
  2094  				}
  2095  			case parser.SHOW:
  2096  				switch i {
  2097  				case c.lastIdx:
  2098  					return nil, showChild(), true
  2099  				case c.lastIdx - 1:
  2100  					if c.tokens[c.lastIdx].Token == parser.IDENTIFIER && strings.ToUpper(c.tokens[c.lastIdx].Literal) == "FIELDS" {
  2101  						return []string{"FROM"}, nil, true
  2102  					}
  2103  				}
  2104  			default:
  2105  				return nil, nil, false
  2106  			}
  2107  			return nil, nil, true
  2108  		},
  2109  	)
  2110  }
  2111  
  2112  func (c *Completer) SearchAllTablesWithSpace(line string, origLine string, index int) readline.CandidateList {
  2113  	cands := c.SearchAllTables(line, origLine, index)
  2114  	for i := range cands {
  2115  		cands[i].AppendSpace = true
  2116  	}
  2117  	return cands
  2118  }
  2119  
  2120  func (c *Completer) SearchAllTables(line string, _ string, _ int) readline.CandidateList {
  2121  	tableKeys := c.scope.Tx.CachedViews.SortedKeys()
  2122  	files := c.ListFiles(line, []string{option.CsvExt, option.TsvExt, option.JsonExt, option.JsonlExt, option.LtsvExt, option.TextExt}, c.scope.Tx.Flags.Repository)
  2123  
  2124  	defaultDir := c.scope.Tx.Flags.Repository
  2125  	if len(defaultDir) < 1 {
  2126  		defaultDir, _ = os.Getwd()
  2127  	}
  2128  
  2129  	items := make([]string, 0, len(tableKeys)+len(files)+len(c.viewList))
  2130  	tablePath := make(map[string]bool)
  2131  	for _, k := range tableKeys {
  2132  		if view, ok := c.scope.Tx.CachedViews.Load(strings.ToUpper(k)); ok {
  2133  			lpath := view.FileInfo.Path
  2134  			tablePath[lpath] = true
  2135  			if filepath.Dir(lpath) == defaultDir {
  2136  				items = append(items, filepath.Base(lpath))
  2137  			} else {
  2138  				items = append(items, lpath)
  2139  			}
  2140  		}
  2141  	}
  2142  
  2143  	items = append(items, c.viewList...)
  2144  	sort.Strings(items)
  2145  
  2146  	for _, f := range files {
  2147  		if f != "." && f != ".." {
  2148  			abs := f
  2149  			if !filepath.IsAbs(abs) {
  2150  				abs = filepath.Join(defaultDir, abs)
  2151  			}
  2152  			if _, ok := tablePath[abs]; ok {
  2153  				continue
  2154  			}
  2155  		}
  2156  		items = append(items, f)
  2157  	}
  2158  
  2159  	cands := make(readline.CandidateList, 0, len(items))
  2160  	for _, t := range items {
  2161  		cands = append(cands, readline.Candidate{Name: []rune(t), FormatAsIdentifier: true, AppendSpace: false})
  2162  	}
  2163  	return cands
  2164  }
  2165  
  2166  func (c *Completer) SearchExecutableFiles(line string, origLine string, index int) readline.CandidateList {
  2167  	cands := c.SearchValues(line, origLine, index)
  2168  	files := c.ListFiles(line, []string{option.SqlExt, option.CsvqProcExt}, "")
  2169  	return append(cands, c.identifierList(files, false)...)
  2170  }
  2171  
  2172  func (c *Completer) SearchDirs(line string, origLine string, index int) readline.CandidateList {
  2173  	cands := c.SearchValues(line, origLine, index)
  2174  	files := c.ListFiles(line, nil, "")
  2175  	return append(cands, c.identifierList(files, false)...)
  2176  }
  2177  
  2178  func (c *Completer) SearchValuesWithSpace(line string, origLine string, index int) readline.CandidateList {
  2179  	cands := c.SearchValues(line, origLine, index)
  2180  	for i := range cands {
  2181  		cands[i].AppendSpace = true
  2182  	}
  2183  	return cands
  2184  }
  2185  
  2186  func (c *Completer) SearchValues(line string, origLine string, index int) readline.CandidateList {
  2187  	if cands := c.EncloseQuotation(line, origLine, index); cands != nil {
  2188  		return cands
  2189  	}
  2190  
  2191  	searchWord := strings.ToUpper(line)
  2192  
  2193  	if 0 < len(c.cursorList) {
  2194  		if cands := c.CursorStatus(line, origLine, index); 0 < len(cands) {
  2195  			return cands
  2196  		}
  2197  	}
  2198  
  2199  	var cands readline.CandidateList
  2200  
  2201  	if c.isInAndAfterSelect {
  2202  		cands = append(cands, c.aggregateFunctionCandidateList(line)...)
  2203  		cands = append(cands, c.analyticFunctionCandidateList(line)...)
  2204  	}
  2205  
  2206  	if len(searchWord) < 1 {
  2207  		return cands
  2208  	}
  2209  
  2210  	var list []string
  2211  	if 1 < len(line) {
  2212  		list = append(list, c.runinfoList...)
  2213  		list = append(list, c.environmentVariableList(line)...)
  2214  	}
  2215  	list = append(list, c.varList...)
  2216  	list = append(list, c.funcList...)
  2217  	list = append(list,
  2218  		"TRUE",
  2219  		"FALSE",
  2220  		"UNKNOWN",
  2221  		"NULL",
  2222  	)
  2223  	list = append(list, c.constants...)
  2224  
  2225  	for _, s := range list {
  2226  		if strings.HasPrefix(strings.ToUpper(s), searchWord) {
  2227  			cands = append(cands, readline.Candidate{Name: []rune(s), FormatAsIdentifier: false, AppendSpace: false})
  2228  		}
  2229  	}
  2230  
  2231  	list = list[:0]
  2232  	list = append(list,
  2233  		"AND",
  2234  		"OR",
  2235  		"NOT",
  2236  		"IS",
  2237  		"BETWEEN",
  2238  		"LIKE",
  2239  		"IN",
  2240  		"ANY",
  2241  		"ALL",
  2242  		"EXISTS",
  2243  		"CASE",
  2244  	)
  2245  
  2246  	if 0 < len(c.cursorList) {
  2247  		list = append(list, "CURSOR")
  2248  	}
  2249  
  2250  	if 0 <= c.lastIdx && c.tokens[c.lastIdx].Token == '(' {
  2251  		list = append(list, "SELECT")
  2252  	}
  2253  
  2254  	for _, s := range list {
  2255  		if strings.HasPrefix(strings.ToUpper(s), searchWord) {
  2256  			cands = append(cands, readline.Candidate{Name: []rune(s), FormatAsIdentifier: false, AppendSpace: true})
  2257  		}
  2258  	}
  2259  
  2260  	if caseCands := c.CaseExpression(line, origLine, index); 0 < len(caseCands) {
  2261  		cands = append(cands, caseCands...)
  2262  	}
  2263  
  2264  	return cands
  2265  }
  2266  
  2267  func (c *Completer) CursorStatus(line string, origLine string, index int) readline.CandidateList {
  2268  	return c.completeArgs(
  2269  		line,
  2270  		origLine,
  2271  		index,
  2272  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  2273  			switch c.tokens[i].Token {
  2274  			case parser.IN:
  2275  				switch i {
  2276  				case c.lastIdx:
  2277  					if (0 < c.lastIdx-3 &&
  2278  						c.tokens[c.lastIdx-3].Token == parser.CURSOR &&
  2279  						c.tokens[c.lastIdx-1].Token == parser.IS) ||
  2280  						0 < c.lastIdx-4 &&
  2281  							c.tokens[c.lastIdx-4].Token == parser.CURSOR &&
  2282  							c.tokens[c.lastIdx-2].Token == parser.IS &&
  2283  							c.tokens[c.lastIdx-1].Token == parser.NOT {
  2284  						return nil, c.candidateList([]string{"RANGE"}, false), true
  2285  					}
  2286  				}
  2287  			case parser.NOT:
  2288  				switch i {
  2289  				case c.lastIdx:
  2290  					if 0 < c.lastIdx-3 &&
  2291  						c.tokens[c.lastIdx-3].Token == parser.CURSOR &&
  2292  						c.tokens[c.lastIdx-1].Token == parser.IS {
  2293  						return nil, c.candidateList([]string{
  2294  							"IN RANGE",
  2295  							"OPEN",
  2296  						}, false), true
  2297  					}
  2298  				}
  2299  			case parser.IS:
  2300  				switch i {
  2301  				case c.lastIdx:
  2302  					if 0 < c.lastIdx-2 && c.tokens[c.lastIdx-2].Token == parser.CURSOR {
  2303  						return []string{"NOT"}, c.candidateList([]string{
  2304  							"IN RANGE",
  2305  							"OPEN",
  2306  						}, false), true
  2307  					}
  2308  				}
  2309  			case parser.CURSOR:
  2310  				switch i {
  2311  				case c.lastIdx:
  2312  					return c.cursorList, nil, true
  2313  				case c.lastIdx - 1:
  2314  					return []string{"IS"}, c.candidateList([]string{"COUNT"}, false), true
  2315  				}
  2316  			case parser.IDENTIFIER, parser.COUNT, parser.OPEN, parser.RANGE:
  2317  				return nil, nil, false
  2318  			}
  2319  			return nil, nil, true
  2320  		},
  2321  	)
  2322  }
  2323  
  2324  func (c *Completer) caseExpressionIsNotEnclosed() bool {
  2325  	if 0 < len(c.tokens) && c.tokens[0].Token == parser.CASE {
  2326  		return false
  2327  	}
  2328  
  2329  	var blockLevel = 0
  2330  	for i := 0; i < len(c.tokens); i++ {
  2331  		switch c.tokens[i].Token {
  2332  		case parser.CASE:
  2333  			blockLevel++
  2334  		case parser.END:
  2335  			blockLevel--
  2336  		}
  2337  	}
  2338  	return 0 < blockLevel
  2339  }
  2340  
  2341  func (c *Completer) CaseExpression(line string, origLine string, index int) readline.CandidateList {
  2342  	caseExperEnclosed := true
  2343  
  2344  	return c.completeArgs(
  2345  		line,
  2346  		origLine,
  2347  		index,
  2348  		func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool) {
  2349  			if caseExperEnclosed {
  2350  				if caseExperEnclosed = !c.caseExpressionIsNotEnclosed(); caseExperEnclosed {
  2351  					return nil, nil, true
  2352  				}
  2353  			}
  2354  
  2355  			switch c.tokens[i].Token {
  2356  			case parser.ELSE:
  2357  				if i < c.lastIdx {
  2358  					return nil, c.filteredCandidateList(line, []string{"END"}, false), true
  2359  				}
  2360  				return nil, nil, true
  2361  			case parser.THEN:
  2362  				if i < c.lastIdx {
  2363  					return []string{"WHEN", "ELSE"}, c.filteredCandidateList(line, []string{"END"}, false), true
  2364  				}
  2365  				return nil, nil, true
  2366  			case parser.WHEN:
  2367  				if i < c.lastIdx {
  2368  					return []string{"THEN"}, nil, true
  2369  				}
  2370  				return nil, nil, true
  2371  			case parser.CASE:
  2372  				return []string{"WHEN"}, nil, true
  2373  			}
  2374  			return nil, nil, false
  2375  		},
  2376  	)
  2377  }
  2378  
  2379  func (c *Completer) EncloseQuotation(line string, origLine string, _ int) readline.CandidateList {
  2380  	runes := []rune(line)
  2381  	if 0 < len(runes) && readline.IsQuotationMark(runes[0]) && !readline.LiteralIsEnclosed(runes[0], []rune(origLine)) {
  2382  		return c.candidateList([]string{string(append([]rune(line), runes[0]))}, false)
  2383  	}
  2384  
  2385  	return nil
  2386  }
  2387  
  2388  func (c *Completer) ListFiles(path string, includeExt []string, repository string) []string {
  2389  	list := make([]string, 0, 10)
  2390  
  2391  	if 0 < len(path) && (path[0] == '"' || path[0] == '\'' || path[0] == '`') {
  2392  		path = path[1:]
  2393  	}
  2394  	searchWord := strings.ToUpper(path)
  2395  
  2396  	var defaultDir string
  2397  	if len(path) < 1 || (!filepath.IsAbs(path) && path != "." && path != ".." && filepath.Base(path) == path) {
  2398  		if 0 < len(repository) {
  2399  			defaultDir = repository
  2400  		} else {
  2401  			defaultDir, _ = os.Getwd()
  2402  		}
  2403  		path = defaultDir
  2404  
  2405  		for _, v := range []string{".", ".."} {
  2406  			if len(searchWord) < 1 || strings.HasPrefix(strings.ToUpper(v), searchWord) {
  2407  				list = append(list, v)
  2408  			}
  2409  		}
  2410  	}
  2411  
  2412  	if _, err := os.Stat(path); err != nil {
  2413  		path = filepath.Dir(path)
  2414  	}
  2415  
  2416  	if files, err := os.ReadDir(path); err == nil {
  2417  
  2418  		for _, f := range files {
  2419  			if f.Name()[0] == '.' {
  2420  				continue
  2421  			}
  2422  
  2423  			if !f.IsDir() && (len(includeExt) < 1 || !query.InStrSliceWithCaseInsensitive(filepath.Ext(f.Name()), includeExt)) {
  2424  				continue
  2425  			}
  2426  
  2427  			fpath := f.Name()
  2428  			if len(defaultDir) < 1 {
  2429  				if path == "." || path == "."+string(os.PathSeparator) {
  2430  					fpath = "." + string(os.PathSeparator) + fpath
  2431  				} else {
  2432  					fpath = filepath.Join(path, fpath)
  2433  				}
  2434  			}
  2435  			if f.IsDir() {
  2436  				fpath = fpath + string(os.PathSeparator)
  2437  			}
  2438  			if len(searchWord) < 1 || strings.HasPrefix(strings.ToUpper(fpath), searchWord) {
  2439  				list = append(list, fpath)
  2440  			}
  2441  		}
  2442  	}
  2443  
  2444  	return list
  2445  }
  2446  
  2447  func (c *Completer) AllColumnList() []string {
  2448  	m := make(map[string]bool)
  2449  	c.scope.Blocks[0].TemporaryTables.Range(func(key, value interface{}) bool {
  2450  		col := c.columnList(value.(*query.View))
  2451  		for _, s := range col {
  2452  			if _, ok := m[s]; !ok {
  2453  				m[s] = true
  2454  			}
  2455  		}
  2456  		return true
  2457  	})
  2458  
  2459  	c.scope.Tx.CachedViews.Range(func(key, value interface{}) bool {
  2460  		col := c.columnList(value.(*query.View))
  2461  		for _, s := range col {
  2462  			if _, ok := m[s]; !ok {
  2463  				m[s] = true
  2464  			}
  2465  		}
  2466  		return true
  2467  	})
  2468  
  2469  	list := make([]string, 0, len(m))
  2470  	for k := range m {
  2471  		list = append(list, k)
  2472  	}
  2473  	sort.Strings(list)
  2474  	return list
  2475  }
  2476  
  2477  func (c *Completer) ColumnList(tableName string, repository string) []string {
  2478  	if list, ok := c.tableColumns[tableName]; ok {
  2479  		return list
  2480  	}
  2481  
  2482  	if view, ok := c.scope.Blocks[0].TemporaryTables.Load(strings.ToUpper(tableName)); ok {
  2483  		list := c.columnList(view)
  2484  		c.tableColumns[tableName] = list
  2485  		return list
  2486  	}
  2487  
  2488  	if fpath, err := query.CreateFilePath(parser.Identifier{Literal: tableName}, repository); err == nil {
  2489  		if view, ok := c.scope.Tx.CachedViews.Load(strings.ToUpper(fpath)); ok {
  2490  			list := c.columnList(view)
  2491  			c.tableColumns[tableName] = list
  2492  			return list
  2493  		}
  2494  	}
  2495  	if fpath, err := query.SearchFilePathFromAllTypes(parser.Identifier{Literal: tableName}, repository); err == nil {
  2496  		if view, ok := c.scope.Tx.CachedViews.Load(strings.ToUpper(fpath)); ok {
  2497  			list := c.columnList(view)
  2498  			c.tableColumns[tableName] = list
  2499  			return list
  2500  		}
  2501  	}
  2502  
  2503  	return nil
  2504  }
  2505  
  2506  func (*Completer) columnList(view *query.View) []string {
  2507  	var list []string
  2508  	for _, h := range view.Header {
  2509  		list = append(list, h.Column)
  2510  	}
  2511  	return list
  2512  }
  2513  
  2514  func (c *Completer) completeArgs(
  2515  	line string,
  2516  	origLine string,
  2517  	index int,
  2518  	fn func(i int) (keywords []string, customList readline.CandidateList, breakLoop bool),
  2519  ) readline.CandidateList {
  2520  	if cands := c.EncloseQuotation(line, origLine, index); cands != nil {
  2521  		return cands
  2522  	}
  2523  
  2524  	baseInterval := 1
  2525  	if 0 < len(line) {
  2526  		baseInterval++
  2527  	}
  2528  	if 0 < len(c.tokens) && 0 < len(line) {
  2529  		c.tokens[len(c.tokens)-1].Token = parser.IDENTIFIER
  2530  	}
  2531  
  2532  	var keywords []string
  2533  	var customList readline.CandidateList
  2534  	var breakLoop bool
  2535  
  2536  	for i := len(c.tokens) - 1; i >= 0; i-- {
  2537  		if keywords, customList, breakLoop = fn(i); breakLoop {
  2538  			break
  2539  		}
  2540  	}
  2541  
  2542  	cands := c.filteredCandidateList(line, keywords, true)
  2543  	cands.Sort()
  2544  	if 0 < len(customList) {
  2545  		cands = append(cands, customList...)
  2546  	}
  2547  	return cands
  2548  }
  2549  
  2550  func (c *Completer) UpdateTokens(line string, origLine string) {
  2551  	c.tokens = c.tokens[:0]
  2552  	s := new(parser.Scanner)
  2553  	s.Init(origLine, "", false, c.scope.Tx.Flags.AnsiQuotes)
  2554  	for {
  2555  		t, _ := s.Scan()
  2556  		if t.Token == parser.EOF {
  2557  			break
  2558  		}
  2559  		c.tokens = append(c.tokens, t)
  2560  	}
  2561  
  2562  	c.setCursorIsInAndAfterSelect()
  2563  
  2564  	if 0 < len(c.tokens) {
  2565  		c.tokens = c.tokens[c.searchStartIndex():]
  2566  	}
  2567  
  2568  	c.combineSubqueryTokens()
  2569  	c.combineTableObject()
  2570  	c.combineFunction()
  2571  	c.SetLastIndex(line)
  2572  }
  2573  
  2574  func (c *Completer) SetLastIndex(line string) {
  2575  	c.lastIdx = len(c.tokens) - 1
  2576  	if 0 < len(c.tokens) && 0 < len(line) {
  2577  		c.tokens[len(c.tokens)-1].Token = parser.IDENTIFIER
  2578  		c.lastIdx--
  2579  	}
  2580  }
  2581  
  2582  func (c *Completer) setCursorIsInAndAfterSelect() {
  2583  	c.isInAndAfterSelect = false
  2584  
  2585  	blockLevel := 0
  2586  
  2587  InAndAfterSelectLoop:
  2588  	for i := len(c.tokens) - 1; i >= 0; i-- {
  2589  		switch c.tokens[i].Token {
  2590  		case ';',
  2591  			parser.FROM, parser.WHERE, parser.GROUP, parser.HAVING, parser.LIMIT, parser.FETCH, parser.OFFSET,
  2592  			parser.INTO:
  2593  
  2594  			break InAndAfterSelectLoop
  2595  		case '(':
  2596  			blockLevel--
  2597  		case ')':
  2598  			blockLevel++
  2599  		case parser.SELECT:
  2600  			if blockLevel <= 0 {
  2601  				c.isInAndAfterSelect = true
  2602  				break InAndAfterSelectLoop
  2603  			}
  2604  		case parser.BY:
  2605  			if blockLevel <= 0 && 0 < i && c.tokens[i-1].Token == parser.ORDER {
  2606  				c.isInAndAfterSelect = true
  2607  				break InAndAfterSelectLoop
  2608  			}
  2609  		}
  2610  	}
  2611  }
  2612  
  2613  func (c *Completer) searchStartIndex() int {
  2614  	idx := 0
  2615  	blockLevel := 0
  2616  	isStatement := false
  2617  
  2618  StartIndexLoop:
  2619  	for i := len(c.tokens) - 1; i >= 0; i-- {
  2620  		switch c.tokens[i].Token {
  2621  		case ';':
  2622  			idx = i + 1
  2623  			isStatement = true
  2624  			break StartIndexLoop
  2625  		case '(':
  2626  			blockLevel--
  2627  			switch {
  2628  			case blockLevel < 0:
  2629  				switch {
  2630  				case i+1 < len(c.tokens) && c.tokens[i+1].Token == parser.SELECT:
  2631  					idx = i + 1
  2632  					break StartIndexLoop
  2633  				case 0 <= i-1 && (c.isTableObject(c.tokens[i-1]) || c.isFunction(c.tokens[i-1])):
  2634  					idx = i - 1
  2635  					break StartIndexLoop
  2636  				}
  2637  			}
  2638  		case ')':
  2639  			blockLevel++
  2640  		}
  2641  	}
  2642  
  2643  	if 0 < len(c.varList) &&
  2644  		(idx == 0 || isStatement) &&
  2645  		(idx < len(c.tokens) && (c.tokens[idx].Token == parser.SELECT || c.tokens[idx].Token == parser.WITH)) {
  2646  		c.selectIntoEnabled = true
  2647  	} else {
  2648  		c.selectIntoEnabled = false
  2649  	}
  2650  	return idx
  2651  }
  2652  
  2653  func (c *Completer) combineSubqueryTokens() {
  2654  	combined := make([]parser.Token, 0, cap(c.tokens))
  2655  	blockLevel := 0
  2656  	for i := 0; i < len(c.tokens); i++ {
  2657  		if 0 < blockLevel {
  2658  			switch c.tokens[i].Token {
  2659  			case '(':
  2660  				blockLevel++
  2661  			case ')':
  2662  				blockLevel--
  2663  				if blockLevel == 0 {
  2664  					combined = append(combined, parser.Token{Token: parser.IDENTIFIER, Literal: dummySubquery})
  2665  				}
  2666  			}
  2667  			continue
  2668  		}
  2669  
  2670  		if c.tokens[i].Token == '(' && i+1 < len(c.tokens) && c.tokens[i+1].Token == parser.SELECT {
  2671  			blockLevel++
  2672  			i++
  2673  		} else {
  2674  			combined = append(combined, c.tokens[i])
  2675  		}
  2676  
  2677  	}
  2678  	c.tokens = combined
  2679  }
  2680  
  2681  func (c *Completer) combineTableObject() {
  2682  	combined := make([]parser.Token, 0, cap(c.tokens))
  2683  	blockLevel := 0
  2684  	tableIdx := 0
  2685  	for i := 0; i < len(c.tokens); i++ {
  2686  		if 0 < blockLevel {
  2687  			switch c.tokens[i].Token {
  2688  			case '(':
  2689  				blockLevel++
  2690  			case ')':
  2691  				blockLevel--
  2692  				if blockLevel == 0 {
  2693  					lit := dummyTableObject
  2694  					if 0 < tableIdx {
  2695  						lit = c.tokens[tableIdx].Literal
  2696  					}
  2697  					combined = append(combined, parser.Token{Token: parser.IDENTIFIER, Literal: lit})
  2698  				}
  2699  			case ',':
  2700  				if tableIdx == 0 && blockLevel == 1 {
  2701  					tableIdx = i + 1
  2702  				}
  2703  			}
  2704  			continue
  2705  		}
  2706  
  2707  		if 1 < i && c.isTableObject(c.tokens[i]) && i+1 < len(c.tokens) && c.tokens[i+1].Token == '(' {
  2708  			blockLevel++
  2709  			i++
  2710  		} else {
  2711  			combined = append(combined, c.tokens[i])
  2712  		}
  2713  
  2714  	}
  2715  	c.tokens = combined
  2716  }
  2717  
  2718  func (c *Completer) combineFunction() {
  2719  	combined := make([]parser.Token, 0, cap(c.tokens))
  2720  	blockLevel := 0
  2721  	funcName := ""
  2722  	for i := 0; i < len(c.tokens); i++ {
  2723  		if 0 < blockLevel {
  2724  			switch c.tokens[i].Token {
  2725  			case '(':
  2726  				blockLevel++
  2727  			case ')':
  2728  				blockLevel--
  2729  				if blockLevel == 0 {
  2730  					if i+2 < len(c.tokens) && c.tokens[i+1].Token == parser.OVER && c.tokens[i+2].Token == '(' {
  2731  						blockLevel++
  2732  						i = i + 2
  2733  					} else if i+4 < len(c.tokens) && c.tokens[i+3].Token == parser.OVER && c.tokens[i+4].Token == '(' {
  2734  						blockLevel++
  2735  						i = i + 4
  2736  					} else {
  2737  						combined = append(combined, parser.Token{Token: parser.FUNCTION, Literal: funcName})
  2738  					}
  2739  				}
  2740  			}
  2741  			continue
  2742  		}
  2743  
  2744  		if 0 < i && c.isFunction(c.tokens[i]) && i+1 < len(c.tokens) && c.tokens[i+1].Token == '(' {
  2745  			funcName = c.tokens[i].Literal
  2746  			blockLevel++
  2747  			i++
  2748  		} else {
  2749  			combined = append(combined, c.tokens[i])
  2750  		}
  2751  
  2752  	}
  2753  	c.tokens = combined
  2754  }
  2755  
  2756  func (c *Completer) isTableObject(token parser.Token) bool {
  2757  	switch token.Token {
  2758  	case parser.CSV, parser.JSON, parser.JSONL, parser.FIXED, parser.LTSV, parser.JSON_TABLE:
  2759  		return true
  2760  	}
  2761  	return false
  2762  }
  2763  
  2764  func (c *Completer) isFunction(token parser.Token) bool {
  2765  	if token.Token == parser.IDENTIFIER {
  2766  		if _, ok := query.Functions[strings.ToUpper(token.Literal)]; ok {
  2767  			return true
  2768  		}
  2769  		return query.InStrSliceWithCaseInsensitive(token.Literal, c.userFuncList)
  2770  	}
  2771  
  2772  	return token.Token == parser.SUBSTRING ||
  2773  		token.Token == parser.JSON_OBJECT ||
  2774  		token.Token == parser.IF ||
  2775  		token.Token == parser.AGGREGATE_FUNCTION ||
  2776  		token.Token == parser.COUNT ||
  2777  		token.Token == parser.LIST_FUNCTION ||
  2778  		token.Token == parser.ANALYTIC_FUNCTION ||
  2779  		token.Token == parser.FUNCTION_NTH ||
  2780  		token.Token == parser.FUNCTION_WITH_INS
  2781  }
  2782  
  2783  func (c *Completer) BracketIsEnclosed() bool {
  2784  	var blockLevel = 0
  2785  	for i := 0; i < len(c.tokens); i++ {
  2786  		switch c.tokens[i].Token {
  2787  		case '(':
  2788  			blockLevel++
  2789  		case ')':
  2790  			blockLevel--
  2791  		}
  2792  	}
  2793  	return blockLevel < 1
  2794  }
  2795  
  2796  func (c *Completer) candidateList(list []string, appendSpace bool) readline.CandidateList {
  2797  	cands := make(readline.CandidateList, 0, len(list))
  2798  	for _, v := range list {
  2799  		cands = append(cands, c.candidate(v, appendSpace))
  2800  	}
  2801  	return cands
  2802  }
  2803  
  2804  func (c *Completer) identifierList(list []string, appendSpace bool) readline.CandidateList {
  2805  	cands := make(readline.CandidateList, 0, len(list))
  2806  	for _, v := range list {
  2807  		cands = append(cands, c.identifier(v, appendSpace))
  2808  	}
  2809  	return cands
  2810  }
  2811  
  2812  func (c *Completer) filteredCandidateList(line string, list []string, appendSpace bool) readline.CandidateList {
  2813  	searchWord := strings.ToUpper(line)
  2814  
  2815  	cands := make(readline.CandidateList, 0, len(list))
  2816  	for _, v := range list {
  2817  		if len(searchWord) < 1 || strings.HasPrefix(strings.ToUpper(v), searchWord) {
  2818  			cands = append(cands, c.candidate(v, appendSpace))
  2819  		}
  2820  	}
  2821  	return cands
  2822  }
  2823  
  2824  func (c *Completer) candidate(candidate string, appendSpace bool) readline.Candidate {
  2825  	return readline.Candidate{Name: []rune(candidate), FormatAsIdentifier: false, AppendSpace: appendSpace}
  2826  }
  2827  
  2828  func (c *Completer) identifier(candidate string, appendSpace bool) readline.Candidate {
  2829  	return readline.Candidate{Name: []rune(candidate), FormatAsIdentifier: true, AppendSpace: appendSpace}
  2830  }
  2831  
  2832  func (c *Completer) aggregateFunctionCandidateList(line string) readline.CandidateList {
  2833  	if len(line) < 1 {
  2834  		return nil
  2835  	}
  2836  	return c.filteredCandidateList(line, c.aggFuncList, false)
  2837  }
  2838  
  2839  func (c *Completer) analyticFunctionCandidateList(line string) readline.CandidateList {
  2840  	var cands readline.CandidateList
  2841  	if 0 <= c.lastIdx && c.tokens[c.lastIdx].Token == parser.FUNCTION {
  2842  		if query.InStrSliceWithCaseInsensitive(c.tokens[c.lastIdx].Literal, []string{
  2843  			"FIRST_VALUE",
  2844  			"LAST_VALUE",
  2845  			"NTH_VALUE",
  2846  			"LAG_VALUE",
  2847  			"LEAD_VALUE",
  2848  		}) {
  2849  			cands = append(cands, c.candidate("IGNORE NULLS", true))
  2850  		}
  2851  
  2852  		if query.InStrSliceWithCaseInsensitive(c.tokens[c.lastIdx].Literal, c.analyticFuncs) {
  2853  			cands = append(cands, c.candidate("OVER", true))
  2854  		}
  2855  	}
  2856  
  2857  	if 0 < len(line) {
  2858  		cands = append(cands, c.filteredCandidateList(line, c.analyticFuncList, false)...)
  2859  	}
  2860  	return cands
  2861  }
  2862  
  2863  func (c *Completer) environmentVariableList(line string) []string {
  2864  	if 2 < len(line) && strings.HasPrefix(line, option.EnvironmentVariableSign+"`") {
  2865  		return c.enclosedEnvList
  2866  	}
  2867  	return c.envList
  2868  }
  2869  
  2870  func (c *Completer) tableFormatList() []string {
  2871  	list := make([]string, 0, len(option.FormatLiteral))
  2872  	for _, v := range option.FormatLiteral {
  2873  		list = append(list, v)
  2874  	}
  2875  	sort.Strings(list)
  2876  	return list
  2877  }
  2878  
  2879  func (c *Completer) importFormatList() []string {
  2880  	list := make([]string, 0, len(option.ImportFormats))
  2881  	for _, v := range option.ImportFormats {
  2882  		list = append(list, option.FormatLiteral[v])
  2883  	}
  2884  	sort.Strings(list)
  2885  	return list
  2886  }
  2887  
  2888  func (c *Completer) encodingList() []string {
  2889  	list := make([]string, 0, len(text.EncodingLiteral))
  2890  	for _, v := range text.EncodingLiteral {
  2891  		list = append(list, v)
  2892  	}
  2893  	sort.Strings(list)
  2894  	return list
  2895  }
  2896  
  2897  func (c *Completer) lineBreakList() []string {
  2898  	list := make([]string, 0, len(text.LineBreakLiteral))
  2899  	for _, v := range text.LineBreakLiteral {
  2900  		list = append(list, v)
  2901  	}
  2902  	sort.Strings(list)
  2903  	return list
  2904  }
  2905  
  2906  func (c *Completer) jsonEscapeTypeList() []string {
  2907  	list := make([]string, 0, len(option.JsonEscapeTypeLiteral))
  2908  	for _, v := range option.JsonEscapeTypeLiteral {
  2909  		list = append(list, v)
  2910  	}
  2911  	sort.Strings(list)
  2912  	return list
  2913  }