Skip to content

Commit

Permalink
Merge pull request #5 from BrandonRoehl/lock-tables-first
Browse files Browse the repository at this point in the history
Add the ability to lock all tables
  • Loading branch information
BrandonRoehl authored Oct 1, 2019
2 parents 3ee6198 + 89292d2 commit cd198d0
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 37 deletions.
35 changes: 24 additions & 11 deletions dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Data struct {
Connection *sql.DB
IgnoreTables []string
MaxAllowedPacket int
LockTables bool

headerTmpl *template.Template
tableTmpl *template.Template
Expand All @@ -48,7 +49,7 @@ type metaData struct {

const (
// Version of this plugin for easy reference
Version = "0.4.1"
Version = "0.5.0"

defaultMaxAllowedPacket = 4194304
)
Expand Down Expand Up @@ -139,6 +140,24 @@ func (data *Data) Dump() error {
return err
}

// Lock all tables before dumping if present
if data.LockTables && len(tables) > 0 {
var b bytes.Buffer
b.WriteString("LOCK TABLES ")
for index, name := range tables {
if index != 0 {
b.WriteString(",")
}
b.WriteString("`" + name + "` READ /*!32311 LOCAL */")
}

if _, err := data.Connection.Exec(b.String()); err != nil {
return err
}

defer data.Connection.Exec("UNLOCK TABLES")
}

for _, name := range tables {
if err := data.dumpTable(name); err != nil {
return err
Expand All @@ -160,11 +179,7 @@ func (data *Data) dumpTable(name string) error {
if data.err != nil {
return data.err
}
table, err := data.createTable(name)
if err != nil {
return err
}

table := data.createTable(name)
return data.writeTable(table)
}

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

func (data *metaData) updateServerVersion(db *sql.DB) (err error) {
var serverVersion sql.NullString
err = db.QueryRow("SELECT version();").Scan(&serverVersion)
err = db.QueryRow("SELECT version()").Scan(&serverVersion)
data.ServerVersion = serverVersion.String
return
}

// MARK: create methods

func (data *Data) createTable(name string) (*table, error) {
t := &table{
func (data *Data) createTable(name string) *table {
return &table{
Name: name,
data: data,
}

return t, nil
}

func (table *table) NameEsc() string {
Expand Down
21 changes: 7 additions & 14 deletions dump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ func TestCreateTableSQLOk(t *testing.T) {
Connection: db,
}

table, err := data.createTable("Test_Table")
assert.NoError(t, err)
table := data.createTable("Test_Table")

result, err := table.CreateSQL()
assert.NoError(t, err)
Expand Down Expand Up @@ -151,8 +150,7 @@ func TestCreateTableRowValues(t *testing.T) {
Connection: db,
}

table, err := data.createTable("test")
assert.NoError(t, err)
table := data.createTable("test")

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

Expand Down Expand Up @@ -181,8 +179,7 @@ func TestCreateTableValuesSteam(t *testing.T) {
MaxAllowedPacket: 4096,
}

table, err := data.createTable("test")
assert.NoError(t, err)
table := data.createTable("test")

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

table, err := data.createTable("test")
assert.NoError(t, err)
table := data.createTable("test")

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

table, err := data.createTable("test")
assert.NoError(t, err)
table := data.createTable("test")

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

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

table, err := data.createTable("Test_Table")
assert.NoError(t, err)
table := data.createTable("Test_Table")

data.writeTable(table)

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

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

table, err := data.createTable("Test_Table")
assert.NoError(t, err)
table := data.createTable("Test_Table")

data.writeTable(table)

Expand Down
8 changes: 4 additions & 4 deletions mysqldump.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ func Register(db *sql.DB, dir, format string) (*Data, error) {
return &Data{
Out: f,
Connection: db,
LockTables: true,
}, nil
}

// Dump Creates a MYSQL dump from the connection to the stream.
func Dump(db *sql.DB, out io.Writer) error {
data := Data{
return (&Data{
Connection: db,
Out: out,
}

return data.Dump()
LockTables: true,
}).Dump()
}

// Close the dumper.
Expand Down
63 changes: 55 additions & 8 deletions mysqldump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mysqldump

import (
"bytes"
"io/ioutil"
"strings"
"testing"

Expand Down Expand Up @@ -56,11 +57,12 @@ UNLOCK TABLES;
`

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

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

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

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

assert.NoError(t, data.Dump(), "an error was not expected when dumping a stub database connection")
}

func TestDumpOk(t *testing.T) {
var buf bytes.Buffer
assert.NoError(t, Dump(db, &buf), "an error was not expected when dumping a stub database connection")

return buf.String()
RunDump(t, &Data{
Out: &buf,
LockTables: true,
})

result := strings.Replace(strings.Split(buf.String(), "-- Dump completed")[0], "`", "~", -1)

assert.Equal(t, expected, result)
}

func TestDumpOk(t *testing.T) {
out := RunDump(t)
func TestNoLockOk(t *testing.T) {
var buf bytes.Buffer

result := strings.Replace(strings.Split(out, "-- Dump completed")[0], "`", "~", -1)
data := &Data{
Out: &buf,
LockTables: false,
}

db, mock, err := sqlmock.New()
assert.NoError(t, err, "an error was not expected when opening a stub database connection")
defer db.Close()

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

serverVersionRows := sqlmock.NewRows([]string{"Version()"}).
AddRow("test_version")

createTableRows := sqlmock.NewRows([]string{"Table", "Create Table"}).
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")

createTableValueRows := sqlmock.NewRows([]string{"id", "email", "name"}).
AddRow(1, nil, "Test Name 1").
AddRow(2, "[email protected]", "Test Name 2")

mock.ExpectQuery(`^SELECT version\(\)$`).WillReturnRows(serverVersionRows)
mock.ExpectQuery("^SHOW TABLES$").WillReturnRows(showTablesRows)
mock.ExpectQuery("^SHOW CREATE TABLE `Test_Table`$").WillReturnRows(createTableRows)
mock.ExpectQuery("^SELECT (.+) FROM `Test_Table`$").WillReturnRows(createTableValueRows)

assert.NoError(t, data.Dump(), "an error was not expected when dumping a stub database connection")

result := strings.Replace(strings.Split(buf.String(), "-- Dump completed")[0], "`", "~", -1)

assert.Equal(t, expected, result)
}

func BenchmarkDump(b *testing.B) {
data := &Data{
Out: ioutil.Discard,
LockTables: true,
}
for i := 0; i < b.N; i++ {
_ = RunDump(b)
RunDump(b, data)
}
}

0 comments on commit cd198d0

Please sign in to comment.