Skip to content

Commit

Permalink
cli: output the completion tag for results with no columns
Browse files Browse the repository at this point in the history
Fixes #3993.
  • Loading branch information
petermattis committed Feb 25, 2016
1 parent c0c963e commit 65e1ba6
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 52 deletions.
2 changes: 1 addition & 1 deletion GLOCKFILE
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ github.com/cockroachdb/c-lz4 c40aaae2fc50293eb8750b34632bc3efe813e23f
github.com/cockroachdb/c-protobuf 4feb192131ea08dfbd7253a00868ad69cbb61b81
github.com/cockroachdb/c-rocksdb c0124c907c74b579d9d3d48eb96471bef270bc25
github.com/cockroachdb/c-snappy 5c6d0932e0adaffce4bfca7bdf2ac37f79952ccf
github.com/cockroachdb/pq 77893094b774b29f293681e6ac0a9322fbf3ce25
github.com/cockroachdb/pq dd29f9a2c333350480bf658e7f99c4ffdc145830
github.com/cockroachdb/stress aa7690c22fd0abd6168ed0e6c361e4f4c5f7ab25
github.com/codahale/hdrhistogram e88be87d51429689cef99043a54150d733265cd7
github.com/coreos/etcd 410d32a9b14f6052a834a966a02950cde518d7ce
Expand Down
30 changes: 15 additions & 15 deletions cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ range_max_bytes: 67108864
// range_min_bytes: 8388608
// range_max_bytes: 67108864
//
// OK
// INSERT 1
// zone ls
// Object 100:
// replicas:
Expand All @@ -524,7 +524,7 @@ range_max_bytes: 67108864
// ttlseconds: 0
//
// zone rm 100
// OK
// DELETE 1
// zone ls
}

Expand All @@ -542,7 +542,7 @@ func Example_sql() {

// Output:
// sql -e create database t; create table t.f (x int, y int); insert into t.f values (42, 69)
// OK
// INSERT 1
// sql -e select 3 select * from t.f
// 1 row
// 3
Expand All @@ -551,11 +551,11 @@ func Example_sql() {
// x y
// 42 69
// sql -e begin select 3 commit
// OK
// BEGIN
// 1 row
// 3
// 3
// OK
// COMMIT
// sql -e select * from t.f
// 1 row
// x y
Expand Down Expand Up @@ -594,21 +594,21 @@ func Example_sql_escape() {

// Output:
// sql -e create database t; create table t.t (s string, d string);
// OK
// CREATE TABLE
// sql -e insert into t.t values (e'foo', 'printable ASCII')
// OK
// INSERT 1
// sql -e insert into t.t values (e'foo\x0a', 'non-printable ASCII')
// OK
// INSERT 1
// sql -e insert into t.t values ('κόσμε', 'printable UTF8')
// OK
// INSERT 1
// sql -e insert into t.t values (e'\xc3\xb1', 'printable UTF8 using escapes')
// OK
// INSERT 1
// sql -e insert into t.t values (e'\x01', 'non-printable UTF8 string')
// OK
// INSERT 1
// sql -e insert into t.t values (e'\xdc\x88\x38\x35', 'UTF8 string with RTL char')
// OK
// INSERT 1
// sql -e insert into t.t values (e'\xc3\x28', 'non-UTF8 string')
// OK
// INSERT 1
// sql -e select * from t.t
// 7 rows
// s d
Expand Down Expand Up @@ -640,15 +640,15 @@ func Example_user() {
// +----------+
// +----------+
// user set foo --password=bar
// OK
// INSERT 1
// user ls
// +----------+
// | username |
// +----------+
// | foo |
// +----------+
// user rm foo
// OK
// DELETE 1
// user ls
// +----------+
// | username |
Expand Down
4 changes: 2 additions & 2 deletions cli/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func runLsNodes(cmd *cobra.Command, args []string) error {
})
}

printQueryOutput(os.Stdout, lsNodesColumnHeaders, rows)
printQueryOutput(os.Stdout, lsNodesColumnHeaders, rows, "")
return nil
}

Expand Down Expand Up @@ -128,7 +128,7 @@ func runStatusNode(cmd *cobra.Command, args []string) error {
return util.Errorf("expected no arguments or a single node ID")
}

printQueryOutput(os.Stdout, nodesColumnHeaders, nodeStatusesToRows(nodeStatuses))
printQueryOutput(os.Stdout, nodesColumnHeaders, nodeStatusesToRows(nodeStatuses), "")
return nil
}

