func runTerm(cmd *cobra.Command, args []string) { if len(args) != 0 { cmd.Usage() return } db := makeSQLClient() liner := liner.NewLiner() defer func() { _ = liner.Close() }() for { l, err := liner.Prompt("> ") if err != nil { if err != io.EOF { fmt.Fprintf(os.Stderr, "Input error: %s\n", err) } break } if len(l) == 0 { continue } liner.AppendHistory(l) if err := processOneLine(db, l); err != nil { fmt.Printf("Error: %s\n", err) } } }
func RunRepl(store *Secstore) { var sections []string var line string var err error liner := liner.NewLiner() defer liner.Close() liner.SetCompleter(completer) for { line, err = liner.Prompt("> ") if err != nil { break } liner.AppendHistory(line) sections = splitSections(line) if len(sections) == 0 { } else if strings.HasPrefix("quit", sections[0]) { break } else { err = EvalCommand(store, sections) if err != nil { fmt.Fprintln(os.Stderr, err) } } } fmt.Fprintln(os.Stderr, "Exiting...") }
func runTerm(cmd *cobra.Command, args []string) { if len(args) != 0 { mustUsage(cmd) return } db := makeSQLClient() liner := liner.NewLiner() defer func() { _ = liner.Close() }() fmt.Fprint(osStdout, infoMessage) // Default prompt is "hostname> " // continued statement prompt it: " -> " // TODO(marc): maybe switch to "user@hostname" and strip port if present. fullPrompt := context.Addr if len(fullPrompt) == 0 { fullPrompt = " " } continuePrompt := strings.Repeat(" ", len(fullPrompt)-1) + "-" fullPrompt += "> " continuePrompt += "> " // TODO(marc): allow passing statements on the command line, // or specifying a flag. This would make testing much simpler. // TODO(marc): detect if we're actually on a terminal. If not, // we may want to repeat the statements on stdout. // TODO(marc): add test. var stmt []string var l string var err error for { if len(stmt) == 0 { l, err = liner.Prompt(fullPrompt) } else { l, err = liner.Prompt(continuePrompt) } if err != nil { if err != io.EOF { fmt.Fprintf(osStderr, "Input error: %s\n", err) } break } stmt = append(stmt, l) // See if we have a semicolon at the end of the line (ignoring // trailing whitespace). if !strings.HasSuffix(strings.TrimSpace(l), ";") { // No semicolon: read some more. continue } // We always insert a newline when continuing statements. // However, it causes problems with lines in the middle of: // - qualified names (eg: database.<newline>table) // - quoted strings (eg: 'foo<newline>bar') // This also makes the history replay horrible. // mysql replaces newlines with spaces in the history, which works // because string concatenation with newlines can also be done with spaces. // postgres keeps the line intact in the history. fullStmt := strings.Join(stmt, "\n") liner.AppendHistory(fullStmt) if err := runPrettyQuery(db, fullStmt); err != nil { fmt.Fprintln(osStdout, err) } // Clear the saved statement. stmt = stmt[:0] } }
// runInteractive runs the SQL client interactively, presenting // a prompt to the user for each statement. func runInteractive(db *sql.DB, dbURL string) { liner := liner.NewLiner() defer func() { _ = liner.Close() }() fmt.Print(infoMessage) // Default prompt is part of the connection URL. eg: "marc@localhost>" // continued statement prompt is: " -> " fullPrompt := dbURL if parsedURL, err := url.Parse(dbURL); err == nil { // If parsing fails, we keep the entire URL. The Open call succeeded, and that // is the important part. fullPrompt = fmt.Sprintf("%s@%s", parsedURL.User, parsedURL.Host) } if len(fullPrompt) == 0 { fullPrompt = " " } continuePrompt := strings.Repeat(" ", len(fullPrompt)-1) + "-" fullPrompt += "> " continuePrompt += "> " // TODO(marc): allow passing statements on the command line, // or specifying a flag. This would make testing much simpler. // TODO(marc): detect if we're actually on a terminal. If not, // we may want to repeat the statements on stdout. // TODO(marc): add test. var stmt []string var l string var err error exitCode := 0 for { if len(stmt) == 0 { l, err = liner.Prompt(fullPrompt) } else { l, err = liner.Prompt(continuePrompt) } if err != nil { if err != io.EOF { fmt.Fprintf(osStderr, "Input error: %s\n", err) exitCode = 1 } break } stmt = append(stmt, l) // See if we have a semicolon at the end of the line (ignoring // trailing whitespace). if !strings.HasSuffix(strings.TrimSpace(l), ";") { // No semicolon: read some more. continue } // We always insert a newline when continuing statements. // However, it causes problems with lines in the middle of: // - qualified names (eg: database.<newline>table) // - quoted strings (eg: 'foo<newline>bar') // This also makes the history replay horrible. // mysql replaces newlines with spaces in the history, which works // because string concatenation with newlines can also be done with spaces. // postgres keeps the line intact in the history. fullStmt := strings.Join(stmt, "\n") liner.AppendHistory(fullStmt) exitCode = 0 if err := runPrettyQuery(db, os.Stdout, fullStmt); err != nil { fmt.Fprintln(osStderr, err) exitCode = 1 } // Clear the saved statement. stmt = stmt[:0] } if exitCode != 0 { os.Exit(exitCode) } }