Skip to content

Commit

Permalink
cli: adds new sql shell metacommands
Browse files Browse the repository at this point in the history
- adds support for `\l`, `\dt`, `\du`, and ‘\d <table>`
- tweak welcome message for consistency
- fix welcome message to show `\q` instead of `CTRL + D` since that doesn’t work on Windows, and isn’t the primary documented way to quit from the shell

Release note: added \d, \dt, \du, \l metacommands to cli shell
  • Loading branch information
kenliu-crl committed Jul 29, 2019
1 parent cfdaadc commit 8fa961c
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ start_server $argv
spawn $argv sql

start_test "Check that the client starts with the welcome message."
eexpect "# Welcome to the cockroach SQL interface."
eexpect "# Welcome to the CockroachDB SQL shell."
end_test

start_test "Check that the client reports the server version, and correctly detects the version is the same as the client."
Expand Down
73 changes: 48 additions & 25 deletions pkg/cli/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,36 @@ import (
)

const (
infoMessage = `# Welcome to the cockroach SQL interface.
welcomeMessage = `#
# Welcome to the CockroachDB SQL shell.
# All statements must be terminated by a semicolon.
# To exit: CTRL + D.
# To exit, type: \q.
#
`
)
helpMessageFmt = `You are using 'cockroach sql', CockroachDB's lightweight SQL client.
Type:
\? or "help" print this help.
\q, quit, exit exit the shell (Ctrl+C/Ctrl+D also supported)
\! CMD run an external command and print its results on standard output.
\| CMD run an external command and run its output as SQL statements.
\set [NAME] set a client-side flag or (without argument) print the current settings.
\unset NAME unset a flag.
\show during a multi-line statement or transaction, show the SQL entered so far.
\h [NAME] help on syntax of SQL commands.
\hf [NAME] help on SQL built-in functions.
\l list all databases in the CockroachDB cluster
\dt show the tables of the current schema in the current database
\du list the users for all databases
\d TABLE show details about columns in the specified table
More documentation about our SQL dialect and the CLI shell is available online:
%s
%s`

const defaultPromptPattern = "%n@%M/%/%x>"
defaultPromptPattern = "%n@%M/%/%x>"

// debugPromptPattern avoids substitution patterns that require a db roundtrip.
const debugPromptPattern = "%n@%M>"
// debugPromptPattern avoids substitution patterns that require a db roundtrip.
debugPromptPattern = "%n@%M>"
)

// sqlShellCmd opens a sql shell.
var sqlShellCmd = &cobra.Command{
Expand Down Expand Up @@ -187,21 +206,7 @@ const (

// printCliHelp prints a short inline help about the CLI.
func printCliHelp() {
fmt.Printf(`You are using 'cockroach sql', CockroachDB's lightweight SQL client.
Type:
\q, quit, exit exit the shell (Ctrl+C/Ctrl+D also supported)
\! CMD run an external command and print its results on standard output.
\| CMD run an external command and run its output as SQL statements.
\set [NAME] set a client-side flag or (without argument) print the current settings.
\unset NAME unset a flag.
\show during a multi-line statement or transaction, show the SQL entered so far.
\? or "help" print this help.
\h [NAME] help on syntax of SQL commands.
\hf [NAME] help on SQL built-in functions.
More documentation about our SQL dialect and the CLI shell is available online:
%s
%s`,
fmt.Printf(helpMessageFmt,
base.DocsURL("sql-statements.html"),
base.DocsURL("use-the-built-in-sql-client.html"),
)
Expand All @@ -214,8 +219,7 @@ func (c *cliState) hasEditor() bool {
return c.ins != noLineEditor
}

// addHistory persists a line of input to the readline history
// file.
// addHistory persists a line of input to the readline history file.
func (c *cliState) addHistory(line string) {
if !c.hasEditor() || len(line) == 0 {
return
Expand Down Expand Up @@ -1020,6 +1024,25 @@ func (c *cliState) doHandleCliCmd(loopState, nextState cliStateEnum) cliStateEnu
case `\hf`:
return c.handleFunctionHelp(cmd[1:], loopState, errState)

case `\l`:
c.concatLines = `SHOW DATABASES`
return cliRunStatement

case `\dt`:
c.concatLines = `SHOW TABLES`
return cliRunStatement

case `\du`:
c.concatLines = `SHOW USERS`
return cliRunStatement

case `\d`:
if len(cmd) == 2 {
c.concatLines = `SHOW COLUMNS FROM ` + cmd[1]
return cliRunStatement
}
return c.invalidSyntax(errState, `%s. Try \? for help.`, c.lastInputLine)

default:
if strings.HasPrefix(cmd[0], `\d`) {
// Unrecognized command for now, but we want to be helpful.
Expand Down Expand Up @@ -1408,8 +1431,8 @@ func runTerm(cmd *cobra.Command, args []string) error {
checkInteractive()

if cliCtx.isInteractive {
// The user only gets to see the info screen on interactive sessions.
fmt.Print(infoMessage)
// The user only gets to see the welcome message on interactive sessions.
fmt.Print(welcomeMessage)
}

conn, err := getPasswordAndMakeSQLClient("cockroach sql")
Expand Down
47 changes: 47 additions & 0 deletions pkg/cli/sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/security"
"github.com/cockroachdb/cockroach/pkg/sql/parser"
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
"github.com/stretchr/testify/assert"
)

// Example_sql_lex tests the usage of the lexer in the sql subcommand.
Expand Down Expand Up @@ -188,3 +189,49 @@ func TestIsEndOfStatement(t *testing.T) {
}
}
}

// Test handleCliCmd cases for metacommands that are aliases for sql statements
func TestHandleCliCmdSqlAliasMetacommands(t *testing.T) {
defer leaktest.AfterTest(t)()
metaCommandTestsTable := []struct {
commandString string
wantSQLStmt string
}{
{`\l`, `SHOW DATABASES`},
{`\dt`, `SHOW TABLES`},
{`\du`, `SHOW USERS`},
{`\d mytable`, `SHOW COLUMNS FROM mytable`},
}

var c cliState
for _, tt := range metaCommandTestsTable {
c = setupTestCliState()
c.lastInputLine = tt.commandString
gotState := c.doHandleCliCmd(cliStateEnum(0), cliStateEnum(1))

assert.Equal(t, cliRunStatement, gotState)
assert.Equal(t, tt.wantSQLStmt, c.concatLines)
}
}

func TestHandleCliCmdSlashDInvalidSyntax(t *testing.T) {
defer leaktest.AfterTest(t)()

metaCommandTestsTable := []string{`\d`, `\d goodarg badarg`, `\dz`}

var c cliState
for _, tt := range metaCommandTestsTable {
c = setupTestCliState()
c.lastInputLine = tt
gotState := c.doHandleCliCmd(cliStateEnum(0), cliStateEnum(1))

assert.Equal(t, cliStateEnum(0), gotState)
assert.Equal(t, errInvalidSyntax, c.exitErr)
}
}

func setupTestCliState() cliState {
c := cliState{}
c.ins = noLineEditor
return c
}

0 comments on commit 8fa961c

Please sign in to comment.