This repository has been archived by the owner on Jan 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #435 from Zarkopafilis/show-create-table
sql: plan: Add SHOW CREATE TABLE [Fix #406]
- Loading branch information
Showing
7 changed files
with
341 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,57 @@ | ||
module gopkg.in/src-d/go-mysql-server.v0 | ||
|
||
require ( | ||
github.com/BurntSushi/toml v0.3.1 // indirect | ||
github.com/CAFxX/gcnotifier v0.0.0-20170518020117-39b0596a2da3 // indirect | ||
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895 // indirect | ||
github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f // indirect | ||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect | ||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect | ||
github.com/BurntSushi/toml v0.3.1 // indirect | ||
github.com/CAFxX/gcnotifier v0.0.0-20170518020117-39b0596a2da3 // indirect | ||
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895 // indirect | ||
github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f // indirect | ||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect | ||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect | ||
github.com/boltdb/bolt v1.3.1 | ||
github.com/cespare/xxhash v1.1.0 // indirect | ||
github.com/circonus-labs/circonus-gometrics v2.2.4+incompatible // indirect | ||
github.com/circonus-labs/circonusllhist v0.0.0-20180430145027-5eb751da55c6 // indirect | ||
github.com/go-ole/go-ole v1.2.1 // indirect | ||
github.com/circonus-labs/circonus-gometrics v2.2.4+incompatible // indirect | ||
github.com/circonus-labs/circonusllhist v0.0.0-20180430145027-5eb751da55c6 // indirect | ||
github.com/go-ole/go-ole v1.2.1 // indirect | ||
github.com/gogo/protobuf v1.1.1 // indirect | ||
github.com/google/go-cmp v0.2.0 // indirect | ||
github.com/gorilla/context v1.1.1 // indirect | ||
github.com/gorilla/handlers v1.4.0 // indirect | ||
github.com/gorilla/mux v1.6.2 // indirect | ||
github.com/hashicorp/consul v1.2.3 // indirect | ||
github.com/hashicorp/go-cleanhttp v0.5.0 // indirect | ||
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect | ||
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect | ||
github.com/hashicorp/go-multierror v1.0.0 // indirect | ||
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6 // indirect | ||
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 // indirect | ||
github.com/hashicorp/memberlist v0.1.0 // indirect | ||
github.com/hashicorp/serf v0.8.1 // indirect | ||
github.com/hashicorp/yamux v0.0.0-20180917205041-7221087c3d28 // indirect | ||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect | ||
github.com/miekg/dns v1.0.12 // indirect | ||
github.com/google/go-cmp v0.2.0 // indirect | ||
github.com/gorilla/context v1.1.1 // indirect | ||
github.com/gorilla/handlers v1.4.0 // indirect | ||
github.com/gorilla/mux v1.6.2 // indirect | ||
github.com/hashicorp/consul v1.2.3 // indirect | ||
github.com/hashicorp/go-cleanhttp v0.5.0 // indirect | ||
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect | ||
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect | ||
github.com/hashicorp/go-multierror v1.0.0 // indirect | ||
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6 // indirect | ||
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 // indirect | ||
github.com/hashicorp/memberlist v0.1.0 // indirect | ||
github.com/hashicorp/serf v0.8.1 // indirect | ||
github.com/hashicorp/yamux v0.0.0-20180917205041-7221087c3d28 // indirect | ||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect | ||
github.com/miekg/dns v1.0.12 // indirect | ||
github.com/mitchellh/hashstructure v1.0.0 | ||
github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 | ||
github.com/opentracing/opentracing-go v1.0.2 | ||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c // indirect | ||
github.com/pelletier/go-toml v1.2.0 // indirect | ||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c // indirect | ||
github.com/pelletier/go-toml v1.2.0 // indirect | ||
github.com/pilosa/pilosa v1.1.0 | ||
github.com/pkg/errors v0.8.0 // indirect | ||
github.com/prometheus/client_golang v0.8.0 // indirect | ||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect | ||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e // indirect | ||
github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 // indirect | ||
github.com/prometheus/client_golang v0.8.0 // indirect | ||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect | ||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e // indirect | ||
github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 // indirect | ||
github.com/satori/go.uuid v1.2.0 // indirect | ||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect | ||
github.com/shirou/gopsutil v2.17.12+incompatible // indirect | ||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect | ||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect | ||
github.com/shirou/gopsutil v2.17.12+incompatible // indirect | ||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect | ||
github.com/sirupsen/logrus v1.1.0 | ||
github.com/spf13/cast v1.2.0 | ||
github.com/stretchr/testify v1.2.2 | ||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect | ||
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3 // indirect | ||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect | ||
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3 // indirect | ||
google.golang.org/grpc v1.15.0 // indirect | ||
gopkg.in/src-d/go-errors.v1 v1.0.0 | ||
gopkg.in/src-d/go-vitess.v1 v1.1.0 | ||
gopkg.in/vmihailenco/msgpack.v2 v2.9.1 // indirect | ||
gopkg.in/vmihailenco/msgpack.v2 v2.9.1 // indirect | ||
gopkg.in/yaml.v2 v2.2.1 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package parse | ||
|
||
import ( | ||
"bufio" | ||
"strings" | ||
) | ||
|
||
import ( | ||
"gopkg.in/src-d/go-errors.v1" | ||
"gopkg.in/src-d/go-mysql-server.v0/sql" | ||
"gopkg.in/src-d/go-mysql-server.v0/sql/plan" | ||
) | ||
|
||
var errUnsupportedShowCreateQuery = errors.NewKind("Unsupported query: SHOW CREATE %s") | ||
|
||
func parseShowCreate(s string) (sql.Node, error) { | ||
r := bufio.NewReader(strings.NewReader(s)) | ||
|
||
var thingToShow string | ||
var name string | ||
steps := []parseFunc{ | ||
expect("show"), | ||
skipSpaces, | ||
expect("create"), | ||
skipSpaces, | ||
readIdent(&thingToShow), | ||
skipSpaces, | ||
readIdent(&name), | ||
skipSpaces, | ||
checkEOF, | ||
} | ||
|
||
for _, step := range steps { | ||
if err := step(r); err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
switch strings.ToLower(thingToShow) { | ||
case "table": | ||
return plan.NewShowCreateTable( | ||
sql.UnresolvedDatabase("").Name(), | ||
nil, | ||
name), nil | ||
default: | ||
return nil, errUnsupportedShowCreateQuery.New(name) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package parse | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"gopkg.in/src-d/go-errors.v1" | ||
"gopkg.in/src-d/go-mysql-server.v0/sql" | ||
"gopkg.in/src-d/go-mysql-server.v0/sql/plan" | ||
) | ||
|
||
func TestParseShowCreateTableQuery(t *testing.T) { | ||
testCases := []struct { | ||
query string | ||
result sql.Node | ||
err *errors.Kind | ||
}{ | ||
{ | ||
"SHOW CREATE", | ||
nil, | ||
errUnsupportedShowCreateQuery, | ||
}, | ||
{ | ||
"SHOW CREATE ANYTHING", | ||
nil, | ||
errUnsupportedShowCreateQuery, | ||
}, | ||
{ | ||
"SHOW CREATE ASDF foo", | ||
nil, | ||
errUnsupportedShowCreateQuery, | ||
}, | ||
{ | ||
"SHOW CREATE TABLE mytable", | ||
plan.NewShowCreateTable(sql.UnresolvedDatabase("").Name(), | ||
nil, | ||
"mytable"), | ||
nil, | ||
}, | ||
} | ||
|
||
for _, tt := range testCases { | ||
t.Run(tt.query, func(t *testing.T) { | ||
require := require.New(t) | ||
|
||
result, err := parseShowCreate(tt.query) | ||
if tt.err != nil { | ||
require.Error(err) | ||
require.True(tt.err.Is(err)) | ||
} else { | ||
require.NoError(err) | ||
require.Equal(tt.result, result) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package plan | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"strings" | ||
|
||
"gopkg.in/src-d/go-errors.v1" | ||
"gopkg.in/src-d/go-mysql-server.v0/sql" | ||
) | ||
|
||
var ErrTableNotFound = errors.NewKind("Table `%s` not found") | ||
|
||
// ShowCreateTable is a node that shows the CREATE TABLE statement for a table. | ||
type ShowCreateTable struct { | ||
Catalog *sql.Catalog | ||
CurrentDatabase string | ||
Table string | ||
} | ||
|
||
// Schema implements the Node interface. | ||
func (n *ShowCreateTable) Schema() sql.Schema { | ||
return sql.Schema{ | ||
&sql.Column{Name: "Table", Type: sql.Text, Nullable: false}, | ||
&sql.Column{Name: "Create Table", Type: sql.Text, Nullable: false}, | ||
} | ||
} | ||
|
||
// TransformExpressionsUp implements the Transformable interface. | ||
func (n *ShowCreateTable) TransformExpressionsUp(f sql.TransformExprFunc) (sql.Node, error) { | ||
return n, nil | ||
} | ||
|
||
// TransformUp implements the Transformable interface. | ||
func (n *ShowCreateTable) TransformUp(f sql.TransformNodeFunc) (sql.Node, error) { | ||
return f(NewShowCreateTable(n.CurrentDatabase, n.Catalog, n.Table)) | ||
} | ||
|
||
// RowIter implements the Node interface | ||
func (n *ShowCreateTable) RowIter(*sql.Context) (sql.RowIter, error) { | ||
db, err := n.Catalog.Database(n.CurrentDatabase) | ||
|
||
if err != nil { | ||
return nil, sql.ErrDatabaseNotFound.New(n.CurrentDatabase) | ||
} | ||
|
||
return &showCreateTablesIter{ | ||
db: db, | ||
table: n.Table, | ||
}, nil | ||
} | ||
|
||
// String implements the Stringer interface. | ||
func (n *ShowCreateTable) String() string { | ||
return fmt.Sprintf("SHOW CREATE TABLE %s", n.Table) | ||
} | ||
|
||
type createTableStmt struct { | ||
colName string | ||
colType sql.Type | ||
} | ||
|
||
type showCreateTablesIter struct { | ||
db sql.Database | ||
table string | ||
|
||
createStmt *createTableStmt | ||
didIteration bool | ||
} | ||
|
||
func (i *showCreateTablesIter) Next() (sql.Row, error) { | ||
if i.didIteration { | ||
return nil, io.EOF | ||
} | ||
|
||
i.didIteration = true | ||
|
||
table, found := i.db.Tables()[i.table] | ||
|
||
if !found { | ||
return nil, ErrTableNotFound.New(i.table) | ||
} | ||
|
||
composedCreateTableStatement := produceCreateStatement(table) | ||
|
||
return sql.NewRow( | ||
i.table, // "Table" string | ||
composedCreateTableStatement, // "Create Table" string | ||
), nil | ||
} | ||
|
||
func produceCreateStatement(table sql.Table) string { | ||
schema := table.Schema() | ||
colCreateStatements := make([]string, len(schema), len(schema)) | ||
|
||
// Statement creation parts for each column | ||
for indx, col := range schema { | ||
createStmtPart := fmt.Sprintf("`%s` %s", col.Name, col.Type.Type()) | ||
|
||
if !col.Nullable { | ||
createStmtPart = fmt.Sprintf("%s NOT NULL", createStmtPart) | ||
} | ||
|
||
switch def := col.Default.(type) { | ||
case string: | ||
if def != "" { | ||
createStmtPart = fmt.Sprintf("%s DEFAULT %s", createStmtPart, def) | ||
} | ||
default: | ||
if def != nil { | ||
createStmtPart = fmt.Sprintf("%s DEFAULT %v", createStmtPart, col.Default) | ||
} | ||
} | ||
|
||
colCreateStatements[indx] = createStmtPart | ||
} | ||
|
||
prettyColCreateStmts := fmt.Sprintf("%s", strings.Join(colCreateStatements, ",\n")) | ||
composedCreateTableStatement := | ||
fmt.Sprintf("CREATE TABLE `%s` (%s) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", table.Name(), prettyColCreateStmts) | ||
|
||
return composedCreateTableStatement | ||
} | ||
|
||
func (i *showCreateTablesIter) Close() error { | ||
return nil | ||
} | ||
|
||
// NewShowCreateTable creates a new ShowCreateTable node. | ||
func NewShowCreateTable(db string, ctl *sql.Catalog, table string) sql.Node { | ||
return &ShowCreateTable{ | ||
CurrentDatabase: db, | ||
Table: table, | ||
Catalog: ctl} | ||
} | ||
|
||
// Resolved implements the Resolvable interface. | ||
func (n *ShowCreateTable) Resolved() bool { | ||
return true | ||
} | ||
|
||
// Children implements the Node interface. | ||
func (n *ShowCreateTable) Children() []sql.Node { return nil } |
Oops, something went wrong.