Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions go/cmd/dolt/cli/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ type Queryist interface {
QueryWithBindings(ctx *sql.Context, query string, parsed sqlparser.Statement, bindings map[string]sqlparser.Expr, qFlags *sql.QueryFlags) (sql.Schema, sql.RowIter, *sql.QueryFlags, error)
}

// ShellServerQueryist is used to gather warnings in the sql-shell context when a server is running.
// We call an extra "show warnings" query, but want to avoid this in other cases, (i.e. dolt sql -q)
type ShellServerQueryist interface {
EnableGatherWarnings()
}

// This type is to store the content of a documented command, elsewhere we can transform this struct into
// other structs that are used to generate documentation at the command line and in markdown files.
type CommandDocumentationContent struct {
Expand Down
2 changes: 1 addition & 1 deletion go/cmd/dolt/commands/blame.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func (cmd BlameCmd) Exec(ctx context.Context, commandStr string, args []string,
return 1
}

err = engine.PrettyPrintResults(sqlCtx, engine.FormatTabular, schema, ri, false)
err = engine.PrettyPrintResults(sqlCtx, engine.FormatTabular, schema, ri, false, false)
if err != nil {
iohelp.WriteLine(cli.CliOut, err.Error())
return 1
Expand Down
2 changes: 1 addition & 1 deletion go/cmd/dolt/commands/cvcmds/verify_constraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func printViolationsForTable(ctx *sql.Context, dbName, tblName string, tbl *dolt

limitItr := &sqlLimitIter{itr: sqlItr, limit: 50}

err = engine.PrettyPrintResults(ctx, engine.FormatTabular, sqlSch, limitItr, false)
err = engine.PrettyPrintResults(ctx, engine.FormatTabular, sqlSch, limitItr, false, false)
if err != nil {
return errhand.BuildDError("Error outputting rows").AddCause(err).Build()
}
Expand Down
42 changes: 31 additions & 11 deletions go/cmd/dolt/commands/engine/sql_print.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"github.com/dolthub/go-mysql-server/sql"
"github.com/dolthub/go-mysql-server/sql/types"
"github.com/fatih/color"

"github.com/dolthub/dolt/go/cmd/dolt/cli"
"github.com/dolthub/dolt/go/libraries/doltcore/row"
Expand Down Expand Up @@ -55,16 +56,17 @@ const (
)

// PrettyPrintResults prints the result of a query in the format provided
func PrettyPrintResults(ctx *sql.Context, resultFormat PrintResultFormat, sqlSch sql.Schema, rowIter sql.RowIter, pageResults bool) (rerr error) {
return prettyPrintResultsWithSummary(ctx, resultFormat, sqlSch, rowIter, PrintNoSummary, pageResults)
func PrettyPrintResults(ctx *sql.Context, resultFormat PrintResultFormat, sqlSch sql.Schema, rowIter sql.RowIter, pageResults bool, showWarnings bool) (rerr error) {
return prettyPrintResultsWithSummary(ctx, resultFormat, sqlSch, rowIter, PrintNoSummary, pageResults, showWarnings)
}

// PrettyPrintResultsExtended prints the result of a query in the format provided, including row count and timing info
func PrettyPrintResultsExtended(ctx *sql.Context, resultFormat PrintResultFormat, sqlSch sql.Schema, rowIter sql.RowIter, pageResults bool) (rerr error) {
return prettyPrintResultsWithSummary(ctx, resultFormat, sqlSch, rowIter, PrintRowCountAndTiming, pageResults)
func PrettyPrintResultsExtended(ctx *sql.Context, resultFormat PrintResultFormat, sqlSch sql.Schema, rowIter sql.RowIter, pageResults bool, showWarnings bool) (rerr error) {
return prettyPrintResultsWithSummary(ctx, resultFormat, sqlSch, rowIter, PrintRowCountAndTiming, pageResults, showWarnings)
}

func prettyPrintResultsWithSummary(ctx *sql.Context, resultFormat PrintResultFormat, sqlSch sql.Schema, rowIter sql.RowIter, summary PrintSummaryBehavior, pageResults bool) (rerr error) {
func prettyPrintResultsWithSummary(ctx *sql.Context, resultFormat PrintResultFormat, sqlSch sql.Schema, rowIter sql.RowIter, summary PrintSummaryBehavior, pageResults bool, showWarnings bool) (rerr error) {

defer func() {
closeErr := rowIter.Close(ctx)
if rerr == nil && closeErr != nil {
Expand Down Expand Up @@ -139,7 +141,15 @@ func prettyPrintResultsWithSummary(ctx *sql.Context, resultFormat PrintResultFor
}

if summary == PrintRowCountAndTiming {
err = printResultSetSummary(numRows, start)
warnings := ""
if showWarnings {
warnings = "\n"
for _, warn := range ctx.Session.Warnings() {
warnings += color.YellowString(fmt.Sprintf("\nWarning (Code %d): %s", warn.Code, warn.Message))
}
}

err = printResultSetSummary(numRows, ctx.WarningCount(), warnings, start)
if err != nil {
return err
}
Expand All @@ -154,9 +164,19 @@ func prettyPrintResultsWithSummary(ctx *sql.Context, resultFormat PrintResultFor
}
}

func printResultSetSummary(numRows int, start time.Time) error {
func printResultSetSummary(numRows int, numWarnings uint16, warningsList string, start time.Time) error {

warning := ""
if numWarnings > 0 {
plural := ""
if numWarnings > 1 {
plural = "s"
}
warning = fmt.Sprintf(", %d warning%s", numWarnings, plural)
}

if numRows == 0 {
printEmptySetResult(start)
printEmptySetResult(start, warning)
return nil
}

Expand All @@ -166,7 +186,7 @@ func printResultSetSummary(numRows int, start time.Time) error {
}

secondsSinceStart := secondsSince(start, time.Now())
err := iohelp.WriteLine(cli.CliOut, fmt.Sprintf("%d %s in set (%.2f sec)", numRows, noun, secondsSinceStart))
err := iohelp.WriteLine(cli.CliOut, fmt.Sprintf("%d %s in set%s (%.2f sec) %s", numRows, noun, warning, secondsSinceStart, warningsList))
if err != nil {
return err
}
Expand Down Expand Up @@ -216,9 +236,9 @@ type nullWriter struct{}
func (n nullWriter) WriteSqlRow(ctx *sql.Context, r sql.Row) error { return nil }
func (n nullWriter) Close(ctx context.Context) error { return nil }

func printEmptySetResult(start time.Time) {
func printEmptySetResult(start time.Time, warning string) {
seconds := secondsSince(start, time.Now())
cli.Printf("Empty set (%.2f sec)\n", seconds)
cli.Printf("Empty set%s (%.2f sec)\n", warning, seconds)
}

func printOKResult(ctx *sql.Context, iter sql.RowIter, start time.Time) error {
Expand Down
2 changes: 1 addition & 1 deletion go/cmd/dolt/commands/schcmds/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func (cmd TagsCmd) Exec(ctx context.Context, commandStr string, args []string, d
}

sqlCtx := sql.NewContext(ctx)
err = engine.PrettyPrintResults(sqlCtx, outputFmt, headerSchema, sql.RowsToRowIter(rows...), false)
err = engine.PrettyPrintResults(sqlCtx, outputFmt, headerSchema, sql.RowsToRowIter(rows...), false, false)

return commands.HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
44 changes: 36 additions & 8 deletions go/cmd/dolt/commands/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ func execSingleQuery(
}

if rowIter != nil {
err = engine.PrettyPrintResults(sqlCtx, format, sqlSch, rowIter, false)
err = engine.PrettyPrintResults(sqlCtx, format, sqlSch, rowIter, false, false)
if err != nil {
return errhand.VerboseErrorFromError(err)
}
Expand Down Expand Up @@ -663,7 +663,7 @@ func execBatchMode(ctx *sql.Context, qryist cli.Queryist, input io.Reader, conti
fileReadProg.printNewLineIfNeeded()
}
}
err = engine.PrettyPrintResults(ctx, format, sqlSch, rowIter, false)
err = engine.PrettyPrintResults(ctx, format, sqlSch, rowIter, false, false)
if err != nil {
err = buildBatchSqlErr(scanner.state.statementStartLine, query, err)
if !continueOnErr {
Expand Down Expand Up @@ -753,6 +753,12 @@ func execShell(sqlCtx *sql.Context, qryist cli.Queryist, format engine.PrintResu

initialCtx := sqlCtx.Context

//We want to gather the warnings if a server is running, as the connection queryist does not automatically cache them
if c, ok := qryist.(cli.ShellServerQueryist); ok {
c.EnableGatherWarnings()
}

toggleWarnings := true
pagerEnabled := false
// Used for the \edit command.
lastSqlCmd := ""
Expand Down Expand Up @@ -796,13 +802,28 @@ func execShell(sqlCtx *sql.Context, qryist cli.Queryist, format engine.PrintResu
}

if cmdType == DoltCliCommand {
_, okOn := subCmd.(WarningOn)
_, okOff := subCmd.(WarningOff)

if _, ok := subCmd.(SlashPager); ok {
p, err := handlePagerCommand(query)
if err != nil {
shell.Println(color.RedString(err.Error()))
} else {
pagerEnabled = p
}
} else if okOn || okOff {
w, err := handleWarningCommand(query)
if err != nil {
shell.Println(color.RedString(err.Error()))
} else {
toggleWarnings = w
if toggleWarnings {
cli.Println("Show warnings enabled")
} else {
cli.Println("Show warnings disabled")
}
}
} else {
err := handleSlashCommand(sqlCtx, subCmd, query, cliCtx)
if err != nil {
Expand All @@ -823,9 +844,9 @@ func execShell(sqlCtx *sql.Context, qryist cli.Queryist, format engine.PrintResu
} else if rowIter != nil {
switch closureFormat {
case engine.FormatTabular, engine.FormatVertical:
err = engine.PrettyPrintResultsExtended(sqlCtx, closureFormat, sqlSch, rowIter, pagerEnabled)
err = engine.PrettyPrintResultsExtended(sqlCtx, closureFormat, sqlSch, rowIter, pagerEnabled, toggleWarnings)
default:
err = engine.PrettyPrintResults(sqlCtx, closureFormat, sqlSch, rowIter, pagerEnabled)
err = engine.PrettyPrintResults(sqlCtx, closureFormat, sqlSch, rowIter, pagerEnabled, toggleWarnings)
}

if err != nil {
Expand Down Expand Up @@ -951,8 +972,12 @@ func formattedPrompts(db, branch string, dirty bool) (string, string) {
// along the way by printing red error messages to the CLI. If there was an issue getting the db name, the ok return
// value will be false and the strings will be empty.
func getDBBranchFromSession(sqlCtx *sql.Context, qryist cli.Queryist) (db string, branch string, ok bool) {
sqlCtx.Session.LockWarnings()
defer sqlCtx.Session.UnlockWarnings()
_, _, _, err := qryist.Query(sqlCtx, "set lock_warnings = 1")
if err != nil {
cli.Println(color.RedString(err.Error()))
return "", "", false
}
defer qryist.Query(sqlCtx, "set lock_warnings = 0")

_, resp, _, err := qryist.Query(sqlCtx, "select database() as db, active_branch() as branch")
if err != nil {
Expand Down Expand Up @@ -993,8 +1018,11 @@ func getDBBranchFromSession(sqlCtx *sql.Context, qryist cli.Queryist) (db string
// isDirty returns true if the workspace is dirty, false otherwise. This function _assumes_ you are on a database
// with a branch. If you are not, you will get an error.
func isDirty(sqlCtx *sql.Context, qryist cli.Queryist) (bool, error) {
sqlCtx.Session.LockWarnings()
defer sqlCtx.Session.UnlockWarnings()
_, _, _, err := qryist.Query(sqlCtx, "set lock_warnings = 1")
if err != nil {
return false, err
}
defer qryist.Query(sqlCtx, "set lock_warnings = 0")

_, resp, _, err := qryist.Query(sqlCtx, "select count(table_name) > 0 as dirty from dolt_status")

Expand Down
79 changes: 75 additions & 4 deletions go/cmd/dolt/commands/sql_slash.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ var slashCmds = []cli.Command{
SlashHelp{},
SlashEdit{},
SlashPager{},
WarningOn{},
WarningOff{},
}

// parseSlashCmd parses a command line string into a slice of strings, splitting on spaces, but allowing spaces within
Expand Down Expand Up @@ -208,8 +210,12 @@ func (s SlashEdit) Exec(ctx context.Context, commandStr string, args []string, d
}

func (s SlashEdit) Docs() *cli.CommandDocumentation {
//TODO implement me
return &cli.CommandDocumentation{}
return &cli.CommandDocumentation{
ShortDesc: "Use $EDITOR to edit the last command.",
LongDesc: "Start a text editor to edit your last command. Command will be executed after you finish editing.",
Synopsis: []string{},
ArgParser: s.ArgParser(),
}
}

func (s SlashEdit) ArgParser() *argparser.ArgParser {
Expand All @@ -220,8 +226,12 @@ func (s SlashEdit) ArgParser() *argparser.ArgParser {
type SlashPager struct{}

func (s SlashPager) Docs() *cli.CommandDocumentation {
//TODO
return &cli.CommandDocumentation{}
return &cli.CommandDocumentation{
ShortDesc: "Enable or Disable the result pager",
LongDesc: "Returns results in pager form. Use pager [on|off].",
Synopsis: []string{},
ArgParser: s.ArgParser(),
}
}

func (s SlashPager) ArgParser() *argparser.ArgParser {
Expand Down Expand Up @@ -266,3 +276,64 @@ func handlePagerCommand(fullCmd string) (bool, error) {

return false, fmt.Errorf("Usage: \\pager [on|off]")
}

type WarningCmd struct{}

func (s WarningCmd) Docs() *cli.CommandDocumentation {
return &cli.CommandDocumentation{
ShortDesc: "Toggle display of generated warnings after sql command.",
LongDesc: "Displays a detailed list of the warnings generated after each sql command. Use \\W and \\w to enable and disable the setting, respectively.",
Synopsis: []string{},
ArgParser: s.ArgParser(),
}
}

func (s WarningCmd) ArgParser() *argparser.ArgParser {
return &argparser.ArgParser{}
}

// Exec should never be called on warning command; It only changes which information is displayed.
// handleWarningCommand should be used instead
func (s WarningCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv, cliCtx cli.CliContext) int {
panic("runtime error. Exec should never be called on warning display commands.")
}

type WarningOn struct {
WarningCmd
}

var _ cli.Command = WarningOn{}

func (s WarningOn) Name() string { return "W" }

func (s WarningOn) Description() string {
return "Show generated warnings after sql command"
}

type WarningOff struct {
WarningCmd
}

var _ cli.Command = WarningOff{}

func (s WarningOff) Name() string { return "w" }

func (s WarningOff) Description() string {
return "Hide generated warnings after sql command"
}

func handleWarningCommand(fullCmd string) (bool, error) {
tokens := strings.Split(fullCmd, " ")

if len(tokens) == 0 || (tokens[0] != "\\w" && tokens[0] != "\\W") {
return false, fmt.Errorf("runtime error: Expected \\w or \\W command.")
} else if len(tokens) > 1 {
return false, fmt.Errorf("Usage: \\w \\w to toggle warnings")
}

if tokens[0] == "\\W" {
return true, nil
} else {
return false, nil
}
}
Loading
Loading