forked from src-d/go-mysql-server
/
show_create_table.go
139 lines (111 loc) · 3.14 KB
/
show_create_table.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package plan
import (
"fmt"
"io"
"strings"
"github.com/src-d/go-mysql-server/internal/similartext"
"github.com/src-d/go-mysql-server/sql"
)
// 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},
}
}
// WithChildren implements the Node interface.
func (n *ShowCreateTable) WithChildren(children ...sql.Node) (sql.Node, error) {
if len(children) != 0 {
return nil, sql.ErrInvalidChildrenNumber.New(n, len(children), 0)
}
return n, nil
}
// 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, err
}
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 showCreateTablesIter struct {
db sql.Database
table string
didIteration bool
}
func (i *showCreateTablesIter) Next() (sql.Row, error) {
if i.didIteration {
return nil, io.EOF
}
i.didIteration = true
tables := i.db.Tables()
if len(tables) == 0 {
return nil, sql.ErrTableNotFound.New(i.table)
}
table, found := tables[i.table]
if !found {
similar := similartext.FindFromMap(tables, i.table)
return nil, sql.ErrTableNotFound.New(i.table + similar)
}
composedCreateTableStatement := produceCreateStatement(table)
return sql.NewRow(
i.table, // "Table" string
composedCreateTableStatement, // "Create Table" string
), nil
}
func produceCreateStatement(table sql.Table) string {
schema := table.Schema()
colStmts := make([]string, len(schema))
// Statement creation parts for each column
for i, col := range schema {
stmt := fmt.Sprintf(" `%s` %s", col.Name, strings.ToLower(sql.MySQLTypeName(col.Type)))
if !col.Nullable {
stmt = fmt.Sprintf("%s NOT NULL", stmt)
}
switch def := col.Default.(type) {
case string:
if def != "" {
stmt = fmt.Sprintf("%s DEFAULT %q", stmt, def)
}
default:
if def != nil {
stmt = fmt.Sprintf("%s DEFAULT %v", stmt, col.Default)
}
}
colStmts[i] = stmt
}
return fmt.Sprintf(
"CREATE TABLE `%s` (\n%s\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4",
table.Name(),
strings.Join(colStmts, ",\n"),
)
}
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 }