Repository: src-d/go-mysql-server (go)

Issue:
Show databases
Implement a command to show databases.

_Originally posted by @erizocosmico in https://github.com/src-d/gitbase/issues/361#issuecomment-427285397

Pull request description:
sql: implement SHOW DATABASES
Closes #412 

Patch:
diff --git a/sql/analyzer/assign_catalog.go b/sql/analyzer/assign_catalog.go
index 1df8174..9960dfe 100644
--- a/sql/analyzer/assign_catalog.go
+++ b/sql/analyzer/assign_catalog.go
@@ -29,6 +29,10 @@ func assignCatalog(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, error)
 		nc := *node
 		nc.Registry = a.Catalog.IndexRegistry
 		return &nc, nil
+	case *plan.ShowDatabases:
+		nc := *node
+		nc.Catalog = a.Catalog
+		return &nc, nil
 	case *plan.ShowProcessList:
 		nc := *node
 		nc.Database = a.CurrentDatabase
diff --git a/sql/parse/parse.go b/sql/parse/parse.go
index c14804a..b71bb2e 100644
--- a/sql/parse/parse.go
+++ b/sql/parse/parse.go
@@ -162,12 +162,15 @@ func convertSet(ctx *sql.Context, n *sqlparser.Set) (sql.Node, error) {
 }
 
 func convertShow(s *sqlparser.Show) (sql.Node, error) {
-	if s.Type != sqlparser.KeywordString(sqlparser.TABLES) {
+	switch s.Type {
+	case sqlparser.KeywordString(sqlparser.TABLES):
+		return plan.NewShowTables(&sql.UnresolvedDatabase{}), nil
+	case sqlparser.KeywordString(sqlparser.DATABASES):
+		return plan.NewShowDatabases(), nil
+	default:
 		unsupportedShow := fmt.Sprintf("SHOW %s", s.Type)
 		return nil, ErrUnsupportedFeature.New(unsupportedShow)
 	}
-
-	return plan.NewShowTables(&sql.UnresolvedDatabase{}), nil
 }
 
 func convertSelect(ctx *sql.Context, s *sqlparser.Select) (sql.Node, error) {
diff --git a/sql/plan/showdatabases.go b/sql/plan/showdatabases.go
new file mode 100644
index 0000000..a7a6efe
--- /dev/null
+++ b/sql/plan/showdatabases.go
@@ -0,0 +1,65 @@
+package plan
+
+import (
+	"sort"
+	"strings"
+
+	"gopkg.in/src-d/go-mysql-server.v0/sql"
+)
+
+// ShowDatabases is a node that shows the databases.
+type ShowDatabases struct {
+	Catalog *sql.Catalog
+}
+
+// NewShowDatabases creates a new show databases node.
+func NewShowDatabases() *ShowDatabases {
+	return new(ShowDatabases)
+}
+
+// Resolved implements the Resolvable interface.
+func (p *ShowDatabases) Resolved() bool {
+	return true
+}
+
+// Children implements the Node interface.
+func (*ShowDatabases) Children() []sql.Node {
+	return nil
+}
+
+// Schema implements the Node interface.
+func (*ShowDatabases) Schema() sql.Schema {
+	return sql.Schema{{
+		Name:     "database",
+		Type:     sql.Text,
+		Nullable: false,
+	}}
+}
+
+// RowIter implements the Node interface.
+func (p *ShowDatabases) RowIter(ctx *sql.Context) (sql.RowIter, error) {
+	var rows = make([]sql.Row, len(p.Catalog.Databases))
+	for i, db := range p.Catalog.Databases {
+		rows[i] = sql.Row{db.Name()}
+	}
+
+	sort.Slice(rows, func(i, j int) bool {
+		return strings.Compare(rows[i][0].(string), rows[j][0].(string)) < 0
+	})
+
+	return sql.RowsToRowIter(rows...), nil
+}
+
+// TransformUp implements the Transformable interface.
+func (p *ShowDatabases) TransformUp(f sql.TransformNodeFunc) (sql.Node, error) {
+	np := *p
+	return f(&np)
+}
+
+// TransformExpressionsUp implements the Transformable interface.
+func (p *ShowDatabases) TransformExpressionsUp(f sql.TransformExprFunc) (sql.Node, error) {
+	return p, nil
+}
+func (p ShowDatabases) String() string {
+	return "ShowDatabases"
+}


Test patch:
diff --git a/engine_test.go b/engine_test.go
index c86d5d9..f4189a4 100644
--- a/engine_test.go
+++ b/engine_test.go
@@ -308,6 +308,10 @@ var queries = []struct {
 		`/*!40101 SET NAMES utf8 */`,
 		[]sql.Row{},
 	},
+	{
+		`SHOW DATABASES`,
+		[]sql.Row{{"mydb"}},
+	},
 }
 
 func TestQueries(t *testing.T) {
diff --git a/sql/analyzer/assign_catalog_test.go b/sql/analyzer/assign_catalog_test.go
index d1cd2b4..913eabb 100644
--- a/sql/analyzer/assign_catalog_test.go
+++ b/sql/analyzer/assign_catalog_test.go
@@ -56,4 +56,10 @@ func TestAssignCatalog(t *testing.T) {
 	require.True(ok)
 	require.Equal(db.Name(), pl.Database)
 	require.Equal(c.ProcessList, pl.ProcessList)
+
+	node, err = f.Apply(sql.NewEmptyContext(), a, plan.NewShowDatabases())
+	require.NoError(err)
+	sd, ok := node.(*plan.ShowDatabases)
+	require.True(ok)
+	require.Equal(c, sd.Catalog)
 }
diff --git a/sql/parse/parse_test.go b/sql/parse/parse_test.go
index 89e4dab..e43cd4f 100644
--- a/sql/parse/parse_test.go
+++ b/sql/parse/parse_test.go
@@ -725,6 +725,7 @@ var fixtures = map[string]sql.Node{
 		},
 		plan.NewUnresolvedTable("foo"),
 	),
+	`SHOW DATABASES`: plan.NewShowDatabases(),
 }
 
 func TestParse(t *testing.T) {