Skip to content

Commit cd198d0

Browse files
authored
Merge pull request #5 from BrandonRoehl/lock-tables-first
Add the ability to lock all tables
2 parents 3ee6198 + 89292d2 commit cd198d0

File tree

4 files changed

+90
-37
lines changed

4 files changed

+90
-37
lines changed

dump.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Data struct {
2323
Connection *sql.DB
2424
IgnoreTables []string
2525
MaxAllowedPacket int
26+
LockTables bool
2627

2728
headerTmpl *template.Template
2829
tableTmpl *template.Template
@@ -48,7 +49,7 @@ type metaData struct {
4849

4950
const (
5051
// Version of this plugin for easy reference
51-
Version = "0.4.1"
52+
Version = "0.5.0"
5253

5354
defaultMaxAllowedPacket = 4194304
5455
)
@@ -139,6 +140,24 @@ func (data *Data) Dump() error {
139140
return err
140141
}
141142

143+
// Lock all tables before dumping if present
144+
if data.LockTables && len(tables) > 0 {
145+
var b bytes.Buffer
146+
b.WriteString("LOCK TABLES ")
147+
for index, name := range tables {
148+
if index != 0 {
149+
b.WriteString(",")
150+
}
151+
b.WriteString("`" + name + "` READ /*!32311 LOCAL */")
152+
}
153+
154+
if _, err := data.Connection.Exec(b.String()); err != nil {
155+
return err
156+
}
157+
158+
defer data.Connection.Exec("UNLOCK TABLES")
159+
}
160+
142161
for _, name := range tables {
143162
if err := data.dumpTable(name); err != nil {
144163
return err
@@ -160,11 +179,7 @@ func (data *Data) dumpTable(name string) error {
160179
if data.err != nil {
161180
return data.err
162181
}
163-
table, err := data.createTable(name)
164-
if err != nil {
165-
return err
166-
}
167-
182+
table := data.createTable(name)
168183
return data.writeTable(table)
169184
}
170185

@@ -228,20 +243,18 @@ func (data *Data) isIgnoredTable(name string) bool {
228243

229244
func (data *metaData) updateServerVersion(db *sql.DB) (err error) {
230245
var serverVersion sql.NullString
231-
err = db.QueryRow("SELECT version();").Scan(&serverVersion)
246+
err = db.QueryRow("SELECT version()").Scan(&serverVersion)
232247
data.ServerVersion = serverVersion.String
233248
return
234249
}
235250

236251
// MARK: create methods
237252

238-
func (data *Data) createTable(name string) (*table, error) {
239-
t := &table{
253+
func (data *Data) createTable(name string) *table {
254+
return &table{
240255
Name: name,
241256
data: data,
242257
}
243-
244-
return t, nil
245258
}
246259

247260
func (table *table) NameEsc() string {

dump_test.go

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,7 @@ func TestCreateTableSQLOk(t *testing.T) {
120120
Connection: db,
121121
}
122122

123-
table, err := data.createTable("Test_Table")
124-
assert.NoError(t, err)
123+
table := data.createTable("Test_Table")
125124

126125
result, err := table.CreateSQL()
127126
assert.NoError(t, err)
@@ -151,8 +150,7 @@ func TestCreateTableRowValues(t *testing.T) {
151150
Connection: db,
152151
}
153152

154-
table, err := data.createTable("test")
155-
assert.NoError(t, err)
153+
table := data.createTable("test")
156154

157155
assert.True(t, table.Next())
158156

@@ -181,8 +179,7 @@ func TestCreateTableValuesSteam(t *testing.T) {
181179
MaxAllowedPacket: 4096,
182180
}
183181

184-
table, err := data.createTable("test")
185-
assert.NoError(t, err)
182+
table := data.createTable("test")
186183

187184
s := table.Stream()
188185
assert.EqualValues(t, "INSERT INTO `test` VALUES ('1','[email protected]','Test Name 1'),('2','[email protected]','Test Name 2');", <-s)
@@ -207,8 +204,7 @@ func TestCreateTableValuesSteamSmallPackets(t *testing.T) {
207204
MaxAllowedPacket: 64,
208205
}
209206

210-
table, err := data.createTable("test")
211-
assert.NoError(t, err)
207+
table := data.createTable("test")
212208

213209
s := table.Stream()
214210
assert.EqualValues(t, "INSERT INTO `test` VALUES ('1','[email protected]','Test Name 1');", <-s)
@@ -234,8 +230,7 @@ func TestCreateTableAllValuesWithNil(t *testing.T) {
234230
Connection: db,
235231
}
236232

237-
table, err := data.createTable("test")
238-
assert.NoError(t, err)
233+
table := data.createTable("test")
239234

240235
results := make([]string, 0)
241236
for table.Next() {
@@ -277,8 +272,7 @@ func TestCreateTableOk(t *testing.T) {
277272

278273
assert.NoError(t, data.getTemplates())
279274

280-
table, err := data.createTable("Test_Table")
281-
assert.NoError(t, err)
275+
table := data.createTable("Test_Table")
282276

283277
data.writeTable(table)
284278

@@ -335,8 +329,7 @@ func TestCreateTableOkSmallPackets(t *testing.T) {
335329

336330
assert.NoError(t, data.getTemplates())
337331

338-
table, err := data.createTable("Test_Table")
339-
assert.NoError(t, err)
332+
table := data.createTable("Test_Table")
340333

341334
data.writeTable(table)
342335

mysqldump.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ func Register(db *sql.DB, dir, format string) (*Data, error) {
3939
return &Data{
4040
Out: f,
4141
Connection: db,
42+
LockTables: true,
4243
}, nil
4344
}
4445

4546
// Dump Creates a MYSQL dump from the connection to the stream.
4647
func Dump(db *sql.DB, out io.Writer) error {
47-
data := Data{
48+
return (&Data{
4849
Connection: db,
4950
Out: out,
50-
}
51-
52-
return data.Dump()
51+
LockTables: true,
52+
}).Dump()
5353
}
5454

5555
// Close the dumper.

mysqldump_test.go

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package mysqldump
22

33
import (
44
"bytes"
5+
"io/ioutil"
56
"strings"
67
"testing"
78

@@ -56,11 +57,12 @@ UNLOCK TABLES;
5657
5758
`
5859

59-
func RunDump(t testing.TB) string {
60+
func RunDump(t testing.TB, data *Data) {
6061
db, mock, err := sqlmock.New()
6162
assert.NoError(t, err, "an error was not expected when opening a stub database connection")
6263
defer db.Close()
6364

65+
data.Connection = db
6466
showTablesRows := sqlmock.NewRows([]string{"Tables_in_Testdb"}).
6567
AddRow("Test_Table")
6668

@@ -74,27 +76,72 @@ func RunDump(t testing.TB) string {
7476
AddRow(1, nil, "Test Name 1").
7577
AddRow(2, "[email protected]", "Test Name 2")
7678

77-
mock.ExpectQuery("^SELECT version()").WillReturnRows(serverVersionRows)
79+
mock.ExpectQuery(`^SELECT version\(\)$`).WillReturnRows(serverVersionRows)
7880
mock.ExpectQuery("^SHOW TABLES$").WillReturnRows(showTablesRows)
81+
mock.ExpectExec("^LOCK TABLES `Test_Table` READ /\\*!32311 LOCAL \\*/$").WillReturnResult(sqlmock.NewResult(1, 1))
7982
mock.ExpectQuery("^SHOW CREATE TABLE `Test_Table`$").WillReturnRows(createTableRows)
8083
mock.ExpectQuery("^SELECT (.+) FROM `Test_Table`$").WillReturnRows(createTableValueRows)
8184

85+
assert.NoError(t, data.Dump(), "an error was not expected when dumping a stub database connection")
86+
}
87+
88+
func TestDumpOk(t *testing.T) {
8289
var buf bytes.Buffer
83-
assert.NoError(t, Dump(db, &buf), "an error was not expected when dumping a stub database connection")
8490

85-
return buf.String()
91+
RunDump(t, &Data{
92+
Out: &buf,
93+
LockTables: true,
94+
})
95+
96+
result := strings.Replace(strings.Split(buf.String(), "-- Dump completed")[0], "`", "~", -1)
97+
98+
assert.Equal(t, expected, result)
8699
}
87100

88-
func TestDumpOk(t *testing.T) {
89-
out := RunDump(t)
101+
func TestNoLockOk(t *testing.T) {
102+
var buf bytes.Buffer
90103

91-
result := strings.Replace(strings.Split(out, "-- Dump completed")[0], "`", "~", -1)
104+
data := &Data{
105+
Out: &buf,
106+
LockTables: false,
107+
}
108+
109+
db, mock, err := sqlmock.New()
110+
assert.NoError(t, err, "an error was not expected when opening a stub database connection")
111+
defer db.Close()
112+
113+
data.Connection = db
114+
showTablesRows := sqlmock.NewRows([]string{"Tables_in_Testdb"}).
115+
AddRow("Test_Table")
116+
117+
serverVersionRows := sqlmock.NewRows([]string{"Version()"}).
118+
AddRow("test_version")
119+
120+
createTableRows := sqlmock.NewRows([]string{"Table", "Create Table"}).
121+
AddRow("Test_Table", "CREATE TABLE 'Test_Table' (`id` int(11) NOT NULL AUTO_INCREMENT,`email` char(60) DEFAULT NULL, `name` char(60), PRIMARY KEY (`id`))ENGINE=InnoDB DEFAULT CHARSET=latin1")
122+
123+
createTableValueRows := sqlmock.NewRows([]string{"id", "email", "name"}).
124+
AddRow(1, nil, "Test Name 1").
125+
AddRow(2, "[email protected]", "Test Name 2")
126+
127+
mock.ExpectQuery(`^SELECT version\(\)$`).WillReturnRows(serverVersionRows)
128+
mock.ExpectQuery("^SHOW TABLES$").WillReturnRows(showTablesRows)
129+
mock.ExpectQuery("^SHOW CREATE TABLE `Test_Table`$").WillReturnRows(createTableRows)
130+
mock.ExpectQuery("^SELECT (.+) FROM `Test_Table`$").WillReturnRows(createTableValueRows)
131+
132+
assert.NoError(t, data.Dump(), "an error was not expected when dumping a stub database connection")
133+
134+
result := strings.Replace(strings.Split(buf.String(), "-- Dump completed")[0], "`", "~", -1)
92135

93136
assert.Equal(t, expected, result)
94137
}
95138

96139
func BenchmarkDump(b *testing.B) {
140+
data := &Data{
141+
Out: ioutil.Discard,
142+
LockTables: true,
143+
}
97144
for i := 0; i < b.N; i++ {
98-
_ = RunDump(b)
145+
RunDump(b, data)
99146
}
100147
}

0 commit comments

Comments
 (0)