-
Notifications
You must be signed in to change notification settings - Fork 0
/
table_export.go
195 lines (158 loc) · 4.97 KB
/
table_export.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"io"
"log"
"os"
"os/exec"
)
const (
RowsChunk = 100
)
type TableExport struct {
db *sql.DB
dbName string
tableName string
columns map[string]string
rowCount int
fileFinishChan chan string
writer *FileWriter
}
func NewTableExport(db *sql.DB, dbName string, tableName string, fileFinishChan chan string) *TableExport {
tableExport := &TableExport{
db: db,
dbName: dbName,
tableName: tableName,
fileFinishChan: fileFinishChan}
return tableExport
}
func (table *TableExport) exportFileName() string {
return *exportDir + table.tableName + ".sql"
}
func (table *TableExport) mysqldump() {
args := []string{}
if *socket != "" {
args = append(args, fmt.Sprintf("--socket=%s", *socket))
} else {
args = append(args, fmt.Sprintf("--host=%s --port=%d", *host, *port))
}
if *username != "" {
args = append(args, fmt.Sprintf("-u%s", *username))
}
if *password != "" {
args = append(args, fmt.Sprintf("-p%s", *password))
}
args = append(args, table.dbName, table.tableName)
// open the out file for writing
outfile, err := os.Create(table.exportFileName())
handleError(err, "Could not create file")
defer outfile.Close()
cmd := exec.Command("mysqldump", args...)
cmd.Stdout = outfile
stderr, err := cmd.StderrPipe()
err = cmd.Start()
handleError(err, "Error when starts dumping table via mysqldump")
go io.Copy(os.Stderr, stderr)
err = cmd.Wait()
// export finish, close db connect to avoid 'too many connections' error
table.fileFinishChan <- table.exportFileName()
}
func (table *TableExport) process() {
if *verbose {
log.Printf("Processing table %s...", table.tableName)
}
// use mysqldump command to export each table
_, err := exec.LookPath("mysqldump")
if err != nil && *mysqldump == true {
log.Fatalln("Could not find 'mysqldump' command.")
}
if *mysqldump {
// close db connection as don't use anymore to avoid too many connections error
table.db.Close()
table.mysqldump()
return
}
table.writer = NewFileWriter(table.exportFileName())
table.rowCount = table.getRowCount()
table.initColumnList()
go table.writer.start()
tableComment := `----
-- Dump data of table ` + table.tableName + `
----`
table.writer.write(tableComment)
table.writer.writeNewLine()
// drop table if exist
table.writer.write(fmt.Sprintf("DROP TABLE IF EXISTS `%s`;", table.tableName))
table.writer.writeNewLine()
createTableString, err := table.getCreateTableQuery()
handleError(err, "Could not get create table query")
table.writer.write(createTableString + ";")
table.writer.writeNewLine()
// write insert statement
table.writer.writeNewLine()
table.writer.finish()
// export finish, close db connect to avoid 'too many connections' error
table.db.Close()
table.fileFinishChan <- table.exportFileName()
}
func (table *TableExport) initColumnList() {
query := fmt.Sprint("SELECT `COLUMN_NAME`, `DATA_TYPE` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `TABLE_CATALOG` = 'def' ORDER BY `ORDINAL_POSITION`")
rows, err := Query(table.db, query, table.dbName, table.tableName)
if err != nil {
log.Fatalf("Coun't get list of column of table '%s': %v", table.tableName, err)
}
defer rows.Close()
table.columns = make(map[string]string)
var colName, colType string
for rows.Next() {
err := rows.Scan(&colName, &colType)
if err != nil {
log.Fatalf("Coun't get list of column of table '%s': %v", table.tableName, err)
}
table.columns[colName] = colType
}
}
func (table *TableExport) getNumberOfColumn() int {
return len(table.columns)
}
func (table *TableExport) getCreateTableQuery() (string, error) {
rows, err := Query(table.db, fmt.Sprintf("SHOW CREATE TABLE `%s`", table.tableName))
if err != nil {
log.Fatalf("Couldn't get create table query:\n %v", err)
}
defer rows.Close()
var tableName, createTableQuery string
if rows.Next() {
err := rows.Scan(&tableName, &createTableQuery)
return createTableQuery, err
}
return "", fmt.Errorf("Couldn't get create table query for table `%s`: %v", table.tableName, rows.Err())
}
func (table *TableExport) fetchData(offset int, dataOut chan [][]string) {
//results := make([]string, 0, RowsChunk)
query := fmt.Sprintf("SELECT * FROM `%s` OFFSET %d LIMIT %d", table.tableName, offset, RowsChunk)
rows, err := Query(table.db, query)
if err != nil {
log.Fatalf("Couldn't fetch data: %v", err)
}
defer rows.Close()
// travel on data and return data
}
func (table *TableExport) getRowCount() int {
rows, err := Query(table.db, fmt.Sprintf("SELECT COUNT(1) FROM `%s`", table.tableName))
if err != nil {
log.Fatalf("Error when try to get number row of table '%s': %v", table.tableName, err)
}
defer rows.Close()
var rowCount int
if rows.Next() {
err = rows.Scan(&rowCount)
if err != nil {
log.Fatalf("Error when try to get number row of table '%s': %v", table.tableName, err)
}
return rowCount
}
return 0
}