Expand Down
11 changes: 3 additions & 8 deletions cli/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func runStatements(conn *sqlConn, stmts []string) error {
for _, stmt := range stmts {
q := makeQuery(stmt)
for {
cols, allRows, err := runQuery(conn, q)
cols, allRows, tag, err := runQuery(conn, q)
if err != nil {
if err == pq.ErrNoMoreResults {
break
Expand All @@ -240,15 +240,10 @@ func runStatements(conn *sqlConn, stmts []string) error {

if len(cols) == 0 {
// No result selected, inform the user.
fmt.Fprintln(os.Stdout, "OK")
fmt.Fprintln(os.Stdout, tag)
} else {
// Some results selected, inform the user about how much data to expect.
noun := "rows"
if len(allRows) == 1 {
noun = "row"
}

fmt.Fprintf(os.Stdout, "%d %s\n", len(allRows), noun)
fmt.Fprintf(os.Stdout, "%d row%s\n", len(allRows), pluralize(int64(len(allRows))))

// Then print the results themselves.
fmt.Fprintln(os.Stdout, strings.Join(cols, "\t"))
Expand Down
77 changes: 56 additions & 21 deletions cli/sql_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (c *sqlConn) Query(query string, args []driver.Value) (*sqlRows, error) {
if err != nil {
return nil, err
}
return &sqlRows{Rows: rows, conn: c}, nil
return &sqlRows{rows: rows.(sqlRowsI), conn: c}, nil
}

func (c *sqlConn) Next() (*sqlRows, error) {
Expand All @@ -75,7 +75,7 @@ func (c *sqlConn) Next() (*sqlRows, error) {
if err != nil {
return nil, err
}
return &sqlRows{Rows: rows, conn: c}, nil
return &sqlRows{rows: rows.(sqlRowsI), conn: c}, nil
}

func (c *sqlConn) Close() {
Expand All @@ -88,21 +88,39 @@ func (c *sqlConn) Close() {
}
}

type sqlRows struct {
type sqlRowsI interface {
driver.Rows
Result() driver.Result
Tag() string
}

type sqlRows struct {
rows sqlRowsI
conn *sqlConn
}

func (r *sqlRows) Columns() []string {
return r.rows.Columns()
}

func (r *sqlRows) Result() driver.Result {
return r.rows.Result()
}

func (r *sqlRows) Tag() string {
return r.rows.Tag()
}

func (r *sqlRows) Close() error {
err := r.Rows.Close()
err := r.rows.Close()
if err == driver.ErrBadConn {
r.conn.Close()
}
return err
}

func (r *sqlRows) Next(values []driver.Value) error {
err := r.Rows.Next(values)
err := r.rows.Next(values)
if err == driver.ErrBadConn {
r.conn.Close()
}
Expand Down Expand Up @@ -154,7 +172,7 @@ func makeQuery(query string, parameters ...driver.Value) queryFunc {

// runQuery takes a 'query' with optional 'parameters'.
// It runs the sql query and returns a list of columns names and a list of rows.
func runQuery(conn *sqlConn, fn queryFunc) ([]string, [][]string, error) {
func runQuery(conn *sqlConn, fn queryFunc) ([]string, [][]string, string, error) {
return runQueryWithFormat(conn, nil, fn)
}

Expand All @@ -163,10 +181,10 @@ func runQuery(conn *sqlConn, fn queryFunc) ([]string, [][]string, error) {
// If 'format' is not nil, the values with column name
// found in the map are run through the corresponding callback.
func runQueryWithFormat(conn *sqlConn, format fmtMap, fn queryFunc) (
[]string, [][]string, error) {
[]string, [][]string, string, error) {
rows, err := fn(conn)
if err != nil {
return nil, nil, err
return nil, nil, "", err
}

defer func() { _ = rows.Close() }()
Expand All @@ -177,14 +195,14 @@ func runQueryWithFormat(conn *sqlConn, format fmtMap, fn queryFunc) (
// It runs the sql query and writes pretty output to 'w'.
func runPrettyQuery(conn *sqlConn, w io.Writer, fn queryFunc) error {
for {
cols, allRows, err := runQuery(conn, fn)
cols, allRows, result, err := runQuery(conn, fn)
if err != nil {
if err == pq.ErrNoMoreResults {
return nil
}
return err
}
printQueryOutput(w, cols, allRows)
printQueryOutput(w, cols, allRows, result)
fn = nextResult
}
}
Expand All @@ -197,23 +215,22 @@ func runPrettyQuery(conn *sqlConn, w io.Writer, fn queryFunc) error {
// It returns the header row followed by all data rows.
// If both the header row and list of rows are empty, it means no row
// information was returned (eg: statement was not a query).
func sqlRowsToStrings(rows *sqlRows, format fmtMap) ([]string, [][]string, error) {
func sqlRowsToStrings(rows *sqlRows, format fmtMap) ([]string, [][]string, string, error) {
cols := rows.Columns()

if len(cols) == 0 {
return nil, nil, nil
var allRows [][]string
var vals []driver.Value
if len(cols) > 0 {
vals = make([]driver.Value, len(cols))
}

vals := make([]driver.Value, len(cols))
allRows := [][]string{}

for {
err := rows.Next(vals)
if err == io.EOF {
break
}
if err != nil {
return nil, nil, err
return nil, nil, "", err
}
rowStrings := make([]string, len(cols))
for i, v := range vals {
Expand All @@ -226,15 +243,33 @@ func sqlRowsToStrings(rows *sqlRows, format fmtMap) ([]string, [][]string, error
allRows = append(allRows, rowStrings)
}

return cols, allRows, nil
result := rows.Result()
tag := rows.Tag()
switch tag {
case "":
tag = "OK"
case "DELETE", "INSERT", "UPDATE":
if n, err := result.RowsAffected(); err == nil {
tag = fmt.Sprintf("%s %d", tag, n)
}
}

return cols, allRows, tag, nil
}

func pluralize(n int64) string {
if n == 1 {
return ""
}
return "s"
}

// printQueryOutput takes a list of column names and a list of row contents
// writes a pretty table to 'w', or "OK" if empty.
func printQueryOutput(w io.Writer, cols []string, allRows [][]string) {
func printQueryOutput(w io.Writer, cols []string, allRows [][]string, tag string) {
if len(cols) == 0 {
// This operation did not return rows, just show success.
fmt.Fprintln(w, "OK")
// This operation did not return rows, just show the tag.
fmt.Fprintln(w, tag)
return
}

Expand Down
6 changes: 3 additions & 3 deletions cli/sql_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ func TestRunQuery(t *testing.T) {
}

expected := `
OK
SET
`
if a, e := b.String(), expected[1:]; a != e {
t.Fatalf("expected output:\n%s\ngot:\n%s", e, a)
}
b.Reset()

// Use system database for sample query/output as they are fairly fixed.
cols, rows, err := runQuery(conn, makeQuery(`SHOW COLUMNS FROM system.namespace`))
cols, rows, _, err := runQuery(conn, makeQuery(`SHOW COLUMNS FROM system.namespace`))
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -119,7 +119,7 @@ OK
return fmt.Sprintf("--> %s <--", val)
}

_, rows, err = runQueryWithFormat(conn, fmtMap{"name": newFormat},
_, rows, _, err = runQueryWithFormat(conn, fmtMap{"name": newFormat},
makeQuery(`SELECT * FROM system.namespace WHERE name=$1`, "descriptor"))
if err != nil {
t.Fatal(err)
Expand Down
4 changes: 2 additions & 2 deletions cli/zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func runGetZone(cmd *cobra.Command, args []string) {

conn := makeSQLClient()
defer conn.Close()
_, rows, err := runQueryWithFormat(conn, fmtMap{"config": formatZone},
_, rows, _, err := runQueryWithFormat(conn, fmtMap{"config": formatZone},
makeQuery(`SELECT * FROM system.zones WHERE id=$1`, id))
if err != nil {
log.Error(err)
Expand Down Expand Up @@ -117,7 +117,7 @@ func runLsZones(cmd *cobra.Command, args []string) {
}
conn := makeSQLClient()
defer conn.Close()
_, rows, err := runQueryWithFormat(conn, fmtMap{"config": formatZone},
_, rows, _, err := runQueryWithFormat(conn, fmtMap{"config": formatZone},
makeQuery(`SELECT * FROM system.zones`))
if err != nil {
log.Error(err)
Expand Down

0 comments on commit 65e1ba6

Please sign in to comment.