// addHistory persists a line of input to the readline history // file. func addHistory(line string) { // readline.AddHistory will push command into memory and try to // persist to disk (if readline.SetHistoryPath was called). err can // be not nil only if it got a IO error while trying to persist. if err := readline.AddHistory(line); err != nil { log.Warningf("cannot save command-line history: %s", err) log.Info("command-line history will not be saved in this session") readline.SetHistoryPath("") } }
// runInteractive runs the SQL client interactively, presenting // a prompt to the user for each statement. func runInteractive(conn *sqlConn) (exitErr error) { fullPrompt, continuePrompt := preparePrompts(conn.url) if isatty.IsTerminal(os.Stdout.Fd()) { // We only enable history management when the terminal is actually // interactive. This saves on memory when e.g. piping a large SQL // script through the command-line client. userAcct, err := user.Current() if err != nil { if log.V(2) { log.Warningf("cannot retrieve user information: %s", err) log.Info("cannot load or save the command-line history") } } else { histFile := filepath.Join(userAcct.HomeDir, ".cockroachdb_history") readline.SetHistoryPath(histFile) } } fmt.Print(infoMessage) var stmt []string for { thisPrompt := fullPrompt if len(stmt) > 0 { thisPrompt = continuePrompt } l, err := readline.Line(thisPrompt) if err == readline.ErrInterrupt || err == io.EOF { break } else if err != nil { fmt.Fprintf(osStderr, "input error: %s\n", err) return err } tl := strings.TrimSpace(l) // Check if this is a request for help or a client-side command. // If so, process it directly and skip query processing below. status := handleInputLine(&stmt, tl) if status == cliNextLine { continue } else if status == cliExit { break } // We join the statements back together with newlines in case // there is a significant newline inside a string literal. However // we join with spaces for keeping history, because otherwise a // history recall will only pull one line from a multi-line // statement. fullStmt := strings.Join(stmt, "\n") // We save the history between each statement, This enables // reusing history in another SQL shell without closing the // current shell. // // AddHistory will push command into memory and try to persist // to disk (if readline.SetHistoryPath was called). // err can be not nil only if it got a IO error while // trying to persist. if err := readline.AddHistory(strings.Join(stmt, " ")); err != nil { log.Warningf("cannot save command-line history: %s", err) log.Info("command-line history will not be saved in this session") readline.SetHistoryPath("") } if exitErr = runPrettyQuery(conn, os.Stdout, makeQuery(fullStmt)); exitErr != nil { fmt.Fprintln(osStderr, exitErr) } // Clear the saved statement. stmt = stmt[:0] } return exitErr }